pax_global_header00006660000000000000000000000064147344474570014535gustar00rootroot0000000000000052 comment=f4d2f3cb95643876fae3b8bace525784a255fb0c pykdumpfile-0.5.5.1/000077500000000000000000000000001473444745700142345ustar00rootroot00000000000000pykdumpfile-0.5.5.1/.gitignore000066400000000000000000000002451473444745700162250ustar00rootroot00000000000000# Generated cffi code _addrxlat.* _kdumpfile.* # Object files *.o *.so # Python bytecode *.pyc # Python distribution /dist/ *.egg-info # Editor backup files *~ pykdumpfile-0.5.5.1/LICENSE000066400000000000000000000431031473444745700152420ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. pykdumpfile-0.5.5.1/README.md000066400000000000000000000005771473444745700155240ustar00rootroot00000000000000# pykdumpfile Bindings to the libkdumpfile shared library. ## Links * [libkdumpfile](https://github.com/ptesarik/libkdumpfile) ## License This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. pykdumpfile-0.5.5.1/addrxlat.h000066400000000000000000000254241473444745700162170ustar00rootroot00000000000000/* Copyright (C) 2022 Petr Tesarik This file is free software; you can redistribute it and/or modify it under the terms of either * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version or both in parallel, as here. pykdumpfile is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received copies of the GNU General Public License and the GNU Lesser General Public License along with this program. If not, see . */ /* The rest of this file is adapted from the public header. * Matching libkdumpfile commit: * 82f1795d9589706b1b8df338eb4a7dbd8180daba */ #define ADDRXLAT_VER_MAJOR ... #define ADDRXLAT_VER_MINOR ... #define ADDRXLAT_VER_MICRO ... #define ADDRXLAT_VERSION ... typedef enum _addrxlat_status { ADDRXLAT_OK = 0, ADDRXLAT_ERR_NOTIMPL, ADDRXLAT_ERR_NOTPRESENT, ADDRXLAT_ERR_INVALID, ADDRXLAT_ERR_NOMEM, ADDRXLAT_ERR_NODATA, ADDRXLAT_ERR_NOMETH, ADDRXLAT_ERR_CUSTOM_BASE = -1 } addrxlat_status; const char *addrxlat_strerror(addrxlat_status status); typedef uint_fast64_t addrxlat_addr_t; #define ADDRXLAT_ADDR_MAX ... typedef int_fast64_t addrxlat_off_t; typedef uint_fast64_t addrxlat_pte_t; typedef enum _addrxlat_addrspace { ADDRXLAT_KPHYSADDR, ADDRXLAT_MACHPHYSADDR, ADDRXLAT_KVADDR, ADDRXLAT_NOADDR = -1, } addrxlat_addrspace_t; const char *addrxlat_addrspace_name(addrxlat_addrspace_t as); typedef struct _addrxlat_fulladdr { addrxlat_addr_t addr; addrxlat_addrspace_t as; } addrxlat_fulladdr_t; typedef struct _addrxlat_ctx addrxlat_ctx_t; addrxlat_ctx_t *addrxlat_ctx_new(void); unsigned long addrxlat_ctx_incref(addrxlat_ctx_t *ctx); unsigned long addrxlat_ctx_decref(addrxlat_ctx_t *ctx); addrxlat_status addrxlat_ctx_err( addrxlat_ctx_t *ctx, addrxlat_status status, const char *msgfmt, ...); void addrxlat_ctx_clear_err(addrxlat_ctx_t *ctx); const char *addrxlat_ctx_get_err(const addrxlat_ctx_t *ctx); typedef struct _addrxlat_cb addrxlat_cb_t; typedef addrxlat_status addrxlat_cb_reg_value_fn( const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val); typedef addrxlat_status addrxlat_cb_sym_value_fn( const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val); typedef addrxlat_status addrxlat_cb_sym_sizeof_fn( const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val); typedef addrxlat_status addrxlat_cb_sym_offsetof_fn( const addrxlat_cb_t *cb, const char *obj, const char *elem, addrxlat_addr_t *val); typedef addrxlat_status addrxlat_cb_num_value_fn( const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val); typedef enum _addrxlat_byte_order { ADDRXLAT_BIG_ENDIAN, ADDRXLAT_LITTLE_ENDIAN, ADDRXLAT_HOST_ENDIAN = -1 } addrxlat_byte_order_t; typedef struct _addrxlat_buffer addrxlat_buffer_t; typedef void addrxlat_put_page_fn(const addrxlat_buffer_t *buf); struct _addrxlat_buffer { addrxlat_fulladdr_t addr; const void *ptr; size_t size; addrxlat_byte_order_t byte_order; addrxlat_put_page_fn *put_page; void *priv; }; typedef addrxlat_status addrxlat_get_page_fn( const addrxlat_cb_t *cb, addrxlat_buffer_t *buf); typedef unsigned long addrxlat_read_caps_fn(const addrxlat_cb_t *cb); unsigned long ADDRXLAT_CAPS(unsigned val); struct _addrxlat_cb { const addrxlat_cb_t *next; void *priv; addrxlat_get_page_fn *get_page; addrxlat_read_caps_fn *read_caps; addrxlat_cb_reg_value_fn *reg_value; addrxlat_cb_sym_value_fn *sym_value; addrxlat_cb_sym_sizeof_fn *sym_sizeof; addrxlat_cb_sym_offsetof_fn *sym_offsetof; addrxlat_cb_num_value_fn *num_value; }; addrxlat_cb_t *addrxlat_ctx_add_cb(addrxlat_ctx_t *ctx); void addrxlat_ctx_del_cb(addrxlat_ctx_t *ctx, addrxlat_cb_t *cb); const addrxlat_cb_t *addrxlat_ctx_get_cb(const addrxlat_ctx_t *ctx); typedef enum _addrxlat_kind { ADDRXLAT_NOMETH, ADDRXLAT_CUSTOM, ADDRXLAT_LINEAR, ADDRXLAT_PGT, ADDRXLAT_LOOKUP, ADDRXLAT_MEMARR, } addrxlat_kind_t; typedef struct _addrxlat_step addrxlat_step_t; typedef addrxlat_status addrxlat_first_step_fn( addrxlat_step_t *step, addrxlat_addr_t addr); typedef addrxlat_status addrxlat_next_step_fn(addrxlat_step_t *step); typedef struct _addrxlat_param_custom { addrxlat_first_step_fn *first_step; addrxlat_next_step_fn *next_step; void *data; } addrxlat_param_custom_t; typedef struct _addrxlat_param_linear { addrxlat_off_t off; } addrxlat_param_linear_t; typedef enum _addrxlat_pte_format { ADDRXLAT_PTE_INVALID = -1, ADDRXLAT_PTE_NONE, ADDRXLAT_PTE_PFN32, ADDRXLAT_PTE_PFN64, ADDRXLAT_PTE_AARCH64, ADDRXLAT_PTE_IA32, ADDRXLAT_PTE_IA32_PAE, ADDRXLAT_PTE_X86_64, ADDRXLAT_PTE_S390X, ADDRXLAT_PTE_PPC64_LINUX_RPN30, ADDRXLAT_PTE_AARCH64_LPA, ADDRXLAT_PTE_AARCH64_LPA2, ADDRXLAT_PTE_ARM, ADDRXLAT_PTE_RISCV32, ADDRXLAT_PTE_RISCV64, } addrxlat_pte_format_t; const char *addrxlat_pte_format_name(addrxlat_pte_format_t fmt); addrxlat_pte_format_t addrxlat_pte_format(const char *name); int addrxlat_pteval_shift(addrxlat_pte_format_t fmt); #define ADDRXLAT_FIELDS_MAX 8 typedef struct _addrxlat_paging_form { addrxlat_pte_format_t pte_format; unsigned short nfields; unsigned short fieldsz[ADDRXLAT_FIELDS_MAX]; } addrxlat_paging_form_t; typedef struct _addrxlat_param_pgt { addrxlat_fulladdr_t root; addrxlat_pte_t pte_mask; addrxlat_paging_form_t pf; } addrxlat_param_pgt_t; typedef struct _addrxlat_lookup_elem { addrxlat_addr_t orig; addrxlat_addr_t dest; } addrxlat_lookup_elem_t; typedef struct _addrxlat_param_lookup { addrxlat_addr_t endoff; size_t nelem; addrxlat_lookup_elem_t *tbl; } addrxlat_param_lookup_t; typedef struct _addrxlat_param_memarr { addrxlat_fulladdr_t base; unsigned shift; unsigned elemsz; unsigned valsz; } addrxlat_param_memarr_t; typedef union _addrxlat_param { addrxlat_param_custom_t custom; addrxlat_param_linear_t linear; addrxlat_param_pgt_t pgt; addrxlat_param_lookup_t lookup; addrxlat_param_memarr_t memarr; } addrxlat_param_t; typedef struct _addrxlat_meth { addrxlat_kind_t kind; addrxlat_addrspace_t target_as; addrxlat_param_t param; } addrxlat_meth_t; typedef enum _addrxlat_sys_meth { ADDRXLAT_SYS_METH_NONE = -1, ADDRXLAT_SYS_METH_PGT, ADDRXLAT_SYS_METH_UPGT, ADDRXLAT_SYS_METH_DIRECT, ADDRXLAT_SYS_METH_KTEXT, ADDRXLAT_SYS_METH_VMEMMAP, ADDRXLAT_SYS_METH_RDIRECT, ADDRXLAT_SYS_METH_MACHPHYS_KPHYS, ADDRXLAT_SYS_METH_KPHYS_MACHPHYS, ADDRXLAT_SYS_METH_CUSTOM } addrxlat_sys_meth_t; #define ADDRXLAT_SYS_METH_CUSTOM_NUM ... #define ADDRXLAT_SYS_METH_NUM ... typedef struct _addrxlat_range { addrxlat_addr_t endoff; addrxlat_sys_meth_t meth; } addrxlat_range_t; typedef struct _addrxlat_map addrxlat_map_t; addrxlat_map_t *addrxlat_map_new(void); unsigned long addrxlat_map_incref(addrxlat_map_t *map); unsigned long addrxlat_map_decref(addrxlat_map_t *map); size_t addrxlat_map_len(const addrxlat_map_t *map); const addrxlat_range_t *addrxlat_map_ranges(const addrxlat_map_t *map); addrxlat_status addrxlat_map_set( addrxlat_map_t *map, addrxlat_addr_t addr, const addrxlat_range_t *range); addrxlat_sys_meth_t addrxlat_map_search( const addrxlat_map_t *map, addrxlat_addr_t addr); addrxlat_map_t *addrxlat_map_copy(const addrxlat_map_t *map); typedef enum _addrxlat_optidx { ADDRXLAT_OPT_NULL, ADDRXLAT_OPT_arch, ADDRXLAT_OPT_os_type, ADDRXLAT_OPT_version_code, ADDRXLAT_OPT_phys_bits, ADDRXLAT_OPT_virt_bits, ADDRXLAT_OPT_page_shift, ADDRXLAT_OPT_phys_base, ADDRXLAT_OPT_rootpgt, ADDRXLAT_OPT_xen_p2m_mfn, ADDRXLAT_OPT_xen_xlat, ADDRXLAT_OPT_NUM } addrxlat_optidx_t; typedef union _addrxlat_optval { const char *str; unsigned long num; addrxlat_addr_t addr; addrxlat_fulladdr_t fulladdr; } addrxlat_optval_t; typedef struct _addrxlat_opt { addrxlat_optidx_t idx; addrxlat_optval_t val; } addrxlat_opt_t; void addrxlat_opt_arch(addrxlat_opt_t *opt, const char *val); void addrxlat_opt_os_type(addrxlat_opt_t *opt, const char *val); void addrxlat_opt_version_code(addrxlat_opt_t *opt, unsigned long val); void addrxlat_opt_phys_bits(addrxlat_opt_t *opt, unsigned long val); void addrxlat_opt_virt_bits(addrxlat_opt_t *opt, unsigned long val); void addrxlat_opt_page_shift(addrxlat_opt_t *opt, unsigned long val); void addrxlat_opt_phys_base(addrxlat_opt_t *opt, addrxlat_addr_t val); void addrxlat_opt_rootpgt(addrxlat_opt_t *opt, const addrxlat_fulladdr_t *val); void addrxlat_opt_xen_p2m_mfn(addrxlat_opt_t *opt, unsigned long val); void addrxlat_opt_xen_xlat(addrxlat_opt_t *opt, unsigned long val); unsigned long ADDRXLAT_VER_LINUX(unsigned a, unsigned b, unsigned c); unsigned long ADDRXLAT_VER_XEN(unsigned major, unsigned minor); typedef struct _addrxlat_sys addrxlat_sys_t; addrxlat_sys_t *addrxlat_sys_new(void); unsigned long addrxlat_sys_incref(addrxlat_sys_t *sys); unsigned long addrxlat_sys_decref(addrxlat_sys_t *sys); addrxlat_status addrxlat_sys_os_init( addrxlat_sys_t *sys, addrxlat_ctx_t *ctx, unsigned optc, const addrxlat_opt_t *opts); typedef enum _addrxlat_sys_map { ADDRXLAT_SYS_MAP_HW, ADDRXLAT_SYS_MAP_KV_PHYS, ADDRXLAT_SYS_MAP_KPHYS_DIRECT, ADDRXLAT_SYS_MAP_MACHPHYS_KPHYS, ADDRXLAT_SYS_MAP_KPHYS_MACHPHYS, ADDRXLAT_SYS_MAP_NUM, } addrxlat_sys_map_t; void addrxlat_sys_set_map( addrxlat_sys_t *sys, addrxlat_sys_map_t idx, addrxlat_map_t *map); addrxlat_map_t *addrxlat_sys_get_map( const addrxlat_sys_t *sys, addrxlat_sys_map_t idx); void addrxlat_sys_set_meth( addrxlat_sys_t *sys, addrxlat_sys_meth_t idx, const addrxlat_meth_t *meth); const addrxlat_meth_t *addrxlat_sys_get_meth( const addrxlat_sys_t *sys, addrxlat_sys_meth_t idx); struct _addrxlat_step { addrxlat_ctx_t *ctx; addrxlat_sys_t *sys; const addrxlat_meth_t *meth; unsigned short remain; unsigned elemsz; addrxlat_fulladdr_t base; union { void *data; addrxlat_pte_t pte; const addrxlat_lookup_elem_t *elem; addrxlat_addr_t addr; } raw; addrxlat_addr_t idx[ADDRXLAT_FIELDS_MAX + 1]; }; addrxlat_status addrxlat_launch(addrxlat_step_t *step, addrxlat_addr_t addr); addrxlat_status addrxlat_step(addrxlat_step_t *step); addrxlat_status addrxlat_walk(addrxlat_step_t *step); typedef addrxlat_status addrxlat_op_fn(void *data, const addrxlat_fulladdr_t *addr); typedef struct _addrxlat_op_ctl { addrxlat_ctx_t *ctx; addrxlat_sys_t *sys; addrxlat_op_fn *op; void *data; unsigned long caps; } addrxlat_op_ctl_t; addrxlat_status addrxlat_op(const addrxlat_op_ctl_t *ctl, const addrxlat_fulladdr_t *addr); addrxlat_status addrxlat_fulladdr_conv( addrxlat_fulladdr_t *faddr, addrxlat_addrspace_t as, addrxlat_ctx_t *ctx, addrxlat_sys_t *sys); pykdumpfile-0.5.5.1/addrxlat/000077500000000000000000000000001473444745700160375ustar00rootroot00000000000000pykdumpfile-0.5.5.1/addrxlat/__init__.py000066400000000000000000000026521473444745700201550ustar00rootroot00000000000000'''addrxlat ''' from _addrxlat import ffi, lib as C from .constants import * from .exceptions import * from .objects import * from . import utils ### ### Version codes ### def VER_LINUX(a, b, c): '''VER_LINUX(a, b, c) -> version code Calculate the Linux kernel version code.''' return C.ADDRXLAT_VER_LINUX(a, b, c) def VER_XEN(major, minor): '''VER_XEN(major, minor) -> version code Calculate the Xen hypervisor version code.''' return C.ADDRXLAT_VER_XEN(major, minor) ### ### Other static functions ### def addrspace_name(addrspace): '''addrspace_name(addrspace) -> name Return the name of an address space constant.''' return utils.to_unicode(ffi.string(C.addrxlat_addrspace_name(addrspace))) def CAPS(addrspace): '''CAPS(addrspace) -> capability bitmask Translate an address space constant into a capability bitmask.''' return C.ADDRXLAT_CAPS(addrspace) def pte_format_name(fmt): '''pte_format_name(fmt) -> name Return the name of a PTE format constant.''' return utils.to_unicode(ffi.string(C.addrxlat_pte_format_name(fmt))) def pte_format(name): '''pte_format(name) -> fmt Return the PTE format constant by name.''' return C.addrxlat_pte_format(utils.to_bytes(name)) def pteval_shift(fmt): '''pteval_shift(fmt) -> bit shift Get the pteval shift for a PTE format. See PTE_xxx for valid values of fmt.''' return C.addrxlat_pteval_shift(fmt) pykdumpfile-0.5.5.1/addrxlat/constants.py000066400000000000000000000057731473444745700204410ustar00rootroot00000000000000'''addrxlat.const ''' ### ### Constants ### from _addrxlat import lib as C # versioning VER_MAJOR = C.ADDRXLAT_VER_MAJOR VER_MINOR = C.ADDRXLAT_VER_MINOR VER_MICRO = C.ADDRXLAT_VER_MICRO VERSION = C.ADDRXLAT_VERSION # addrxlat_status OK = C.ADDRXLAT_OK ERR_NOTIMPL = C.ADDRXLAT_ERR_NOTIMPL ERR_NOTPRESENT = C.ADDRXLAT_ERR_NOTPRESENT ERR_INVALID = C.ADDRXLAT_ERR_INVALID ERR_NOMEM = C.ADDRXLAT_ERR_NOMEM ERR_NODATA = C.ADDRXLAT_ERR_NODATA ERR_NOMETH = C.ADDRXLAT_ERR_NOMETH ERR_CUSTOM_BASE = C.ADDRXLAT_ERR_CUSTOM_BASE # addrxlat_addr_t ADDR_MAX = C.ADDRXLAT_ADDR_MAX # addrxlat_addrspace_t KPHYSADDR = C.ADDRXLAT_KPHYSADDR MACHPHYSADDR = C.ADDRXLAT_MACHPHYSADDR KVADDR = C.ADDRXLAT_KVADDR NOADDR = C.ADDRXLAT_NOADDR # addrxlat_byte_order_t BIG_ENDIAN = C.ADDRXLAT_BIG_ENDIAN LITTLE_ENDIAN = C.ADDRXLAT_LITTLE_ENDIAN HOST_ENDIAN = C.ADDRXLAT_HOST_ENDIAN # addrxlat_kind_t NOMETH = C.ADDRXLAT_NOMETH CUSTOM = C.ADDRXLAT_CUSTOM LINEAR = C.ADDRXLAT_LINEAR PGT = C.ADDRXLAT_PGT LOOKUP = C.ADDRXLAT_LOOKUP MEMARR = C.ADDRXLAT_MEMARR # addrxlat_pte_format_t PTE_INVALID = C.ADDRXLAT_PTE_INVALID PTE_NONE = C.ADDRXLAT_PTE_NONE PTE_PFN32 = C.ADDRXLAT_PTE_PFN32 PTE_PFN64 = C.ADDRXLAT_PTE_PFN64 PTE_AARCH64 = C.ADDRXLAT_PTE_AARCH64 PTE_IA32 = C.ADDRXLAT_PTE_IA32 PTE_IA32_PAE = C.ADDRXLAT_PTE_IA32_PAE PTE_X86_64 = C.ADDRXLAT_PTE_X86_64 PTE_S390X = C.ADDRXLAT_PTE_S390X PTE_PPC64_LINUX_RPN30 = C.ADDRXLAT_PTE_PPC64_LINUX_RPN30 PTE_AARCH64_LPA = C.ADDRXLAT_PTE_AARCH64_LPA PTE_AARCH64_LPA2 = C.ADDRXLAT_PTE_AARCH64_LPA2 PTE_ARM = C.ADDRXLAT_PTE_ARM PTE_RISCV32 = C.ADDRXLAT_PTE_RISCV32 PTE_RISCV64 = C.ADDRXLAT_PTE_RISCV64 # other paging form constants FIELDS_MAX = C.ADDRXLAT_FIELDS_MAX # addrxlat_sys_meth_t SYS_METH_NONE = C.ADDRXLAT_SYS_METH_NONE SYS_METH_PGT = C.ADDRXLAT_SYS_METH_PGT SYS_METH_UPGT = C.ADDRXLAT_SYS_METH_UPGT SYS_METH_DIRECT = C.ADDRXLAT_SYS_METH_DIRECT SYS_METH_KTEXT = C.ADDRXLAT_SYS_METH_KTEXT SYS_METH_VMEMMAP = C.ADDRXLAT_SYS_METH_VMEMMAP SYS_METH_RDIRECT = C.ADDRXLAT_SYS_METH_RDIRECT SYS_METH_MACHPHYS_KPHYS = C.ADDRXLAT_SYS_METH_MACHPHYS_KPHYS SYS_METH_KPHYS_MACHPHYS = C.ADDRXLAT_SYS_METH_KPHYS_MACHPHYS SYS_METH_CUSTOM = C.ADDRXLAT_SYS_METH_CUSTOM SYS_METH_CUSTOM_NUM = C.ADDRXLAT_SYS_METH_CUSTOM_NUM SYS_METH_NUM = C.ADDRXLAT_SYS_METH_NUM # addrxlat_optidx_t OPT_NULL = C.ADDRXLAT_OPT_NULL OPT_arch = C.ADDRXLAT_OPT_arch OPT_os_type = C.ADDRXLAT_OPT_os_type OPT_version_code = C.ADDRXLAT_OPT_version_code OPT_phys_bits = C.ADDRXLAT_OPT_phys_bits OPT_virt_bits = C.ADDRXLAT_OPT_virt_bits OPT_page_shift = C.ADDRXLAT_OPT_page_shift OPT_phys_base = C.ADDRXLAT_OPT_phys_base OPT_rootpgt = C.ADDRXLAT_OPT_rootpgt OPT_xen_p2m_mfn = C.ADDRXLAT_OPT_xen_p2m_mfn OPT_xen_xlat = C.ADDRXLAT_OPT_xen_xlat OPT_NUM = C.ADDRXLAT_OPT_NUM # addrxlat_sys_map_t SYS_MAP_HW = C.ADDRXLAT_SYS_MAP_HW SYS_MAP_KV_PHYS = C.ADDRXLAT_SYS_MAP_KV_PHYS SYS_MAP_KPHYS_DIRECT = C.ADDRXLAT_SYS_MAP_KPHYS_DIRECT SYS_MAP_MACHPHYS_KPHYS = C.ADDRXLAT_SYS_MAP_MACHPHYS_KPHYS SYS_MAP_KPHYS_MACHPHYS = C.ADDRXLAT_SYS_MAP_KPHYS_MACHPHYS SYS_MAP_NUM = C.ADDRXLAT_SYS_MAP_NUM pykdumpfile-0.5.5.1/addrxlat/defs_py2.py000066400000000000000000000002001473444745700201140ustar00rootroot00000000000000'''addrxlat.defs_py2 ''' unicode_type = unicode binary_type = str def restore_exception(exc, val, tb): raise exc, val, tb pykdumpfile-0.5.5.1/addrxlat/defs_py3.py000066400000000000000000000002151473444745700201230ustar00rootroot00000000000000'''addrxlat.defs_py3 ''' unicode_type = str binary_type = bytes def restore_exception(exc, val, tb): raise exc(val).with_traceback(tb) pykdumpfile-0.5.5.1/addrxlat/exceptions.py000066400000000000000000000046171473444745700206020ustar00rootroot00000000000000'''addrxlat.exceptions ''' from .constants import * from .utils import to_unicode from _addrxlat import ffi, lib as C def strerror(status): '''strerror(status) -> error message Return the string describing a given error status.''' return to_unicode(ffi.string(C.addrxlat_strerror(status))) class AddrxlatError(Exception): '''Common base for all addrxlat exceptions. AddrxlatError(status[, message]) If message is not specified, use addrxlat_strerror(status). Attributes: status addrxlat status code, see ERR_xxx message verbose error message''' def __init__(self, status, message=None): if message is None: message = strerror(status) super(AddrxlatError, self).__init__(message) self.status = status self.message = message def _def_exception(name, status, addbases=()): '''Create an addrxlat exception for a given status code. The new exception is derived from AddrxlatError, but you may specify additional base classes with addbases. ''' def __init__(self, *args, **kwargs): super(cls, self).__init__(status, *args, **kwargs) def __repr__(self): "x.__repr__() <==> repr(x)" return "%s%r" % (self.__class__.__name__, self.args[1:]) di = { '__doc__' : name + '([message])' + ''' If message is not specified, use the default error message. ''', 'status' : status, '__init__' : __init__, '__repr__' : __repr__, } cls = type(name, (AddrxlatError,) + addbases, di) return cls _exceptions = { ('NotImplementedError', ERR_NOTIMPL, (NotImplementedError,)), ('NotPresentError', ERR_NOTPRESENT), ('InvalidError', ERR_INVALID), ('MemoryError', ERR_NOMEM, (MemoryError,)), ('NoDataError', ERR_NODATA), ('NoMethodError', ERR_NOMETH), } _exc_map = {} for _exc in _exceptions: _cls = _def_exception(*_exc) globals()[_cls.__name__] = _cls _exc_map[_cls.status] = _cls # Free up init-time variables del _exc, _cls, _exceptions, _def_exception def get_exception(status, *args, **kwargs): '''get_exception(status[, message]) Get an appropriate exception for the given status. If there is no specific exception, make an instance of AddrxlatError. ''' exc = _exc_map.get(status) if exc is not None: return exc(*args, **kwargs) return AddrxlatError(status, *args, **kwargs) pykdumpfile-0.5.5.1/addrxlat/objects.py000066400000000000000000001104011473444745700200370ustar00rootroot00000000000000'''addrxlat.objects There are two types of objects in libaddrxlat: - simple value - reference-counted ''' from _addrxlat import ffi, lib as C from .constants import * from .exceptions import * from . import utils ### ### Helper constants ### _ADDR_MAX_HALF = ADDR_MAX // 2 ### ### Common property setters ### def _cdata_or_null(value): if value is None: return ffi.NULL else: return value._cdata ### ### Callback functions ### ERR_PYEXC = ERR_CUSTOM_BASE ERR_CFFI_CONV = ERR_CUSTOM_BASE - 1 def _status_result(ctx, status, result): if status == OK: ctx._set_exception() return result exc, val, tb = ctx._set_exception() if exc is not None: utils.restore_exception(exc, val, tb) elif status == ERR_CFFI_CONV: raise TypeError('CFFI could not convert callback return value') else: raise get_exception(status, ctx.get_err()) def _ctx_error(ctx, exc, val, tb): ctx._set_exception(exc, val, tb) if issubclass(exc, AddrxlatError): status = exc.status else: status = ERR_PYEXC return ctx.err(status, str(val)) def _cb_ctx_error(exc, val, tb): if tb is None: # happens if there was an error converting the return value return ERR_CFFI_CONV ctx = ffi.from_handle(tb.tb_frame.f_locals['cb'].priv) return _ctx_error(ctx, exc, val, tb) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_reg_value(cb, name, val): return ffi.from_handle(cb.priv)._cb_reg_value(name, val) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_sym_value(cb, name, val): return ffi.from_handle(cb.priv)._cb_sym_value(name, val) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_sym_sizeof(cb, name, val): return ffi.from_handle(cb.priv)._cb_sym_sizeof(name, val) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_sym_offsetof(cb, obj, elem, val): return ffi.from_handle(cb.priv)._cb_sym_offsetof(obj, elem, val) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_num_value(cb, name, val): return ffi.from_handle(cb.priv)._cb_num_value(name, val) @ffi.def_extern(onerror=_cb_ctx_error, error=ERR_PYEXC) def _cb_get_page(cb, buf): return ffi.from_handle(cb.priv)._cb_get_page(buf) @ffi.def_extern(onerror=_cb_ctx_error, error=0) def _cb_read_caps(cb): return ffi.from_handle(cb.priv)._cb_read_caps() @ffi.def_extern() def _cb_put_page(buf): ffi.from_handle(buf.priv)._cb_put_page() def _cb_meth_error(exc, val, tb): if tb is None: # happens if there was an error converting the return value return ERR_CFFI_CONV ctx = Context(tb.tb_frame.f_locals['step'].ctx) return _ctx_error(ctx, exc, val, tb) @ffi.def_extern(onerror=_cb_meth_error, error=ERR_PYEXC) def _cb_first_step(step, addr): return ffi.from_handle(step.meth.param.custom.data)._cb_first_step(step, addr) @ffi.def_extern(onerror=_cb_meth_error, error=ERR_PYEXC) def _cb_next_step(step): return ffi.from_handle(step.meth.param.custom.data)._cb_next_step(step) def _cb_op_error(exc, val, tb): if tb is None: # happens if there was an error converting the return value return ERR_CFFI_CONV op = ffi.from_handle(tb.tb_frame.f_locals['op']) return _ctx_error(op.ctx, exc, val, tb) @ffi.def_extern(onerror=_cb_op_error, error=ERR_PYEXC) def _cb_op(op, addr): return ffi.from_handle(op)._cb_op(addr) ### ### addrxlat_ctx_t ### class Context(object): '''Context([ptr]) -> ctx Wrapper for cdata addrxlat_ctx_t *. If ptr is omitted, allocate a new translation context.''' def __init__(self, ptr=None): if ptr is None: ptr = C.addrxlat_ctx_new() if not ptr: raise MemoryError('Could not allocate addrxlat_ctx_t') else: C.addrxlat_ctx_incref(ptr) self._cdata = ptr self._exc = None self._exc_val = None self._exc_tb = None self._handle = ffi.new_handle(self) self._cb = C.addrxlat_ctx_add_cb(self._cdata) self._cb.priv = self._handle self._cb.get_page = C._cb_get_page self._cb.read_caps = C._cb_read_caps self._cb.reg_value = C._cb_reg_value self._cb.sym_value = C._cb_sym_value self._cb.sym_sizeof = C._cb_sym_sizeof self._cb.sym_offsetof = C._cb_sym_offsetof self._cb.num_value = C._cb_num_value self.read_caps = None def __del__(self): ctx = self._cdata self._cdata = ffi.NULL C.addrxlat_ctx_del_cb(ctx, self._cb) C.addrxlat_ctx_decref(ctx) def __eq__(self, other): return self._cdata == other._cdata def __ne__(self, other): return not self == other def err(self, status, str): '''CTX.err(status, str) -> status Set the error message.''' return C.addrxlat_ctx_err(self._cdata, status, utils.to_bytes(str)) def clear_err(self): '''CTX.clear_err() Clear the error message.''' C.addrxlat_ctx_clear_err(self._cdata) def get_err(self): '''CTX.get_err() -> error string Return a detailed error description of the last error condition.''' err = C.addrxlat_ctx_get_err(self._cdata) if not err: return None else: return utils.to_unicode(ffi.string(err)) def _set_exception(self, exc=None, exc_val=None, exc_tb=None): '''Save an exception, returning the old value. With no arguments, clear the saved exception.''' result = (self._exc, self._exc_val, self._exc_tb) self._exc = exc self._exc_val = exc_val self._exc_tb = exc_tb return result def _cb_reg_value(self, name, val): val[0] = self.cb_reg_value(ffi.string(name)) return OK def cb_reg_value(self, name): '''CTX.cb_reg_value(name) -> val Callback function to get register value by name.''' return self.next_cb_reg_value(name) def next_cb_reg_value(self, name): '''CTX.next_cb_reg_value(name) -> val Call the next callback to get register value.''' val = ffi.new('addrxlat_addr_t*') status = self._cb.next.reg_value(self._cb.next, utils.to_bytes(name), val) return _status_result(self, status, val[0]) def _cb_sym_value(self, name, val): val[0] = self.cb_sym_value(ffi.string(name)) return OK def cb_sym_value(self, name): '''CTX.cb_sym_value(name) -> val Callback function to get symbol value by name.''' return self.next_cb_sym_value(name) def next_cb_sym_value(self, name): '''CTX.next_cb_sym_value(name) -> val Call the next callback to get symbol value.''' val = ffi.new('addrxlat_addr_t*') status = self._cb.next.sym_value(self._cb.next, utils.to_bytes(name), val) return _status_result(self, status, val[0]) def _cb_sym_sizeof(self, name, val): val[0] = self.cb_sym_sizeof(ffi.string(name)) return OK def cb_sym_sizeof(self, name): '''CTX.cb_sym_sizeof(name) -> val Callback function to get symbol size by name.''' return self.next_cb_sym_sizeof(name) def next_cb_sym_sizeof(self, name): '''CTX.next_cb_sym_sizeof(name) -> val Call the next callback to get symbol size.''' val = ffi.new('addrxlat_addr_t*') status = self._cb.next.sym_sizeof(self._cb.next, utils.to_bytes(name), val) return _status_result(self, status, val[0]) def _cb_sym_offsetof(self, obj, elem, val): val[0] = self.cb_sym_offsetof(ffi.string(obj), ffi.string(elem)) return OK def cb_sym_offsetof(self, obj, elem): '''CTX.cb_sym_offsetof(obj, elem) -> val Callback function to get element offset within object.''' return self.next_cb_sym_offsetof(obj, elem) def next_cb_sym_offsetof(self, obj, elem): '''CTX.next_cb_sym_offsetof(obj, elem) -> val Call the next callback to get element offset within object.''' val = ffi.new('addrxlat_addr_t*') status = self._cb.next.sym_offsetof(self._cb.next, utils.to_bytes(obj), utils.to_bytes(elem), val) return _status_result(self, status, val[0]) def _cb_num_value(self, name, val): val[0] = self.cb_num_value(ffi.string(name)) return OK def cb_num_value(self, name): '''CTX.cb_num_value(name) -> val Callback function to get number value by name.''' return self.next_cb_num_value(name) def next_cb_num_value(self, name): '''CTX.next_cb_num_value(name) -> val Call the next callback to get number value.''' val = ffi.new('addrxlat_addr_t*') status = self._cb.next.num_value(self._cb.next, utils.to_bytes(name), val) return _status_result(self, status, val[0]) def _cb_get_page(self, buf): self.cb_get_page(Buffer(buf)) return OK def cb_get_page(self, buf): '''CTX.cb_get_page(buf) Callback function to read a page at a given address. Update the Buffer object passed as parameter.''' return self.next_cb_get_page(buf) def next_cb_get_page(self, buf): '''CTX.next_cb_get_page(buf) Call the next callback to read a page.''' status = self._cb.next.get_page(self._cb.next, buf._cdata) return _status_result(self, status, None) def _cb_read_caps(self): return self.cb_read_caps() def cb_read_caps(self): '''CTX.cb_read_caps() -> read_caps Callback function to get a bitmask of address spaces accepted by CTX.cb_read_page(). Returns CTX.read_caps if not None, otherwise calls CTX.next_cb_read_caps().''' if self.read_caps is not None: return self.read_caps return self.next_cb_read_caps() def next_cb_read_caps(self): '''CTX.next_cb_read_caps() Call the next read capabilities callback.''' return self._cb.next.read_caps(self._cb.next) ### ### addrxlat_buffer_t ### class Buffer(object): '''Buffer([ptr]) -> buf Wrapper for cdata addrxlat_buffer_t *. If ptr is omitted, allocate a new buffer.''' def __init__(self, ptr=None): if ptr is None: ptr = ffi.new('addrxlat_buffer_t*') if not ptr: raise MemoryError('Could not allocate addrxlat_buffer_t') self._cdata = ptr self._handle = ffi.new_handle(self) self._orig_put_page = self._cdata.put_page self._orig_priv = self._cdata.priv self._cdata.put_page = C._cb_put_page self._cdata.priv = self._handle self._data = None def __del__(self): self._cdata.put_page = self._orig_put_page self._cdata.priv = self._orig_priv @property def addr(self): '''address (FullAddress)''' return FullAddressFromCData(self._cdata.addr) @addr.setter def addr(self, value): self._cdata.addr = value._cdata[0] @property def data(self): '''raw binary data''' if self._cdata.ptr == ffi.NULL: return None return ffi.buffer(self._cdata.ptr, self._cdata.size) @data.setter def data(self, value): self._data = value if value is None: self._cdata.ptr = ffi.NULL self._cdata.size = 0 else: cdata = ffi.from_buffer(value) self._cdata.ptr = cdata self._cdata.size = len(cdata) @property def byte_order(self): '''byte order''' return self._cdata.byte_order @byte_order.setter def byte_order(self, value): self._cdata.byte_order = value def _cb_put_page(self): self.cb_put_page() def cb_put_page(self): '''BUF.cb_put_page() Callback function to release a page data object that was previously returned by CTX.cb_get_page().''' self.data = None ### ### addrxlat_fulladdr_t ### class FullAddress(object): '''FullAddress(ptr) -> fulladdr Construct a full address, that is an address within a given address space (xxxADDR).''' def __init__(self, addrspace=NOADDR, addr=0): self._cdata = ffi.new('addrxlat_fulladdr_t*', { 'as': addrspace, 'addr': addr, }) def __repr__(self): return '%s(%r, %r)' % ( self.__class__.__name__, self.addrspace, self.addr) @property def addr(self): '''address (unsigned)''' return self._cdata.addr @addr.setter def addr(self, value): self._cdata.addr = value @property def addrspace(self): '''address space''' return getattr(self._cdata, 'as') @addrspace.setter def addrspace(self, value): setattr(self._cdata, 'as', value) def __eq__(self, other): return (self.addr == other.addr and self.addrspace == other.addrspace) def __ne__(self, other): return not self == other def conv(self, addrspace, ctx, sys): '''FULLADDR.conv(addrspace, ctx, sys) -> status Convert a full address to a given target address space.''' status = C.addrxlat_fulladdr_conv(self._cdata, addrspace, ctx._cdata, sys._cdata) return _status_result(ctx, status, None) def copy(self): "make a copy of self" return type(self)(addrspace=self.addrspace, addr=self.addr) def FullAddressFromCData(ptr): '''FullAddressFromCData(ptr) -> FullAddress Initialize a FullAddress from a cdata addrxlat_fulladdr_t *.''' return FullAddress(getattr(ptr, 'as'), ptr.addr) no_address = FullAddress(NOADDR, 0) ### ### addrxlat_meth_t ### class Method(object): '''Method(kind) -> address translation method This is a generic base class for all translation desriptions. Use a subclass to get a more suitable interface to the parameters of a specific translation kind.''' def __init__(self, kind, target_as=NOADDR, param=None): self.__cdata = ffi.new('addrxlat_meth_t*', { 'kind': kind, 'target_as': target_as, }) sz = ffi.sizeof(self.__cdata.param) self._param = ffi.cast('unsigned char[{}]'.format(sz), ffi.addressof(self.__cdata.param)) if param is not None: self.param = param def __eq__(self, other): return ffi.buffer(self._cdata) == ffi.buffer(other._cdata) def __ne__(self, other): return not self == other @property def _cdata(self): '''raw cdata representation of the Method object''' return self.__cdata @property def kind(self): '''translation kind''' return self.__cdata.kind @property def target_as(self): '''target address space''' return self.__cdata.target_as @target_as.setter def target_as(self, value): self.__cdata.target_as = value @property def param(self): '''method parameters as a raw byte buffer''' return self._param @param.setter def param(self, value): self._param[0:len(value)] = value # ADDRXLAT_CUSTOM class CustomMethod(Method): '''CustomMethod() -> custom address translation method This is an abstract base class for translation methods based on callback. Change the cb_first_step and cb_next_step methods to get a working instance.''' def __init__(self, target_as=NOADDR): super(CustomMethod, self).__init__(CUSTOM, target_as) self._handle = ffi.new_handle(self) param = ffi.addressof(self._cdata.param.custom) param.first_step = C._cb_first_step param.next_step = C._cb_next_step param.data = self._handle def _cb_first_step(self, step, addr): '''raw first_step callback''' stepobj = StepFromCData(step) self.cb_first_step(stepobj, addr) step[0] = stepobj._cdata[0] return OK def cb_first_step(self, step, addr): '''METH.cb_first_step(step, addr) Callback to perform the initial translation step.''' raise NotImplementedError('NULL callback') def _cb_next_step(self, step): '''raw next_step callback''' stepobj = StepFromCData(step) self.cb_next_step(stepobj) step[0] = stepobj._cdata[0] return OK def cb_next_step(self, step): '''METH.cb_next_step(step) Callback to perform further translation steps.''' raise NotImplementedError('NULL callback') class ForwardCustomMethod(CustomMethod): '''ForwardCustomMethod(ptr) -> custom address translation method. Wrapper around an existing custom translation method. Callbacks are forwarded to that object's implementation. Instances of this class are created by MethodFromCData.''' def __init__(self, ptr): super(ForwardCustomMethod, self).__init__(ptr.target_as) self._forward = ptr[0] def cb_first_step(self, step, addr): '''Forward the first step callback to the wrapped method.''' try: step._cdata.meth = ffi.addressof(self._forward) cdata = step._cdata status = self._forward.param.custom.first_step(cdata, addr) step.base = FullAddressFromCData(cdata.base) return status finally: step._cdata.meth = self._cdata def cb_next_step(self, step): '''Forward the next step callback to the wrapped method.''' try: step._cdata.meth = ffi.addressof(self._forward) cdata = step._cdata status = self._forward.param.custom.next_step(cdata) step.base = FullAddressFromCData(cdata.base) return status finally: step._cdata.meth = self._cdata # ADDRXLAT_LINEAR class LinearMethod(Method): '''LinearMethod() -> linear address translation method''' def __init__(self, target_as=NOADDR, off=0): super(LinearMethod, self).__init__(LINEAR, target_as) self.off = off def __repr__(self): return '%s(%r, %r)' % ( self.__class__.__name__, self.target_as, self.off) @property def off(self): '''target linear offset from source''' return self._cdata.param.linear.off @off.setter def off(self, value): # Clip large numbers to addrxlat_off_t self._cdata.param.linear.off = ((value + _ADDR_MAX_HALF) & ADDR_MAX) - _ADDR_MAX_HALF # ADDRXLAT_PGT class PageTableMethod(Method): '''PageTableMethod() -> page table address translation method''' def __init__(self, target_as=NOADDR, root=no_address, pte_format=PTE_NONE, fields=()): super(PageTableMethod, self).__init__(PGT, target_as) self.root = root self.pte_format = pte_format self.fields = fields def __repr__(self): return '%s(%r, %r, %r, %r)' % ( self.__class__.__name__, self.target_as, self.root, self.pte_format, self.fields) @property def _cdata(self): '''raw cdata representation of the PageTableMethod object''' super()._cdata.param.pgt.root = self._root._cdata[0] return super()._cdata @property def root(self): '''root page table address''' return self._root @root.setter def root(self, value): self._root = value @property def pte_mask(self): '''page table entry mask''' return super()._cdata.param.pgt.pte_mask @pte_mask.setter def pte_mask(self, value): super()._cdata.param.pgt.pte_mask = value @property def pte_format(self): '''format of a page tabe entry (PTE_xxx)''' return super()._cdata.param.pgt.pf.pte_format @pte_format.setter def pte_format(self, value): super()._cdata.param.pgt.pf.pte_format = value @property def fields(self): '''size of address fields in bits''' pf = ffi.addressof(super()._cdata.param.pgt.pf) return tuple(pf.fieldsz[0:pf.nfields]) @fields.setter def fields(self, value): pf = ffi.addressof(super()._cdata.param.pgt.pf) pf.fieldsz = value pf.nfields = len(value) # ADDRXLAT_LOOKUP class LookupMethod(Method): '''LookupMethod() -> table lookup address translation method''' def __init__(self, target_as=NOADDR, endoff=0, tbl=()): super(LookupMethod, self).__init__(LOOKUP, target_as) self.endoff = endoff self.tbl = tbl def __repr__(self): return '%s(%r, %r, %r)' % ( self.__class__.__name__, self.target_as, self.endoff, self.tbl) @property def endoff(self): '''max address offset inside each object''' return self._cdata.param.lookup.endoff @endoff.setter def endoff(self, value): self._cdata.param.lookup.endoff = value @property def tbl(self): 'lookup table' return self._tbl @tbl.setter def tbl(self, value): nelem = len(value) p = C.malloc(nelem * ffi.sizeof('addrxlat_lookup_elem_t')) if not p: raise MemoryError('Could not allocate addrxlat_lookup_elem_t*') try: p = ffi.cast('addrxlat_lookup_elem_t*', p) for idx, (orig, dest) in enumerate(value): p[idx] = { 'orig': orig, 'dest': dest } except: C.free(p) raise param = ffi.addressof(self._cdata.param.lookup) C.free(param.tbl) param.tbl = p param.nelem = nelem self._tbl = value # ADDRXLAT_MEMARR class MemoryArrayMethod(Method): '''MemoryArrayMethod() -> memory array address translation method''' def __init__(self, target_as=NOADDR, base=no_address, shift=0, elemsz=0, valsz=0): super(MemoryArrayMethod, self).__init__(MEMARR, target_as) self.base = base self.shift = shift self.elemsz = elemsz self.valsz = valsz def __repr__(self): return '%s(%r, %r, %r, %r, %r)' % ( self.__class__.__name__, self.target_as, self.base, self.shift, self.elemsz, self.valsz) @property def base(self): '''base address of the translation array''' return self._base @base.setter def base(self, value): self._base = value self._cdata.param.memarr.base = value._cdata[0] @property def shift(self): '''address bit shift''' return self._cdata.param.memarr.shift @shift.setter def shift(self, value): self._cdata.param.memarr.shift = value @property def elemsz(self): '''size of each array element''' return self._cdata.param.memarr.elemsz @elemsz.setter def elemsz(self, value): self._cdata.param.memarr.elemsz = value @property def valsz(self): '''size of the value''' return self._cdata.param.memarr.valsz @valsz.setter def valsz(self, value): self._cdata.param.memarr.valsz = value def MethodFromCData(ptr): '''MethodFromCData(ptr) -> method Initialize a Method from a cdata addrxlat_meth_t *.''' if not ptr: return None kind = ptr.kind target_as = ptr.target_as if kind == CUSTOM: return ForwardCustomMethod(ptr) elif kind == LINEAR: return LinearMethod(target_as, ptr.param.linear.off) elif kind == PGT: pgt = ffi.addressof(ptr.param.pgt) return PageTableMethod(target_as, pgt.root, pgt.pf.pte_format) elif kind == LOOKUP: return LookupMethod(target_as, ptr.param.lookup.endoff) elif kind == MEMARR: memarr = ffi.addressof(ptr.param.memarr) return MemoryArrayMethod(target_as, memarr.base, memarr.shift, memarr.elemsz, memarr.valsz) else: sz = ffi.sizeof(ptr.param) p = ffi.cast('unsigned char[{}]'.format(sz), ffi.addressof(ptr.param)) return Method(kind, target_as, p) ### ### addrxlat_range_t ### class Range(object): '''Range() -> range Construct an address range.''' def __init__(self, endoff=0, meth=SYS_METH_NONE): self._cdata = ffi.new('addrxlat_range_t*', { 'endoff': endoff, 'meth': meth, }) def __repr__(self): return '%s(%r, %r)' % ( self.__class__.__name__, self.endoff, self.meth) @property def endoff(self): '''maximum offset contained in the range''' return self._cdata.endoff @endoff.setter def endoff(self, value): self._cdata.endoff = value @property def meth(self): '''translation method for this range''' return self._cdata.meth @meth.setter def meth(self, value): self._cdata.meth = value def copy(self): "make a copy of self" return type(self)(endoff=self.endoff, meth=self.meth) def RangeFromCData(ptr): '''RangeFromCData(ptr) -> Range Initialize a Range from a cdata addrxlat_range_t *.''' return Range(ptr.endoff, ptr.meth) ### ### addrxlat_map_t ### class Map(object): '''Map([ptr]) -> map Wrapper for cdata addrxlat_map_t *. If ptr is omitted, allocate a new translation map.''' def __init__(self, ptr=None): if ptr is None: ptr = C.addrxlat_map_new() if not ptr: raise MemoryError('Could not allocate addrxlat_map_t') else: C.addrxlat_map_incref(ptr) self._cdata = ptr def __del__(self): C.addrxlat_map_decref(self._cdata) def __eq__(self, other): return self._cdata == other._cdata def __ne__(self, other): return not self == other def __len__(self): return C.addrxlat_map_len(self._cdata) def __getitem__(self, index): n = len(self) if index < 0: index = n + index if index >= n: raise IndexError('map index out of range') ranges = C.addrxlat_map_ranges(self._cdata) return RangeFromCData(ranges + index) def set(self, addr, range): '''MAP.set(addr, range) -> status\n\ Modify map so that addresses between addr and addr+range.off (inclusive) are mapped using range.meth.''' status = C.addrxlat_map_set(self._cdata, addr, range._cdata) if status != OK: raise get_exception(status) def search(self, addr): '''MAP.search(addr) -> meth Find the translation method for the given address.''' return C.addrxlat_map_search(self._cdata, addr) def copy(self): '''M.copy() -> map Return a shallow copy of a translation map.''' map = C.addrxlat_map_copy(self._cdata) if not map: raise MemoryError('Could not copy map') result = Map(map) C.addrxlat_map_decref(map) return result ### ### addrxlat_sys_t ### _options = { 'arch': (C.addrxlat_opt_arch, utils.to_bytes), 'os_type': (C.addrxlat_opt_os_type, utils.to_bytes), 'version_code': (C.addrxlat_opt_version_code, None), 'phys_bits': (C.addrxlat_opt_phys_bits, None), 'virt_bits': (C.addrxlat_opt_virt_bits, None), 'page_shift': (C.addrxlat_opt_page_shift, None), 'phys_base': (C.addrxlat_opt_phys_base, None), 'rootpgt': (C.addrxlat_opt_rootpgt, lambda a: a._cdata), 'xen_p2m_mfn': (C.addrxlat_opt_xen_p2m_mfn, None), 'xen_xlat': (C.addrxlat_opt_xen_xlat, None), } class System(object): '''SystemBase([ptr]) -> sys Wrapper for cdata addrxlat_sys_t *. If ptr is omitted, allocate a new translation system.''' def __init__(self, ptr=None): if ptr is None: ptr = C.addrxlat_sys_new() if not ptr: raise MemoryError('Could not allocate addrxlat_sys_t') else: C.addrxlat_sys_incref(ptr) self._cdata = ptr def __del__(self): C.addrxlat_sys_decref(self._cdata) def __repr__(self): return '%s()' % (self.__class__.__name__) def __eq__(self, other): return self._cdata == other._cdata def __ne__(self, other): return not self == other def os_init(self, ctx, **kwargs): '''SYS.os_init(...) -> status Set up a translation system for a pre-defined operating system.''' opts = ffi.new('addrxlat_opt_t[]', len(kwargs)) num = 0 tmp_values = [] for opt, value in kwargs.items(): func, conv = _options[opt] if conv is not None: value = conv(value) tmp_values.append(value) func(opts + num, value) num += 1 status = C.addrxlat_sys_os_init(self._cdata, ctx._cdata, num, opts) return _status_result(ctx, status, None) def set_map(self, idx, map): '''SYS.set_map(idx, map) Explicitly set the given translation map of a translation system. See SYS_MAP_xxx for valid values of idx.''' if idx >= SYS_MAP_NUM: raise IndexError('system map index out of range') C.addrxlat_sys_set_map(self._cdata, idx, map._cdata); def get_map(self, idx): '''SYS.get_map(idx) -> Map or None Get the given translation map of a translation system. See SYS_MAP_xxx for valid values of idx.''' if idx >= SYS_MAP_NUM: raise IndexError('system map index out of range') map = C.addrxlat_sys_get_map(self._cdata, idx) if not map: return None else: return Map(map) def set_meth(self, idx, meth): '''SYS.set_meth(idx, meth) Explicitly set a pre-defined translation method of a translation system. See SYS_METH_xxx for valid values of idx.''' if idx >= SYS_METH_NUM: raise IndexError('system meth index out of range') C.addrxlat_sys_set_meth(self._cdata, idx, meth._cdata) def get_meth(self, idx): '''SYS.get_meth(idx) -> Method Get the given translation method of a translation system. See SYS_METH_xxx for valid values of idx.''' if idx >= SYS_METH_NUM: raise IndexError('system method index out of range') meth = C.addrxlat_sys_get_meth(self._cdata, idx) return MethodFromCData(meth) class Step(object): '''Step(ctx) -> step''' def __init__(self, ctx=None, sys=None, meth=None, remain=0, elemsz=0, base=no_address, raw=None, idx=()): self.__cdata = ffi.new('addrxlat_step_t*') self.ctx = ctx self.sys = sys self.meth = meth self.remain = remain self.elemsz = elemsz self.base = base if raw is not None: self.raw = raw if idx is not None: self.idx = idx def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r)' % ( self.__class__.__name__, self.ctx, self.sys, self.meth, self.remain, self.elemsz, self.base, self.raw, self.idx) @property def _cdata(self): '''raw cdata representation of the Step object''' self.__cdata.base = self._base._cdata[0] return self.__cdata @property def ctx(self): '''translation context for the next step''' return self._ctx @ctx.setter def ctx(self, value): self._ctx = value self.__cdata.ctx = _cdata_or_null(value) @property def sys(self): '''translation system for the next step''' return self._sys @sys.setter def sys(self, value): self._sys = value self.__cdata.sys = _cdata_or_null(value) @property def meth(self): '''translation method for the next step''' return self._meth @meth.setter def meth(self, value): self._meth = value self.__cdata.meth = _cdata_or_null(value) @property def remain(self): '''remaining steps''' return self._cdata.remain @remain.setter def remain(self, value): self.__cdata.remain = value @property def elemsz(self): '''size of the indexed element''' return self.__cdata.elemsz @elemsz.setter def elemsz(self, value): self.__cdata.elemsz = value @property def base(self): '''base address for next translation step''' return self._base @base.setter def base(self, value): self._base = value self.__cdata.base = value._cdata[0] @property def raw(self): '''raw value from last step''' if not self.__cdata.meth: return None kind = self.__cdata.meth.kind if kind == CUSTOM: return self.__cdata.raw.data elif kind == PGT: return self.__cdata.raw.pte elif kind == LOOKUP: elem = self.__cdata.raw.elem return (elem.orig, elem.dest) elif kind == MEMARR: return self.__cdata.raw.addr else: return None @raw.setter def raw(self, value): cdata = self.__cdata if not cdata.meth: raise AttributeError() kind = self.__cdata.meth.kind if kind == CUSTOM: cdata.raw.data = value elif kind == PGT: cdata.raw.pte = value elif kind == LOOKUP: elem = cffi.addressof(cdata.raw.elem) elem.orig, elem.dest = value elif kind == MEMARR: cdata.raw.addr = value else: raise TypeError('attribute cannot be changed for this method') @property def idx(self): '''sizes of address parts in bits''' cdata = self.__cdata return tuple(i for i in cdata.idx) @idx.setter def idx(self, value): self.__cdata.idx = value def launch(self, addr): '''STEP.launch(addr) -> status Make the first translation step (launch a translation).''' status = C.addrxlat_launch(self.__cdata, addr) return _status_result(self.ctx, status, None) def step(self): '''STEP.step() -> status Perform one translation step.''' status = C.addrxlat_step(self.__cdata) return _status_result(self.ctx, status, None) def walk(self): '''STEP.walk() -> status\n\ Perform one complete address translation.''' status = C.addrxlat_walk(self._cdata) return _status_result(self.ctx, status, None) def StepFromCData(ptr): '''StepFromCData(ptr) -> Step Initialize a Step from a cdata addrxlat_step_t *.''' ctx = Context(ptr.ctx) if not ptr.sys: sys = None else: sys = System(ptr.sys) raw = None if not ptr.meth: meth = None else: meth = MethodFromCData(ptr.meth) if meth.kind == CUSTOM: raw = ptr.raw.data elif meth.kind == PGT: raw = ptr.raw.pte elif meth.kind == LOOKUP: raw = ptr.raw.elem elif meth.kind == MEMARR: raw = ptr.raw.addr base = FullAddressFromCData(ptr.base) return Step(ctx, sys, meth, ptr.remain, ptr.elemsz, base, raw, ptr.idx) class Operator(object): '''Operator(ctx) -> op Base class for generic addrxlat operations.''' def __init__(self, ctx=None, sys=None, caps=0): self._cdata = ffi.new('addrxlat_op_ctl_t*') self._handle = ffi.new_handle(self) self._cdata.data = self._handle self._cdata.op = C._cb_op self.ctx = ctx self.sys = sys self.caps = caps self.result = None def __repr__(self): return '%s(%r, %r)' % ( self.__class__.__name__, self.ctx, self.sys, self.caps) def __call__(self, addr): status = C.addrxlat_op(self._cdata, addr._cdata) return _status_result(self.ctx, status, self.result) @property def ctx(self): '''translation context''' return self._ctx @ctx.setter def ctx(self, value): self._ctx = value self._cdata.ctx = _cdata_or_null(value) @property def sys(self): '''translation system''' return self._sys @sys.setter def sys(self, value): self._sys = value self._cdata.sys = _cdata_or_null(value) @property def caps(self): '''operation capabilities''' return self._cdata.caps @caps.setter def caps(self, value): self._cdata.caps = value def _cb_op(self, addr): addr = FullAddressFromCData(addr) self.result = self.callback(addr) return OK def callback(self, addr): '''operation callback''' pass pykdumpfile-0.5.5.1/addrxlat/utils.py000066400000000000000000000005421473444745700175520ustar00rootroot00000000000000'''addrxlat.utils ''' import sys if sys.version_info[0] == 3: from .defs_py3 import * else: from .defs_py2 import * def to_bytes(s): if isinstance(s, binary_type): return s return unicode_type(s).encode("utf-8") def to_unicode(s): if isinstance(s, unicode_type): return s return binary_type(s).decode("utf-8") pykdumpfile-0.5.5.1/ffi_addrxlat.py000066400000000000000000000017621473444745700172430ustar00rootroot00000000000000from os import path from cffi import FFI ffi = FFI() header_file = path.join(path.dirname(__file__), "addrxlat.h") with open(header_file) as f: ffi.cdef(f.read()) ffi.cdef(""" /* The lookup table must be allocated by libc allocators. * Expose them here. */ void *malloc(size_t size); void free(void *ptr); /* Callbacks. */ extern "Python" { addrxlat_cb_reg_value_fn _cb_reg_value; addrxlat_cb_sym_value_fn _cb_sym_value; addrxlat_cb_sym_sizeof_fn _cb_sym_sizeof; addrxlat_cb_sym_offsetof_fn _cb_sym_offsetof; addrxlat_cb_num_value_fn _cb_num_value; addrxlat_get_page_fn _cb_get_page; addrxlat_put_page_fn _cb_put_page; addrxlat_read_caps_fn _cb_read_caps; addrxlat_first_step_fn _cb_first_step; addrxlat_next_step_fn _cb_next_step; addrxlat_op_fn _cb_op; } """) ffi.set_source( '_addrxlat', ''' #include #include ''', libraries = [ 'addrxlat', ], ) if __name__ == '__main__': ffi.compile() pykdumpfile-0.5.5.1/ffi_kdumpfile.py000066400000000000000000000011061473444745700174100ustar00rootroot00000000000000from os import path from cffi import FFI ffi = FFI() for header in ('addrxlat.h', 'kdumpfile.h'): header_file = path.join(path.dirname(__file__), header) with open(header_file) as f: ffi.cdef(f.read()) ffi.cdef(""" /* Blob data must be allocated by libc allocators. * Expose them here. */ void *malloc(size_t size); void free(void *ptr); extern "Python" { } """) ffi.set_source( '_kdumpfile', ''' #include #include ''', libraries = [ 'kdumpfile', ], ) if __name__ == '__main__': ffi.compile() pykdumpfile-0.5.5.1/kdumpfile.h000066400000000000000000000166231473444745700163750ustar00rootroot00000000000000/* Copyright (C) 2022 Petr Tesarik This file is free software; you can redistribute it and/or modify it under the terms of either * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version or both in parallel, as here. pykdumpfile is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received copies of the GNU General Public License and the GNU Lesser General Public License along with this program. If not, see . */ /* The rest of this file is adapted from the public header. * Matching libkdumpfile commit: * 5b044292abe9cbfed0d33f2acf1ed1f43e1364f8 */ #define KDUMPFILE_VER_MAJOR ... #define KDUMPFILE_VER_MINOR ... #define KDUMPFILE_VER_MICRO ... #define KDUMPFILE_VERSION ... typedef uint_fast64_t kdump_num_t; typedef addrxlat_addr_t kdump_addr_t; #define KDUMP_ADDR_MAX ... typedef kdump_addr_t kdump_paddr_t; typedef kdump_addr_t kdump_vaddr_t; typedef struct _kdump_ctx kdump_ctx_t; typedef enum _kdump_status { KDUMP_OK = 0, KDUMP_ERR_SYSTEM, KDUMP_ERR_NOTIMPL, KDUMP_ERR_NODATA, KDUMP_ERR_CORRUPT, KDUMP_ERR_INVALID, KDUMP_ERR_NOKEY, KDUMP_ERR_EOF, KDUMP_ERR_BUSY, KDUMP_ERR_ADDRXLAT, } kdump_status; typedef enum _kdump_byte_order { KDUMP_BIG_ENDIAN = ADDRXLAT_BIG_ENDIAN, KDUMP_LITTLE_ENDIAN = ADDRXLAT_LITTLE_ENDIAN, } kdump_byte_order_t; typedef enum _kdump_mmap_policy { KDUMP_MMAP_NEVER, KDUMP_MMAP_ALWAYS, KDUMP_MMAP_TRY, KDUMP_MMAP_TRY_ONCE, } kdump_mmap_policy_t; typedef enum _kdump_xen_type { KDUMP_XEN_NONE, KDUMP_XEN_SYSTEM, KDUMP_XEN_DOMAIN, } kdump_xen_type_t; typedef enum _kdump_xen_xlat { KDUMP_XEN_AUTO, KDUMP_XEN_NONAUTO, } kdump_xen_xlat_t; kdump_ctx_t *kdump_new(void); enum kdump_clone_bits { KDUMP_CLONE_BIT_XLAT, }; #define KDUMP_CLONE_XLAT ... kdump_ctx_t *kdump_clone(const kdump_ctx_t *orig, unsigned long flags); void kdump_free(kdump_ctx_t *ctx); kdump_status kdump_err(kdump_ctx_t *ctx, kdump_status status, const char *msgfmt, ...); void kdump_clear_err(kdump_ctx_t *ctx); const char *kdump_get_err(kdump_ctx_t *ctx); kdump_status kdump_get_addrxlat(kdump_ctx_t *ctx, addrxlat_ctx_t **axctx, addrxlat_sys_t **axsys); uint_fast16_t kdump_d16toh(kdump_ctx_t *ctx, uint_fast16_t val); uint_fast32_t kdump_d32toh(kdump_ctx_t *ctx, uint_fast32_t val); uint_fast64_t kdump_d64toh(kdump_ctx_t *ctx, uint_fast64_t val); kdump_status kdump_set_filenames(kdump_ctx_t *ctx, unsigned n, const char *const *names); kdump_status kdump_set_filename(kdump_ctx_t *ctx, const char *name); kdump_status kdump_open_fdset(kdump_ctx_t *ctx, unsigned nfds, const int *fds); kdump_status kdump_open_fd(kdump_ctx_t *ctx, int fd); typedef enum _kdump_addrspace { KDUMP_KPHYSADDR = ADDRXLAT_KPHYSADDR, KDUMP_MACHPHYSADDR = ADDRXLAT_MACHPHYSADDR, KDUMP_KVADDR = ADDRXLAT_KVADDR, KDUMP_NOADDR = ADDRXLAT_NOADDR, } kdump_addrspace_t; kdump_status kdump_read(kdump_ctx_t *ctx, kdump_addrspace_t as, kdump_addr_t addr, void *buffer, size_t *plength); kdump_status kdump_read_string(kdump_ctx_t *ctx, kdump_addrspace_t as, kdump_addr_t addr, char **pstr); typedef struct _kdump_bmp kdump_bmp_t; unsigned long kdump_bmp_incref(kdump_bmp_t *bmp); unsigned long kdump_bmp_decref(kdump_bmp_t *bmp); const char *kdump_bmp_get_err(const kdump_bmp_t *bmp); kdump_status kdump_bmp_get_bits( kdump_bmp_t *bmp, kdump_addr_t first, kdump_addr_t last, unsigned char *raw); kdump_status kdump_bmp_find_set( kdump_bmp_t *bmp, kdump_addr_t *idx); kdump_status kdump_bmp_find_clear( kdump_bmp_t *bmp, kdump_addr_t *idx); typedef struct _kdump_blob kdump_blob_t; kdump_blob_t *kdump_blob_new(void *data, size_t size); kdump_blob_t *kdump_blob_new_dup(const void *data, size_t size); unsigned long kdump_blob_incref(kdump_blob_t *blob); unsigned long kdump_blob_decref(kdump_blob_t *blob); void *kdump_blob_pin(kdump_blob_t *blob); unsigned long kdump_blob_unpin(kdump_blob_t *blob); size_t kdump_blob_size(const kdump_blob_t *blob); kdump_status kdump_blob_set(kdump_blob_t *blob, void *data, size_t size); typedef enum _kdump_attr_type { KDUMP_NIL, KDUMP_DIRECTORY, KDUMP_NUMBER, KDUMP_ADDRESS, KDUMP_STRING, KDUMP_BITMAP, KDUMP_BLOB, } kdump_attr_type_t; typedef union _kdump_attr_value { kdump_num_t number; kdump_addr_t address; const char *string; kdump_bmp_t *bitmap; kdump_blob_t *blob; } kdump_attr_value_t; typedef struct _kdump_attr { kdump_attr_type_t type; kdump_attr_value_t val; } kdump_attr_t; typedef struct _kdump_attr_ref { void *_ptr; } kdump_attr_ref_t; typedef struct _kdump_attr_iter { const char *key; kdump_attr_ref_t pos; } kdump_attr_iter_t; kdump_status kdump_set_attr(kdump_ctx_t *ctx, const char *key, const kdump_attr_t *valp); kdump_status kdump_set_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t num); kdump_status kdump_set_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t addr); kdump_status kdump_set_string_attr(kdump_ctx_t *ctx, const char *key, const char *str); kdump_status kdump_clear_attr(kdump_ctx_t *ctx, const char *key); kdump_status kdump_get_attr(kdump_ctx_t *ctx, const char *key, kdump_attr_t *valp); kdump_status kdump_get_typed_attr(kdump_ctx_t *ctx, const char *key, kdump_attr_type_t type, kdump_attr_value_t *valp); kdump_status kdump_get_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t *num); kdump_status kdump_get_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t *addr); kdump_status kdump_get_string_attr(kdump_ctx_t *ctx, const char *key, const char **str); kdump_status kdump_attr_ref(kdump_ctx_t *ctx, const char *key, kdump_attr_ref_t *ref); kdump_status kdump_sub_attr_ref(kdump_ctx_t *ctx, const kdump_attr_ref_t *base, const char *subkey, kdump_attr_ref_t *ref); void kdump_attr_unref(kdump_ctx_t *ctx, kdump_attr_ref_t *ref); kdump_attr_type_t kdump_attr_ref_type(kdump_attr_ref_t *ref); int kdump_attr_ref_isset(kdump_attr_ref_t *ref); kdump_status kdump_attr_ref_get(kdump_ctx_t *ctx, const kdump_attr_ref_t *ref, kdump_attr_t *valp); void kdump_attr_discard(kdump_ctx_t *ctx, kdump_attr_t *attr); kdump_status kdump_attr_ref_set(kdump_ctx_t *ctx, kdump_attr_ref_t *ref, const kdump_attr_t *valp); kdump_status kdump_set_sub_attr(kdump_ctx_t *ctx, const kdump_attr_ref_t *base, const char *subkey, const kdump_attr_t *valp); kdump_status kdump_attr_iter_start(kdump_ctx_t *ctx, const char *path, kdump_attr_iter_t *iter); kdump_status kdump_attr_ref_iter_start(kdump_ctx_t *ctx, const kdump_attr_ref_t *ref, kdump_attr_iter_t *iter); kdump_status kdump_attr_iter_next(kdump_ctx_t *ctx, kdump_attr_iter_t *iter); void kdump_attr_iter_end(kdump_ctx_t *ctx, kdump_attr_iter_t *iter); kdump_status kdump_vmcoreinfo_raw(kdump_ctx_t *ctx, char **raw); kdump_status kdump_vmcoreinfo_line(kdump_ctx_t *ctx, const char *key, char **val); kdump_status kdump_vmcoreinfo_symbol(kdump_ctx_t *ctx, const char *symname, kdump_addr_t *symvalue); const char *kdump_strerror(kdump_status status); pykdumpfile-0.5.5.1/kdumpfile/000077500000000000000000000000001473444745700162145ustar00rootroot00000000000000pykdumpfile-0.5.5.1/kdumpfile/__init__.py000066400000000000000000000002261473444745700203250ustar00rootroot00000000000000'''kdumpfile ''' from _kdumpfile import ffi, lib as C from .constants import * from .exceptions import * from .objects import * from . import utils pykdumpfile-0.5.5.1/kdumpfile/constants.py000066400000000000000000000046061473444745700206100ustar00rootroot00000000000000'''kdumpfile.const ''' ### ### Constants ### from _kdumpfile import lib as C # versioning VER_MAJOR = C.KDUMPFILE_VER_MAJOR VER_MINOR = C.KDUMPFILE_VER_MINOR VER_MICRO = C.KDUMPFILE_VER_MICRO VERSION = C.KDUMPFILE_VERSION #kdump_status OK = C.KDUMP_OK ERR_SYSTEM = C.KDUMP_ERR_SYSTEM ERR_NOTIMPL = C.KDUMP_ERR_NOTIMPL ERR_NODATA = C.KDUMP_ERR_NODATA ERR_CORRUPT = C.KDUMP_ERR_CORRUPT ERR_INVALID = C.KDUMP_ERR_INVALID ERR_NOKEY = C.KDUMP_ERR_NOKEY ERR_EOF = C.KDUMP_ERR_EOF ERR_BUSY = C.KDUMP_ERR_BUSY ERR_ADDRXLAT = C.KDUMP_ERR_ADDRXLAT # kdump_addr_t ADDR_MAX = C.KDUMP_ADDR_MAX # kdump_byte_order_t BIG_ENDIAN = C.KDUMP_BIG_ENDIAN LITTLE_ENDIAN = C.KDUMP_LITTLE_ENDIAN # kdump_mmap_policy_t MMAP_NEVER = C.KDUMP_MMAP_NEVER MMAP_ALWAYS = C.KDUMP_MMAP_ALWAYS MMAP_TRY = C.KDUMP_MMAP_TRY MMAP_TRY_ONCE = C.KDUMP_MMAP_TRY_ONCE # kdump_xen_type_t XEN_NONE = C.KDUMP_XEN_NONE XEN_SYSTEM = C.KDUMP_XEN_SYSTEM XEN_DOMAIN = C.KDUMP_XEN_DOMAIN # kdump_xen_xlat_t XEN_AUTO = C.KDUMP_XEN_AUTO XEN_NONAUTO = C.KDUMP_XEN_NONAUTO # enum kdump_clone_bits CLONE_BIT_XLAT = C.KDUMP_CLONE_BIT_XLAT CLONE_XLAT = C.KDUMP_CLONE_XLAT # kdump_addrspace_t KPHYSADDR = C.KDUMP_KPHYSADDR MACHPHYSADDR = C.KDUMP_MACHPHYSADDR KVADDR = C.KDUMP_KVADDR NOADDR = C.KDUMP_NOADDR # kdump_attr_type_t NIL = C.KDUMP_NIL DIRECTORY = C.KDUMP_DIRECTORY NUMBER = C.KDUMP_NUMBER ADDRESS = C.KDUMP_ADDRESS STRING = C.KDUMP_STRING BITMAP = C.KDUMP_BITMAP BLOB = C.KDUMP_BLOB # well-known attributes ATTR_FILE_FD = "file.fd" ATTR_FILE_FORMAT = "file.format" ATTR_FILE_PAGEMAP = "file.pagemap" ATTR_ARCH_NAME = "arch.name" ATTR_BYTE_ORDER = "arch.byte_order" ATTR_PTR_SIZE = "arch.ptr_size" ATTR_PAGE_SIZE = "arch.page_size" ATTR_PAGE_SHIFT = "arch.page_shift" ATTR_NUM_CPUS = "cpu.number" ATTR_OSTYPE = "addrxlat.ostype" ATTR_XLAT_DEFAULT = "addrxlat.default" ATTR_XLAT_FORCE = "addrxlat.force" ATTR_XEN_TYPE = "xen.type" ATTR_XEN_XLAT = "xen.xlat" ATTR_LINUX_VERSION_CODE = "linux.version_code" ATTR_XEN_VERSION_CODE = "xen.version_code" ATTR_XEN_PHYS_START = "xen.phys_start" ATTR_ZERO_EXCLUDED = "file.zero_excluded" ATTR_FILE_MMAP_POLICY = "file.mmap_policy" # canonical architecture names ARCH_AARCH64 = "aarch64" ARCH_ALPHA = "alpha" ARCH_ARM = "arm" ARCH_IA32 = "ia32" ARCH_IA64 = "ia64" ARCH_MIPS = "mips" ARCH_PPC = "ppc" ARCH_PPC64 = "ppc64" ARCH_RISCV32 = "riscv32" ARCH_RISCV64 = "riscv64" ARCH_S390 = "s390" ARCH_S390X = "s390x" ARCH_X86_64 = "x86_64" pykdumpfile-0.5.5.1/kdumpfile/defs_py2.py000066400000000000000000000002001473444745700202710ustar00rootroot00000000000000'''addrxlat.defs_py2 ''' unicode_type = unicode binary_type = str def restore_exception(exc, val, tb): raise exc, val, tb pykdumpfile-0.5.5.1/kdumpfile/defs_py3.py000066400000000000000000000002151473444745700203000ustar00rootroot00000000000000'''addrxlat.defs_py3 ''' unicode_type = str binary_type = bytes def restore_exception(exc, val, tb): raise exc(val).with_traceback(tb) pykdumpfile-0.5.5.1/kdumpfile/exceptions.py000066400000000000000000000050141473444745700207470ustar00rootroot00000000000000'''kdumpfile.exceptions ''' from .constants import * from .utils import to_unicode from _kdumpfile import ffi, lib as C def strerror(status): '''strerror(status) -> error message Return the string describing a given error status.''' return to_unicode(ffi.string(C.kdump_strerror(status))) class KdumpfileError(Exception): '''Common base for all kdumpfile exceptions. KdumpfileError(status[, message]) If message is not specified, use kdumpfile_strerror(status). Attributes: status kdumpfile status code, see ERR_xxx message verbose error message''' def __init__(self, status, message=None): if message is None: message = strerror(status) super(KdumpfileError, self).__init__(message) self.status = status self.message = message def _def_exception(name, status, addbases=()): '''Create an kdumpfile exception for a given status code. The new exception is derived from KdumpfileError, but you may specify additional base classes with addbases. ''' def __init__(self, *args, **kwargs): super(cls, self).__init__(status, *args, **kwargs) def __repr__(self): "x.__repr__() <==> repr(x)" return "%s%r" % (self.__class__.__name__, self.args[1:]) di = { '__doc__' : name + '([message])' + ''' If message is not specified, use the default error message. ''', 'status' : status, '__init__' : __init__, '__repr__' : __repr__, } cls = type(name, (KdumpfileError,) + addbases, di) return cls _exceptions = { ('SystemError', ERR_SYSTEM, (OSError,)), ('NotImplementedError', ERR_NOTIMPL, (NotImplementedError,)), ('NoDataError', ERR_NODATA), ('CorruptError', ERR_CORRUPT), ('InvalidError', ERR_INVALID), ('NoKeyError', ERR_NOKEY, (KeyError,)), ('EOFError', ERR_EOF, (EOFError,)), ('BusyError', ERR_BUSY), ('AddressTranslationError', ERR_ADDRXLAT), } _exc_map = {} for _exc in _exceptions: _cls = _def_exception(*_exc) globals()[_cls.__name__] = _cls _exc_map[_cls.status] = _cls # Free up init-time variables del _exc, _cls, _exceptions, _def_exception def get_exception(status, *args, **kwargs): '''get_exception(status[, message]) Get an appropriate exception for the given status. If there is no specific exception, make an instance of KdumpfileError. ''' exc = _exc_map.get(status) if exc is not None: return exc(*args, **kwargs) return KdumpfileError(status, *args, **kwargs) pykdumpfile-0.5.5.1/kdumpfile/objects.py000066400000000000000000000317751473444745700202340ustar00rootroot00000000000000'''kdumpfile.objects ''' from collections.abc import MutableMapping from _kdumpfile import ffi, lib as C from .constants import * from .exceptions import * from . import utils import addrxlat ### ### kdump_ctx_t ### class Context(object): '''Context() -> context''' def __init__(self, ptr=None): if ptr is None: ptr = C.kdump_new() if not ptr: raise MemoryError('Could not allocate kdump_ctx_t') self._cdata = ptr def __del__(self): C.kdump_free(self._cdata) def clone(self, flags): '''CTX.clone() -> cloned context''' clone = C.kdump_clone(self._cdata, flags) if not clone: raise MemoryError('Could not allocate kdump_ctx_t') return Context(clone) def err(self, status, msg): '''CTX.err(status, msg) -> status Set the error message.''' s = utils.to_bytes(msg) return C.kdump_err(self._cdata, status, b'%s', ffi.from_buffer(s)) def clear_err(self): '''CTX.clear_err() Clear the error message.''' C.kdump_clear_err(self._cdata) def get_err(self): '''CTX.get_err() -> error string Return a detailed error description of the last error condition.''' err = C.kdump_get_err(self._cdata) if not err: return None else: return utils.to_unicode(ffi.string(err)) def get_addrxlat(self): '''CTX.get_addrxlat() -> (addrxlat context, addrxlat system) Get the associated address translation data structures.''' axctx = ffi.new('addrxlat_ctx_t **') axsys = ffi.new('addrxlat_sys_t **') status = C.kdump_get_addrxlat(self._cdata, axctx, axsys) if status != OK: raise get_exception(status, self.get_err()) return (addrxlat.Context(addrxlat.ffi.cast('addrxlat_ctx_t *', axctx[0])), addrxlat.System(addrxlat.ffi.cast('addrxlat_sys_t *', axsys[0]))) def d16toh(self, val): '''CTX.d16toh(val) -> 16-bit value in host byte order''' return C.kdump_d16toh(self._cdata, val) def d32toh(self, val): '''CTX.d32toh(val) -> 32-bit value in host byte order''' return C.kdump_d32toh(self._cdata, val) def d64toh(self, val): '''CTX.d64toh(val) -> 64-bit value in host byte order''' return C.kdump_d64toh(self._cdata, val) def set_filename(self, name): '''CTX.set_filename(name) Provide a descriptive name for a single-file dump.''' status = C.kdump_set_filename(self._cdata, utils.to_bytes(name)) if status != OK: raise get_exception(status, self.get_err()) def set_filenames(self, *names): '''CTX.set_filenames(name...) Provide descriptive names for each file in a set of dump files.''' names = tuple(ffi.new('char[]', utils.to_bytes(n)) for n in names) array = ffi.new('char*[]', names) status = C.kdump_set_filenames(self._cdata, len(names), array) if status != OK: raise get_exception(status, self.get_err()) def open_fd(self, fd): '''CTX.open_fd(fd) Associate this context with a dump file using its file descriptor.''' status = C.kdump_open_fd(self._cdata, fd) if status != OK: raise get_exception(status, self.get_err()) def open_fdset(self, *fdset): '''CTX.open_fdset(fd...) Associate this context with a set of dump files using their file descriptors.''' fds = ffi.new('int[]', fdset) status = C.kdump_open_fdset(self._cdata, len(fdset), fds) if status != OK: raise get_exception(status, self.get_err()) def open(self, path): '''CTX.open(path) Open a dump file and associate this context with it.''' self._file = open(path) status = C.kdump_set_number_attr(self._cdata, b'file.fd', self._file.fileno()) if status != OK: raise get_exception(status, self.get_err()) def read(self, addrspace, address, size): '''CTX.read(addrspace, address, size) -> buffer Read decoded binary data from a starting address.''' buf = ffi.new('char[]', size) rd = ffi.new('size_t*') rd[0] = size status = C.kdump_read(self._cdata, addrspace, address, buf, rd) if status != OK: raise get_exception(status, self.get_err()) return ffi.buffer(buf) def read_string(self, addrspace, addr): '''CTX.read(addrspace, address, size) -> bytes Read a NUL-terminated string from an address.''' pstr = ffi.new('char**') status = C.kdump_read_string(self._cdata, addrspace, addr, pstr) if status != OK: raise get_exception(status, self.get_err()) ret = ffi.string(pstr[0]) C.free(pstr[0]) return ret def vmcoreinfo_raw(self): '''CTX.vmcoreinfo_raw() -> raw bytes Get the raw VMCOREINFO string.''' raw = ffi.new('char**') status = C.kdump_vmcoreinfo_raw(self._cdata, raw) if status != OK: raise get_exception(status, self.get_err()) ret = ffi.string(raw[0]) C.free(raw[0]) return ret def vmcoreinfo_line(self, key): '''CTX.vmcoreinfo_line(key) -> bytes Get the raw VMCOREINFO value by full key name.''' val = ffi.new('char**') status = C.kdump_vmcoreinfo_line(self._cdata, utils.to_bytes(key), val) if status != OK: raise get_exception(status, self.get_err()) ret = ffi.string(val[0]) C.free(val[0]) return ret def vmcoreinfo_symbol(self, name): '''CTX.vmcoreinfo_symbol(name) -> value Get SYMBOL value from VMCOREINFO.''' val = ffi.new('kdump_addr_t*') status = C.kdump_vmcoreinfo_symbol(self._cdata, utils.to_bytes(name), val) if status != OK: raise get_exception(status, self.get_err()) return val[0] @property def attr(self): '''Access to libkdumpfile attributes''' return attr_dir(self, None) class attr_ref(object): '''Attribute reference''' def __init__(self, ctx, key, base=None): self._ctx = ctx if key is None: if base is not None: self._cdata = base._cdata return key = ffi.NULL else: key = utils.to_bytes(key) self._cdata = ffi.new('kdump_attr_ref_t *') if base is None: status = C.kdump_attr_ref(self._ctx._cdata, key, self._cdata) else: status = C.kdump_sub_attr_ref(self._ctx._cdata, base._cdata, key, self._cdata) if status != OK: raise get_exception(status, self._ctx.get_err()) def __del__(self): C.kdump_attr_unref(self._ctx._cdata, self._cdata) class attr_dir(attr_ref, MutableMapping): '''Attribute directory''' # After initialization, this object's attributes become frozen # and further accesses are aliased to libkdumpfile attributes. __frozen = False def __init__(self, ctx, key, base=None): attr_ref.__init__(self, ctx, key, base) MutableMapping.__init__(self) self.__frozen = True def __contains__(self, k): try: ref = attr_ref(self._ctx, k, self) return True except NoKeyError: return False def __getitem__(self, k): try: ref = attr_ref(self._ctx, k, self) except NoKeyError: raise KeyError(k) if C.kdump_attr_ref_type(ref._cdata) == DIRECTORY: return attr_dir(self._ctx, None, ref) v = ffi.new('kdump_attr_t *') status = C.kdump_attr_ref_get(self._ctx._cdata, ref._cdata, v) if status == ERR_NODATA: raise KeyError(k) elif status != OK: raise get_exception(status, self._ctx.get_err()) try: t = v[0].type if t == NUMBER: return v[0].val.number elif t == ADDRESS: return v[0].val.address elif t == STRING: return utils.to_unicode(ffi.string(v[0].val.string)) elif t == BITMAP: return Bitmap(v[0].val.bitmap) elif t == BLOB: return Blob(v[0].val.blob) else: raise NotImplementedError('Unknown attribute type: {}'.format(t)) finally: C.kdump_attr_discard(self._ctx._cdata, v) def __setitem__(self, k, v): ref = attr_ref(self._ctx, k, self) attr = ffi.new('kdump_attr_t *') if v is None: attr.type = NIL else: t = C.kdump_attr_ref_type(ref._cdata) if t == NUMBER: attr.val.number = v elif t == ADDRESS: attr.val.address = v elif t == STRING: s = utils.to_bytes(v) attr.val.string = ffi.from_buffer(s) else: raise NotImplementedError('Unknown attribute type: {}'.format(t)) attr.type = t status = C.kdump_attr_ref_set(self._ctx._cdata, ref._cdata, attr) if status != OK: raise get_exception(status, self._ctx.get_err()) def __delitem__(self, k): self.__setitem(k, None) def __getattr__(self, k): try: return self[k] except KeyError: raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, k)) from None def __setattr__(self, k, v): if self.__frozen: try: self[k] = v except NoKeyError: raise AttributeError(k) from None else: super().__setattr__(k, v) def __delattr__(self, k): self.__setattr__(k, None) def __iter__(self): it = ffi.new('kdump_attr_iter_t *') status = C.kdump_attr_ref_iter_start(self._ctx._cdata, self._cdata, it) if status != OK: raise get_exception(status, self._ctx.get_err()) while it[0].key: yield utils.to_unicode(ffi.string(it[0].key)) status = C.kdump_attr_iter_next(self._ctx._cdata, it) if status != OK: raise get_exception(status, self._ctx.get_err()) def __len__(self): it = ffi.new('kdump_attr_iter_t *') status = C.kdump_attr_ref_iter_start(self._ctx._cdata, self._cdata, it); if status != OK: raise get_exception(status, self._ctx.get_err()) length = 0 while it[0].key: length += 1 status = C.kdump_attr_iter_next(self._ctx._cdata, it) if status != OK: raise get_exception(status, self._ctx.get_err()) return length ### ### kdump_bmp_t ### class Bitmap(object): '''Bitmap() -> dump bitmap''' def __init__(self, ptr): C.kdump_bmp_incref(ptr) self._cdata = ptr def __del__(self): C.kdump_bmp_decref(self._cdata) def get_bits(self, first, last): '''BMP.get_bits(first, last) -> byte array Get bitmap bits as a raw bitmap.''' raw = bytearray((((last - first) | 7) + 1) >> 3) status = C.kdump_bmp_get_bits(self._cdata, first, last, ffi.from_buffer(raw)) if status != OK: raise get_exception(status) return raw def find_set(self, idx): '''BMP.find_set(idx) -> index Find the closest set bit in a bitmapm, starting at idx.''' idx = ffi.new('kdump_addr_t*', idx) status = C.kdump_bmp_find_set(self._cdata, idx) if status != OK: raise get_exception(status) return idx[0] def find_clear(self, idx): '''BMP.find_clear(idx) -> index Find the closest zero bit in a bitmapm, starting at idx.''' idx = ffi.new('kdump_addr_t*', idx) status = C.kdump_bmp_find_clear(self._cdata, idx) if status != OK: raise get_exception(status) return idx[0] ### ### kdump_blob_t ### class Blob(object): '''Blob() -> dump blob''' def __init__(self, ptr=None): if ptr is None: ptr = C.kdump_blob_new(ffi.NULL, 0) if not ptr: raise MemoryError('Could not allocate kdump_blob_t') else: C.kdump_blob_incref(ptr) self._cdata = ptr def __del__(self): C.kdump_blob_decref(self._cdata) def get(self): '''BLOB.get() -> buffer''' buffer = C.kdump_blob_pin(self._cdata) buffer = bytes(ffi.buffer(buffer, C.kdump_blob_size(self._cdata))) C.kdump_blob_unpin(self._cdata) return buffer def set(self, buffer): '''BLOB.set(buffer) Replace blob contents with a new value. The object given as argument must implement the buffer protocol.''' p = C.malloc(len(buffer)) if not p: raise MemoryError('Could not allocate blob buffer') ffi.memmove(p, buffer, len(buffer)) status = C.kdump_blob_set(self._cdata, p, len(buffer)) if status != OK: C.free(p) raise get_exception(status) pykdumpfile-0.5.5.1/kdumpfile/utils.py000066400000000000000000000005431473444745700177300ustar00rootroot00000000000000'''kdumpfile.utils ''' import sys if sys.version_info[0] == 3: from .defs_py3 import * else: from .defs_py2 import * def to_bytes(s): if isinstance(s, binary_type): return s return unicode_type(s).encode("utf-8") def to_unicode(s): if isinstance(s, unicode_type): return s return binary_type(s).decode("utf-8") pykdumpfile-0.5.5.1/pyproject.toml000066400000000000000000000001531473444745700171470ustar00rootroot00000000000000[build-system] requires = ["setuptools", "setuptools-scm", "cffi"] build-backend = "setuptools.build_meta" pykdumpfile-0.5.5.1/setup.cfg000066400000000000000000000013221473444745700160530ustar00rootroot00000000000000[metadata] name = pykdumpfile version = 0.5.5.1 description = Python bindings to libkdumpfile long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/ptesarik/pykdumpfile author = Petr Tesarik author_email = ptesarik@suse.com license = GPLv2+ platforms = any classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) Operating System :: OS Independent Topic :: Software Development :: Debuggers Intended Audience :: Developers Development Status :: 4 - Beta [options] python_requires = >=3.0 packages = addrxlat kdumpfile install_requires = cffi >= 1.8 test_suite = tests pykdumpfile-0.5.5.1/setup.py000066400000000000000000000003651473444745700157520ustar00rootroot00000000000000from setuptools import Extension, setup import sys sys.path.append('') import ffi_addrxlat import ffi_kdumpfile setup( ext_modules=[ ffi_addrxlat.ffi.distutils_extension(), ffi_kdumpfile.ffi.distutils_extension(), ], ) pykdumpfile-0.5.5.1/tests/000077500000000000000000000000001473444745700153765ustar00rootroot00000000000000pykdumpfile-0.5.5.1/tests/test_addrxlat.py000066400000000000000000001135311473444745700206160ustar00rootroot00000000000000import unittest import addrxlat import sys if (sys.version_info.major >= 3): xrange = range class TestAddressSpace(unittest.TestCase): names = ( 'KPHYSADDR', 'MACHPHYSADDR', 'KVADDR', 'NOADDR', ) def test_addrspace_name(self): for name in self.names: self.assertEqual(addrxlat.addrspace_name(addrxlat.__dict__[name]), name) class TestFullAddress(unittest.TestCase): def test_fulladdr_defaults(self): addr = addrxlat.FullAddress() self.assertEqual(addr.addrspace, addrxlat.NOADDR) self.assertEqual(addr.addr, 0) def test_fulladdr_addrspace(self): addr = addrxlat.FullAddress(addrspace=addrxlat.KVADDR) self.assertEqual(addr.addrspace, addrxlat.KVADDR) self.assertEqual(addr.addr, 0) def test_fulladdr_addr(self): addr = addrxlat.FullAddress(addr=0xabcd) self.assertEqual(addr.addrspace, addrxlat.NOADDR) self.assertEqual(addr.addr, 0xabcd) def test_fulladdr_init_pos(self): addr = addrxlat.FullAddress(addrxlat.KVADDR, 0xabcd) self.assertEqual(addr.addrspace, addrxlat.KVADDR) self.assertEqual(addr.addr, 0xabcd) def test_fulladdr_init_kwarg(self): addr = addrxlat.FullAddress(addr=0xabcd, addrspace=addrxlat.KVADDR) self.assertEqual(addr.addrspace, addrxlat.KVADDR) self.assertEqual(addr.addr, 0xabcd) def test_fulladdr_eq(self): addr1 = addrxlat.FullAddress(addrxlat.KVADDR, 0x1234) addr2 = addrxlat.FullAddress(addrxlat.KVADDR, 0x1234) self.assertEqual(addr1, addr2) def test_fulladdr_noteq(self): addr1 = addrxlat.FullAddress(addrxlat.KVADDR, 0x1234) addr2 = addrxlat.FullAddress(addrxlat.KVADDR, 0xabcd) self.assertNotEqual(addr1, addr2) def test_fulladdr_copy(self): addr1 = addrxlat.FullAddress(addrxlat.KVADDR, 0x1234) addr2 = addr1.copy() self.assertIsInstance(addr2, addrxlat.FullAddress) self.assertEqual(addr1.addrspace, addr2.addrspace) self.assertEqual(addr1.addr, addr2.addr) def test_fulladdr_copy_subclass(self): class myfulladdr(addrxlat.FullAddress): pass addr1 = myfulladdr(addrxlat.KVADDR, 0x1234) addr2 = addr1.copy() self.assertIsInstance(addr2, myfulladdr) class TestPTE(unittest.TestCase): names = ( 'PTE_NONE', 'PTE_PFN32', 'PTE_PFN64', 'PTE_AARCH64', 'PTE_IA32', 'PTE_IA32_PAE', 'PTE_X86_64', 'PTE_S390X', 'PTE_PPC64_LINUX_RPN30', 'PTE_AARCH64_LPA', 'PTE_AARCH64_LPA2', 'PTE_ARM', 'PTE_RISCV32', 'PTE_RISCV64', ) def test_pte_format_name(self): for name in self.names: fmt = addrxlat.__dict__[name] libname = addrxlat.pte_format_name(fmt) self.assertEqual(libname, name[4:].lower()) libfmt = addrxlat.pte_format(libname) self.assertEqual(libfmt, fmt) class TestContext(unittest.TestCase): def test_err(self): ctx = addrxlat.Context() ctx.clear_err() self.assertIs(ctx.get_err(), None) status = ctx.err(addrxlat.ERR_CUSTOM_BASE, 'An error message') self.assertEqual(status, addrxlat.ERR_CUSTOM_BASE) self.assertEqual(ctx.get_err(), 'An error message') ctx.clear_err() self.assertIs(ctx.get_err(), None) class TestMethod(unittest.TestCase): def test_meth_defaults(self): meth = addrxlat.Method(addrxlat.NOMETH) self.assertEqual(meth.kind, addrxlat.NOMETH) self.assertEqual(meth.target_as, addrxlat.NOADDR) for i in xrange(len(meth.param)): self.assertEqual(meth.param[i], 0) def test_meth_readonly_kind(self): meth = addrxlat.Method(addrxlat.NOMETH) with self.assertRaises(AttributeError): meth.kind = addrxlat.LINEAR def test_meth_target_as(self): meth = addrxlat.Method(addrxlat.NOMETH, addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.NOMETH) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) for i in xrange(len(meth.param)): self.assertEqual(meth.param[i], 0) def test_meth_param(self): meth = addrxlat.Method(addrxlat.NOMETH, param=(0, 1, 2, 3)) self.assertGreaterEqual(len(meth.param), 4) self.assertEqual(meth.kind, addrxlat.NOMETH) self.assertEqual(meth.target_as, addrxlat.NOADDR) for i in xrange(4): self.assertEqual(meth.param[i], i) for i in xrange(4, len(meth.param)): self.assertEqual(meth.param[i], 0) for i in xrange(4): meth.param[i] += 1 self.assertEqual(meth.kind, addrxlat.NOMETH) self.assertEqual(meth.target_as, addrxlat.NOADDR) for i in xrange(4): self.assertEqual(meth.param[i], i + 1) for i in xrange(4, len(meth.param)): self.assertEqual(meth.param[i], 0) with self.assertRaises(OverflowError): meth.param[0] = 999 with self.assertRaises(OverflowError): meth.param[0] = -1 def test_custom_defaults(self): meth = addrxlat.CustomMethod() self.assertEqual(meth.kind, addrxlat.CUSTOM) self.assertEqual(meth.target_as, addrxlat.NOADDR) def test_custom_readonly_kind(self): meth = addrxlat.CustomMethod() with self.assertRaises(AttributeError): meth.kind = addrxlat.NOMETH def test_custom_target_as(self): meth = addrxlat.CustomMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.CUSTOM) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) def test_custom_notimpl(self): meth = addrxlat.CustomMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.CUSTOM) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) ctx = addrxlat.Context() step = addrxlat.Step(ctx=ctx, meth=meth) with self.assertRaisesRegex(BaseException, "NULL callback"): meth.cb_first_step(step, 0x1234) with self.assertRaisesRegex(BaseException, "NULL callback"): meth.cb_next_step(step) def test_linear_defaults(self): meth = addrxlat.LinearMethod() self.assertEqual(meth.kind, addrxlat.LINEAR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.off, 0) def test_linear_readonly_kind(self): meth = addrxlat.LinearMethod() with self.assertRaises(AttributeError): meth.kind = addrxlat.NOMETH def test_linear_target_as(self): meth = addrxlat.LinearMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.LINEAR) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) self.assertEqual(meth.off, 0) def test_linear_off(self): meth = addrxlat.LinearMethod(off=addrxlat.ADDR_MAX - 0x1234) self.assertEqual(meth.kind, addrxlat.LINEAR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.off, -0x1235) def test_linear_neg_off(self): meth = addrxlat.LinearMethod(off=-addrxlat.ADDR_MAX) self.assertEqual(meth.kind, addrxlat.LINEAR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.off, 1) def test_linear_param(self): meth = addrxlat.LinearMethod(off=0x1234) param = tuple(meth.param) self.assertLess(param.index(0x34), len(meth.param)) meth.param = (0xff,) * len(meth.param) self.assertNotEqual(meth.off, 0x1234) def test_pgt_defaults(self): meth = addrxlat.PageTableMethod() self.assertEqual(meth.kind, addrxlat.PGT) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertIs(meth.root, addrxlat.no_address) self.assertEqual(meth.pte_format, addrxlat.PTE_NONE) self.assertEqual(meth.fields, tuple()) def test_pgt_readonly_kind(self): meth = addrxlat.PageTableMethod() with self.assertRaises(AttributeError): meth.kind = addrxlat.NOMETH def test_pgt_target_as(self): meth = addrxlat.PageTableMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.PGT) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) self.assertIs(meth.root, addrxlat.no_address) self.assertEqual(meth.pte_format, addrxlat.PTE_NONE) self.assertEqual(meth.fields, tuple()) def test_pgt_root(self): root = addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0x1000) meth = addrxlat.PageTableMethod(root=root) self.assertEqual(meth.kind, addrxlat.PGT) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.root, root) self.assertEqual(meth.pte_format, addrxlat.PTE_NONE) self.assertEqual(meth.fields, tuple()) def test_pgt_pte_format(self): meth = addrxlat.PageTableMethod(pte_format=addrxlat.PTE_PFN32) self.assertEqual(meth.kind, addrxlat.PGT) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertIs(meth.root, addrxlat.no_address) self.assertEqual(meth.pte_format, addrxlat.PTE_PFN32) self.assertEqual(meth.fields, tuple()) def test_pgt_fields(self): meth = addrxlat.PageTableMethod(fields=(1, 2, 3)) self.assertEqual(meth.kind, addrxlat.PGT) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertIs(meth.root, addrxlat.no_address) self.assertEqual(meth.pte_format, addrxlat.PTE_NONE) self.assertEqual(meth.fields, (1, 2, 3)) meth.fields = (4, 5, 6) self.assertEqual(meth.fields, (4, 5, 6)) with self.assertRaisesRegex(TypeError, 'not NoneType'): meth.fields = None with self.assertRaisesRegex(IndexError, 'too many initializers'): meth.fields = (0,) * (addrxlat.FIELDS_MAX + 1) def test_lookup_defaults(self): meth = addrxlat.LookupMethod() self.assertEqual(meth.kind, addrxlat.LOOKUP) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.endoff, 0) self.assertEqual(meth.tbl, tuple()) def test_lookup_readonly_kind(self): meth = addrxlat.LookupMethod() with self.assertRaises(AttributeError): meth.kind = addrxlat.NOMETH def test_lookup_target_as(self): meth = addrxlat.LookupMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.LOOKUP) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) self.assertEqual(meth.endoff, 0) self.assertEqual(meth.tbl, tuple()) def test_lookup_endoff(self): meth = addrxlat.LookupMethod(endoff=0x1234) self.assertEqual(meth.kind, addrxlat.LOOKUP) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.endoff, 0x1234) self.assertEqual(meth.tbl, tuple()) def test_lookup_tbl(self): meth = addrxlat.LookupMethod(tbl=((0, 100), (200, 300))) self.assertEqual(meth.kind, addrxlat.LOOKUP) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.endoff, 0) self.assertEqual(meth.tbl, ((0, 100), (200, 300))) with self.assertRaisesRegex(TypeError, 'has no len()'): meth.tbl = None with self.assertRaisesRegex(TypeError, 'no(n-|t )iterable'): meth.tbl = (None,) with self.assertRaisesRegex(TypeError, 'has no len()'): meth.tbl = 1 with self.assertRaisesRegex(TypeError, 'no(n-|t )iterable'): meth.tbl = (1,) with self.assertRaisesRegex(ValueError, 'not enough values to unpack'): meth.tbl = ((),) with self.assertRaisesRegex(ValueError, 'not enough values to unpack'): meth.tbl = ((1,),) with self.assertRaisesRegex(ValueError, 'too many values to unpack'): meth.tbl = ((1, 2, 3),) with self.assertRaisesRegex(TypeError, 'integer is required'): meth.tbl = ((None, None),) with self.assertRaisesRegex(TypeError, 'integer is required'): meth.tbl = ((1, None),) with self.assertRaisesRegex(TypeError, 'integer is required'): meth.tbl = ((None, 1),) def test_memarr_defaults(self): meth = addrxlat.MemoryArrayMethod() self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.base, addrxlat.no_address) self.assertEqual(meth.shift, 0) self.assertEqual(meth.elemsz, 0) self.assertEqual(meth.valsz, 0) def test_memarr_readonly_kind(self): meth = addrxlat.MemoryArrayMethod() with self.assertRaises(AttributeError): meth.kind = addrxlat.NOMETH def test_memarr_target_as(self): meth = addrxlat.MemoryArrayMethod(addrxlat.MACHPHYSADDR) self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.MACHPHYSADDR) self.assertEqual(meth.base, addrxlat.no_address) self.assertEqual(meth.shift, 0) self.assertEqual(meth.elemsz, 0) self.assertEqual(meth.valsz, 0) def test_memarr_base(self): base = addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0x1234) meth = addrxlat.MemoryArrayMethod(base=base) self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.base, base) self.assertEqual(meth.shift, 0) self.assertEqual(meth.elemsz, 0) self.assertEqual(meth.valsz, 0) def test_memarr_shift(self): meth = addrxlat.MemoryArrayMethod(shift=3) self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.base, addrxlat.no_address) self.assertEqual(meth.shift, 3) self.assertEqual(meth.elemsz, 0) self.assertEqual(meth.valsz, 0) def test_memarr_elemsz(self): meth = addrxlat.MemoryArrayMethod(elemsz=12) self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.base, addrxlat.no_address) self.assertEqual(meth.shift, 0) self.assertEqual(meth.elemsz, 12) self.assertEqual(meth.valsz, 0) def test_memarr_valsz(self): meth = addrxlat.MemoryArrayMethod(valsz=8) self.assertEqual(meth.kind, addrxlat.MEMARR) self.assertEqual(meth.target_as, addrxlat.NOADDR) self.assertEqual(meth.base, addrxlat.no_address) self.assertEqual(meth.shift, 0) self.assertEqual(meth.elemsz, 0) self.assertEqual(meth.valsz, 8) class TestRange(unittest.TestCase): def test_range_defaults(self): range = addrxlat.Range() self.assertEqual(range.endoff, 0) self.assertEqual(range.meth, addrxlat.SYS_METH_NONE) def test_range_endoff(self): range = addrxlat.Range(endoff=0x1234) self.assertEqual(range.endoff, 0x1234) self.assertEqual(range.meth, addrxlat.SYS_METH_NONE) def test_range_meth(self): meth = addrxlat.SYS_METH_PGT range = addrxlat.Range(meth=meth) self.assertEqual(range.endoff, 0) self.assertIs(range.meth, addrxlat.SYS_METH_PGT) class TestMap(unittest.TestCase): def test_map_defaults(self): map = addrxlat.Map() self.assertEqual(len(map), 0) def test_map_set(self): map = addrxlat.Map() map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_PGT)) self.assertEqual(len(map), 2) self.assertEqual(map[0].endoff, 0xffff) self.assertEqual(map[0].meth, addrxlat.SYS_METH_PGT) self.assertEqual(map[1].meth, addrxlat.SYS_METH_NONE) def test_map_search(self): map = addrxlat.Map() map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_PGT)) meth2 = map.search(0) self.assertEqual(meth2, addrxlat.SYS_METH_PGT) meth2 = map.search(0x10000) self.assertIs(meth2, addrxlat.SYS_METH_NONE) def test_map_copy(self): map = addrxlat.Map() map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_PGT)) self.assertEqual(len(map), 2) map2 = map.copy() self.assertNotEqual(map2, map) self.assertEqual(len(map2), 2) self.assertEqual(map2[0].endoff, 0xffff) self.assertEqual(map2[0].meth, addrxlat.SYS_METH_PGT) self.assertEqual(map2[1].endoff, map[1].endoff) self.assertIs(map2[1].meth, addrxlat.SYS_METH_NONE) class TestSystem(unittest.TestCase): def test_sys_defaults(self): sys = addrxlat.System() for i in xrange(addrxlat.SYS_MAP_NUM): map = sys.get_map(i) self.assertIs(map, None) for i in xrange(addrxlat.SYS_METH_NUM): meth = sys.get_meth(i) self.assertEqual(meth.kind, addrxlat.NOMETH) def test_sys_map(self): sys = addrxlat.System() newmap = addrxlat.Map() for mapidx in xrange(addrxlat.SYS_MAP_NUM): sys.set_map(mapidx, newmap) for i in xrange(mapidx + 1): map = sys.get_map(i) self.assertEqual(map, newmap) for i in xrange(mapidx + 1, addrxlat.SYS_MAP_NUM): map = sys.get_map(i) self.assertIs(map, None) for i in xrange(addrxlat.SYS_METH_NUM): meth = sys.get_meth(i) self.assertEqual(meth.kind, addrxlat.NOMETH) def test_sys_meth(self): sys = addrxlat.System() newdesc = addrxlat.LinearMethod(0) for i in xrange(addrxlat.SYS_MAP_NUM): map = sys.get_map(i) self.assertIs(map, None) for methidx in xrange(addrxlat.SYS_METH_NUM): sys.set_meth(methidx, newdesc) for i in xrange(methidx): meth = sys.get_meth(i) self.assertEqual(meth, newdesc) for i in xrange(methidx + 1, addrxlat.SYS_METH_NUM): meth = sys.get_meth(i) self.assertEqual(meth.kind, addrxlat.NOMETH) class TestStep(unittest.TestCase): def setUp(self): self.ctx = addrxlat.Context() def test_step_defaults(self): step = addrxlat.Step(self.ctx) self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_sys(self): sys = addrxlat.System() step = addrxlat.Step(self.ctx, sys=sys) self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, sys) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_meth(self): meth = addrxlat.LinearMethod() step = addrxlat.Step(self.ctx, meth=meth) self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, meth) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_remain(self): step = addrxlat.Step(self.ctx) step.remain = 3 self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 3) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_elemsz(self): step = addrxlat.Step(self.ctx) step.elemsz = 8 self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 8) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_base(self): step = addrxlat.Step(self.ctx) base = addrxlat.FullAddress(addrxlat.KVADDR, 0xabcd) step.base = base self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertIs(step.base, base) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_base_addrspace(self): step = addrxlat.Step(self.ctx) step.base = addrxlat.FullAddress(addrxlat.NOADDR, 0) step.base.addrspace = addrxlat.KVADDR self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.FullAddress(addrxlat.KVADDR, 0)) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_base_addr(self): step = addrxlat.Step(self.ctx) step.base = addrxlat.FullAddress(addrxlat.NOADDR, 0) step.base.addr = 0x1234 self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.FullAddress(addrxlat.NOADDR, 0x1234)) self.assertIs(step.raw, None) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_raw(self): step = addrxlat.Step(self.ctx) with self.assertRaises(AttributeError): step.raw = 0xabcd meth = addrxlat.LinearMethod() step.meth = meth with self.assertRaisesRegex(TypeError, 'cannot be changed'): step.raw = 0xabcd meth = addrxlat.PageTableMethod() step.meth = meth step.raw = 0xabcd self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, meth) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertEqual(step.raw, 0xabcd) idx = (0,) * (addrxlat.FIELDS_MAX + 1) self.assertEqual(step.idx, idx) def test_step_idx(self): step = addrxlat.Step(self.ctx) idx = (1, 2, 3, 4) step.idx = idx self.assertIs(step.ctx, self.ctx) self.assertIs(step.sys, None) self.assertIs(step.meth, None) self.assertEqual(step.remain, 0) self.assertEqual(step.elemsz, 0) self.assertEqual(step.base, addrxlat.no_address) self.assertIs(step.raw, None) idx = idx + (0,) * (addrxlat.FIELDS_MAX + 1 - len(idx)) self.assertEqual(step.idx, idx) with self.assertRaisesRegex(TypeError, 'not NoneType'): step.idx = None with self.assertRaisesRegex(IndexError, 'too many initializers'): step.idx = (0,) * (addrxlat.FIELDS_MAX + 2) with self.assertRaisesRegex(TypeError, 'integer is required'): step.idx = (None,) class TestOperator(unittest.TestCase): def setUp(self): self.ctx = addrxlat.Context() def test_op_defaults(self): op = addrxlat.Operator(self.ctx) self.assertIs(op.ctx, self.ctx) self.assertIs(op.sys, None) self.assertEqual(op.caps, 0) def test_op_sys(self): sys = addrxlat.System() op = addrxlat.Operator(self.ctx, sys=sys) self.assertIs(op.ctx, self.ctx) self.assertEqual(op.sys, sys) self.assertEqual(op.caps, 0) def test_op_caps(self): op = addrxlat.Operator(self.ctx, caps=addrxlat.CAPS(addrxlat.KVADDR)) self.assertIs(op.ctx, self.ctx) self.assertIs(op.sys, None) self.assertEqual(op.caps, addrxlat.CAPS(addrxlat.KVADDR)) # # Test translation system has the following layout: # # MAP_HW: # 0-ffff: PGT root=MACHPHYSADDR:0 # 10000-ffffffffffffffff: NONE # # MAP_KV_PHYS: # 0-1fff: DIRECT off=0x1000 # 2000-3fff: LOOKUP # 4000-5fff: MEMARR base=KVADDR:0 # 6000-ffff: PGT # 10000-ffffffffffffffff: NONE # # MAP_KPHYS_DIRECT: # 0-fff: NONE # 1000-2fff: RDIRECT # 3000-ffffffffffffffff: NONE # # MAP_MACHPHYS_KPHYS: # 0-ffff: NONE # 10000-1ffff: KPHYS_MACHPHYS # 20000-ffffffffffffffff: NONE # # MAP_KPHYS_MACHPHYS: # 0-ffff: MACHPHYS_KPHYS # 10000-ffffffffffffffff: NONE # class TestTranslation(unittest.TestCase): def setUp(self): def get_page(buf): # Page table level 2 @ 0 if buf.addr.addr == 0x10000: buf.data = bytearray((0x00, 0x00, 0x01, 0x01)) buf.byte_order = addrxlat.BIG_ENDIAN # Page table level 1 @ 0x65 elif buf.addr.addr == 0x10100 + 0x65 * 4: buf.data = bytearray((0x00, 0x00, 0x01, 0xc0)) buf.byte_order = addrxlat.BIG_ENDIAN # Page table level 1 @ 0x41 elif buf.addr.addr == 0x10100 + 0x41 * 4: buf.data = bytearray((0x00, 0x00, 0x01, 0xa9)) buf.byte_order = addrxlat.BIG_ENDIAN # Memory array at 0x40 elif buf.addr.addr == 0x11000 + 0x40 * 4: buf.data = bytearray((0x00, 0x00, 0x00, 0xaa)) buf.byte_order = addrxlat.BIG_ENDIAN else: raise addrxlat.NoDataError self.ctx = addrxlat.Context() self.ctx.read_caps = addrxlat.CAPS(addrxlat.MACHPHYSADDR) self.ctx.cb_get_page = get_page self.sys = addrxlat.System() map = addrxlat.Map() self.sys.set_map(addrxlat.SYS_MAP_HW, map) meth = addrxlat.PageTableMethod(addrxlat.MACHPHYSADDR) meth.root = addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0x10000) meth.pte_format = addrxlat.PTE_PFN32 meth.fields = (8, 8, 8) self.sys.set_meth(addrxlat.SYS_METH_PGT, meth) map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_PGT)) map = addrxlat.Map() self.sys.set_map(addrxlat.SYS_MAP_KV_PHYS, map) meth = addrxlat.LinearMethod(addrxlat.KPHYSADDR, 0x1000) self.sys.set_meth(addrxlat.SYS_METH_DIRECT, meth) map.set(0, addrxlat.Range(0x1fff, addrxlat.SYS_METH_DIRECT)) meth = addrxlat.LookupMethod(addrxlat.KPHYSADDR) meth.endoff = 0xff meth.tbl = ((0x2000, 0xfa00), (0x3000, 0xfb00), (0x3100, 0xff00)) self.sys.set_meth(addrxlat.SYS_METH_CUSTOM, meth) map.set(0x2000, addrxlat.Range(0x1fff, addrxlat.SYS_METH_CUSTOM)) meth = addrxlat.MemoryArrayMethod(addrxlat.KPHYSADDR) meth.base = addrxlat.FullAddress(addrxlat.KVADDR, 0) meth.shift = 8 meth.elemsz = 4 meth.valsz = 4 self.sys.set_meth(addrxlat.SYS_METH_CUSTOM + 1, meth) map.set(0x4000, addrxlat.Range(0x1fff, addrxlat.SYS_METH_CUSTOM + 1)) map.set(0x6000, addrxlat.Range(0x9fff, addrxlat.SYS_METH_PGT)) map = addrxlat.Map() self.sys.set_map(addrxlat.SYS_MAP_KPHYS_DIRECT, map) meth = addrxlat.LinearMethod(addrxlat.KVADDR, -0x1000) self.sys.set_meth(addrxlat.SYS_METH_RDIRECT, meth) map.set(0x1000, addrxlat.Range(0x1fff, addrxlat.SYS_METH_RDIRECT)) map = addrxlat.Map() self.sys.set_map(addrxlat.SYS_MAP_MACHPHYS_KPHYS, map) meth = addrxlat.LinearMethod(addrxlat.KPHYSADDR, -0x10000) self.sys.set_meth(addrxlat.SYS_METH_MACHPHYS_KPHYS, meth) map.set(0x10000, addrxlat.Range(0xffff, addrxlat.SYS_METH_MACHPHYS_KPHYS)) map = addrxlat.Map() self.sys.set_map(addrxlat.SYS_MAP_KPHYS_MACHPHYS, map) meth = addrxlat.LinearMethod(addrxlat.MACHPHYSADDR, 0x10000) self.sys.set_meth(addrxlat.SYS_METH_KPHYS_MACHPHYS, meth) map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_KPHYS_MACHPHYS)) def test_fulladdr_conv_kphys_machphys(self): "KPHYS -> MACHPHYS using offset" addr = addrxlat.FullAddress(addrxlat.KPHYSADDR, 0x2345) addr.conv(addrxlat.MACHPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0x12345)) def test_fulladdr_fail_kphys_machphys(self): "KPHYS -> MACHPHYS out of bounds" addr = addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xf4255) with self.assertRaisesRegex(addrxlat.NoMethodError, 'No way to translate'): addr.conv(addrxlat.MACHPHYSADDR, self.ctx, self.sys) def test_fulladdr_conv_machphys_kphys(self): "MACHPHYS -> KPHYS using offset" addr = addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0x1abcd) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xabcd)) def test_fulladdr_fail_machphys_kphys(self): "MACHPHYS -> KPHYS out of bounds" addr = addrxlat.FullAddress(addrxlat.MACHPHYSADDR, 0xabcd) with self.assertRaisesRegex(addrxlat.NoMethodError, 'No way to translate'): addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) def test_fulladdr_conv_direct(self): "KV -> KPHYS using directmap" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x1234) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0x2234)) def test_fulladdr_conv_lookup(self): "KV -> KPHYS using lookup" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x2055) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xfa55)) def test_fulladdr_conv_memarr(self): "KV -> KPHYS using memory array" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x4055) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xaa55)) def test_fulladdr_conv_memarr_pgt(self): "KV -> KPHYS using fallback from memory array to page tables" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x4155) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xa955)) def test_fulladdr_fail_memarr(self): "KV -> KPHYS using memory array returns None" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x4255) with self.assertRaises(addrxlat.NoDataError): addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) def test_fulladdr_conv_pgt(self): "KV -> KPHYS using page tables" addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x6502) addr.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0xc002)) def test_fulladdr_conv_rdirect(self): "KPHYS -> KV using reverse directmap" addr = addrxlat.FullAddress(addrxlat.KPHYSADDR, 0x2345) addr.conv(addrxlat.KVADDR, self.ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KVADDR, 0x1345)) def test_op_direct(self): "Operator using directmap" class hexop(addrxlat.Operator): def __init__(self, prefix='', *args, **kwargs): super(hexop, self).__init__(*args, **kwargs) self.prefix = prefix def callback(self, addr): return '{}{:x}'.format(self.prefix, addr.addr) myop = hexop(ctx=self.ctx, sys=self.sys, caps=addrxlat.CAPS(addrxlat.KPHYSADDR), prefix='0x') result = myop(addrxlat.FullAddress(addrxlat.KVADDR, 0xabc)) self.assertEqual(result, '0x1abc') def test_subclass_memarr(self): "KV -> KPHYS using memory array and a subclass" class mycontext(addrxlat.Context): def __init__(self, *args, **kwargs): super(mycontext, self).__init__(*args, **kwargs) self.read_caps = addrxlat.CAPS(addrxlat.MACHPHYSADDR) def cb_get_page(self, buf): # Memory array at 0x40 if buf.addr.addr == 0x11000 + 0x40 * 4: buf.data = bytearray((0x00, 0x00, 0x00, 0x12)) buf.byte_order = addrxlat.BIG_ENDIAN else: raise addrxlat.NoDataError ctx = mycontext() addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x4034) addr.conv(addrxlat.KPHYSADDR, ctx, self.sys) self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0x1234)) CUSTOM_MAGIC_ADDR = 0x4d795f4d61676963 # My_Magic CUSTOM_MAGIC_ADDR2 = 0x4d61676963546f6f # MagicToo class _magic_custom(addrxlat.CustomMethod): def _cb_first_step(self, step, addr): step.base = { 'as': addrxlat.NOADDR, 'addr': CUSTOM_MAGIC_ADDR } step.idx[0] = addr & 0xff step.idx[1] = addr >> 8 step.remain = 2 return addrxlat.OK def _cb_next_step(self, step): step.base.addr = CUSTOM_MAGIC_ADDR2 + step.idx[1] step.elemsz = 0x100 return addrxlat.OK class TestCustom(unittest.TestCase): def setUp(self): self.ctx = addrxlat.Context() def first_step(step, addr): step.base = addrxlat.FullAddress(addrxlat.NOADDR, 0xabcdef) step.idx = (addr & 0xff, addr >> 8) step.remain = 2 def next_step(step): step.base.addr = 0x123456 + step.idx[1] step.elemsz = 0x100 self.meth = addrxlat.CustomMethod() self.meth.target_as = addrxlat.KPHYSADDR self.meth.cb_first_step = first_step self.meth.cb_next_step = next_step self.magic = _magic_custom() self.meth_ext = addrxlat.MethodFromCData(self.magic._cdata) self.assertEqual(self.meth_ext.kind, addrxlat.CUSTOM) self.assertEqual(self.meth_ext.target_as, addrxlat.NOADDR) self.meth_ext.target_as = addrxlat.KPHYSADDR self.meth_extmod = addrxlat.MethodFromCData(self.magic._cdata) self.meth_extmod.target_as = addrxlat.KPHYSADDR self.meth_extmod.cb_next_step = next_step def test_customdesc_cb(self): step = addrxlat.Step(ctx=self.ctx, meth=self.meth) self.assertEqual(step.base, addrxlat.no_address) self.meth.cb_first_step(step, 0x1234) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, 0xabcdef) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) self.meth.cb_next_step(step) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, 0x123456 + 0x12) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) def test_customdesc_conv(self): sys = addrxlat.System() map = addrxlat.Map() sys.set_meth(addrxlat.SYS_METH_CUSTOM, self.meth) map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_CUSTOM)) sys.set_map(addrxlat.SYS_MAP_KV_PHYS, map) addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x2345) addr.conv(addrxlat.KPHYSADDR, self.ctx, sys) self.assertEqual(addr.addrspace, addrxlat.KPHYSADDR) self.assertEqual(addr.addr, 0x123456 + 0x4523) def test_customdesc_ext_cb(self): step = addrxlat.Step(ctx=self.ctx, meth=self.meth_ext) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.meth_ext.cb_first_step(step, 0x1234) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, CUSTOM_MAGIC_ADDR) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) self.meth_ext.cb_next_step(step) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, CUSTOM_MAGIC_ADDR2 + 0x12) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) def test_customdesc_ext_conv(self): sys = addrxlat.System() map = addrxlat.Map() sys.set_meth(addrxlat.SYS_METH_CUSTOM, self.meth_ext) map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_CUSTOM)) sys.set_map(addrxlat.SYS_MAP_KV_PHYS, map) addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x2345) addr.conv(addrxlat.KPHYSADDR, self.ctx, sys) self.assertEqual(addr.addrspace, addrxlat.KPHYSADDR) self.assertEqual(addr.addr, CUSTOM_MAGIC_ADDR2 + 0x4523) def test_customdesc_extmod_cb(self): step = addrxlat.Step(ctx=self.ctx, meth=self.meth_extmod) self.assertEqual(step.base, addrxlat.no_address) self.meth_extmod.cb_first_step(step, 0x1234) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, CUSTOM_MAGIC_ADDR) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) self.meth_extmod.cb_next_step(step) self.assertEqual(step.base.addrspace, addrxlat.NOADDR) self.assertEqual(step.base.addr, 0x123456 + 0x12) self.assertEqual(step.idx[0], 0x34) self.assertEqual(step.idx[1], 0x12) def test_customdesc_extmod_conv(self): sys = addrxlat.System() map = addrxlat.Map() sys.set_meth(addrxlat.SYS_METH_CUSTOM, self.meth_extmod) map.set(0, addrxlat.Range(0xffff, addrxlat.SYS_METH_CUSTOM)) sys.set_map(addrxlat.SYS_MAP_KV_PHYS, map) addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x2345) addr.conv(addrxlat.KPHYSADDR, self.ctx, sys) self.assertEqual(addr.addrspace, addrxlat.KPHYSADDR) self.assertEqual(addr.addr, 0x123456 + 0x4523) if __name__ == '__main__': unittest.main() pykdumpfile-0.5.5.1/tests/test_kdumpfile.py000066400000000000000000000050731473444745700207740ustar00rootroot00000000000000import unittest import kdumpfile import sys def get_attr_item(attr, key): return attr[key] def get_ostype_attr(attr): return attr.addrxlat.ostype def iter_search_subkey(attr_dir, name): found = False for key in attr_dir: if key == name: found = True return found class TestContext(unittest.TestCase): err_msg = 'Custom error message' err_msg2 = 'Another error' def test_err(self): ctx = kdumpfile.Context() self.assertIsNone(ctx.get_err()) ctx.err(kdumpfile.OK, self.err_msg) self.assertIsNone(ctx.get_err()) ctx.err(kdumpfile.ERR_NOTIMPL, self.err_msg) self.assertEqual(ctx.get_err(), self.err_msg) ctx.err(kdumpfile.ERR_NOTIMPL, self.err_msg2) self.assertEqual(ctx.get_err(), '{}: {}'.format(self.err_msg2, self.err_msg)) ctx.clear_err() self.assertIsNone(ctx.get_err()) def test_attr(self): ctx = kdumpfile.Context() attr = ctx.attr self.assertIsNone(attr.get(kdumpfile.ATTR_OSTYPE)) self.assertRaises(KeyError, get_attr_item, attr, kdumpfile.ATTR_OSTYPE) self.assertRaises(AttributeError, get_ostype_attr, attr) # unset directories can be instantiated but not iterated self.assertTrue('ostype' in attr.addrxlat) self.assertRaises(kdumpfile.NoDataError, iter_search_subkey, attr.addrxlat, 'ostype') # unknown OS type fails early and does not change the attribute value self.assertRaises(NotImplementedError, attr.__setitem__, kdumpfile.ATTR_OSTYPE, 'unknown') self.assertRaises(KeyError, get_attr_item, attr, kdumpfile.ATTR_OSTYPE) attr[kdumpfile.ATTR_OSTYPE] = 'linux' self.assertEqual(attr.get(kdumpfile.ATTR_OSTYPE), 'linux') self.assertEqual(attr[kdumpfile.ATTR_OSTYPE], 'linux') self.assertEqual(attr.addrxlat.ostype, 'linux') self.assertTrue(iter_search_subkey(attr.addrxlat, 'ostype')) del attr.addrxlat.ostype self.assertIsNone(attr.get(kdumpfile.ATTR_OSTYPE)) self.assertRaises(KeyError, get_attr_item, attr, kdumpfile.ATTR_OSTYPE) self.assertRaises(AttributeError, get_ostype_attr, attr) # unset attributes are contained but skipped in iteration self.assertFalse(iter_search_subkey(attr.addrxlat, 'ostype')) attr.addrxlat.ostype = 'linux' self.assertEqual(attr.get(kdumpfile.ATTR_OSTYPE), 'linux') self.assertEqual(attr[kdumpfile.ATTR_OSTYPE], 'linux') self.assertEqual(attr.addrxlat.ostype, 'linux') if __name__ == '__main__': unittest.main()