diff --git a/Doxyfile b/Doxyfile index 11be3ee7..73bacdad 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,7 +1,7 @@ -# Doxyfile 1.8.5 +# Doxyfile 1.12.0 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. +# Doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. @@ -12,16 +12,26 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use Doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use Doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -32,9 +42,6 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -# NOTE: These are taken from the configure.ac file. The output looks better -# when placing the version in the PROJECT_NAME. Thje PROJECT_NUMBER seems -# intended more for things like the RCS version. PROJECT_NAME = $(PROJECT)-$(VERSION) # The PROJECT_NUMBER tag can be used to enter a project or revision number. This @@ -49,53 +56,79 @@ PROJECT_NUMBER = PROJECT_BRIEF = "Kernel coredump file access" -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If +# entered, it will be relative to the location where Doxygen was started. If # left blank the current directory will be used. -# NOTE: This is taken from the DX_DOCDIR variable (set by calling -# DX_INIT_DOXYGEN). The Makefile relies on it being there. OUTPUT_DIRECTORY = $(DOCDIR) -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where +# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding Doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this +# documentation generated by Doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- -# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, -# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, -# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# Turkish, Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -116,13 +149,13 @@ REPEAT_BRIEF = YES ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief +# Doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. @@ -130,7 +163,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -140,16 +173,13 @@ FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to +# If left blank the directory from which Doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. +# will be relative from the directory where Doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -# NOTE: This is taken from the srcdir variable, which "make distcheck" plays -# with. You may need to add subdirectory(s) here, depending on your directory -# structure. But you almost certainly want the SRCDIR itself to be stripped. STRIP_FROM_PATH = $(SRCDIR) # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the @@ -161,14 +191,14 @@ STRIP_FROM_PATH = $(SRCDIR) STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief @@ -177,7 +207,17 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by Doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) @@ -185,7 +225,7 @@ JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this @@ -197,15 +237,23 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and Doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# Doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as Doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -220,20 +268,19 @@ TAB_SIZE = 8 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -262,46 +309,81 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make Doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by Doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by Doxygen, so you can +# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES -# When enabled doxygen tries to link words that correspond to documented +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 6. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 6 + +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + +# When enabled Doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and +# tag to YES in order to let Doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -313,16 +395,16 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. +# Doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. @@ -331,13 +413,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then Doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -382,21 +471,42 @@ TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The +# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# Doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest +# symbols. At the end of a run Doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use +# during processing. When set to 0 Doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -406,35 +516,41 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -449,7 +565,14 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. @@ -457,23 +580,24 @@ EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -486,29 +610,57 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = $(ENABLE_INTERNAL) -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and macOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. @@ -520,21 +672,22 @@ FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. @@ -546,7 +699,7 @@ SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. @@ -563,37 +716,35 @@ SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -618,8 +769,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -639,24 +790,25 @@ SHOW_FILES = YES SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from +# Doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file +# by Doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated +# by Doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can +# that represents Doxygen's defaults, run Doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# Note that if you run Doxygen from a directory containing a file called +# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = @@ -664,27 +816,42 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. CITE_BIB_FILES = +# The EXTERNAL_TOOL_PATH tag can be used to extend the search path (PATH +# environment variable) so that external tools such as latex and gs can be +# found. +# Note: Directories specified with EXTERNAL_TOOL_PATH are added in front of the +# path already specified by the PATH variable, and are added in the order +# specified. +# Note: This option is particularly useful for macOS version 14 (Sonoma) and +# higher, when running Doxygen from Doxywizard, because in this case any user- +# defined changes to the PATH are ignored. A typical example on macOS is to set +# EXTERNAL_TOOL_PATH = /Library/TeX/texbin /usr/local/bin +# together with the standard path, the full search path used by doxygen when +# launching external tools will then become +# PATH=/Library/TeX/texbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + +EXTERNAL_TOOL_PATH = + #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the +# standard output by Doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -692,42 +859,89 @@ QUIET = YES WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete +# function parameter documentation. If set to NO, Doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, Doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO -# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about +# undocumented enumeration values. If set to NO, Doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + +# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the Doxygen process Doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that Doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of Doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -738,34 +952,48 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -# NOTE: You do want to limit the search for specific sub-directories. -# If you "make distcheck" and things go wrong, there's a leftover -# ($PROJECT)-$VERSION) file containing a copy of all the sources. If you don't -# limit the search, and forget to clean up, then doxygen start seeing double... -# It is important to root all paths with SRCDIR - again, because of "make -# distcheck". So usually this would be something like "$(SRCDIR)/src". INPUT = $(SRCDIR) # This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that Doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by Doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -779,10 +1007,11 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # -# Note that relative paths are relative to the directory from which doxygen is +# Note that relative paths are relative to the directory from which Doxygen is # run. -EXCLUDE = $(SRCDIR)/config.h $(SRCDIR)/tests +EXCLUDE = $(SRCDIR)/config.h \ + $(SRCDIR)/tests # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -804,12 +1033,10 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test -EXCLUDE_SYMBOLS = _GNU_SOURCE ATTR +EXCLUDE_SYMBOLS = _GNU_SOURCE \ + ATTR # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -837,7 +1064,7 @@ EXAMPLE_RECURSIVE = NO IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should +# The INPUT_FILTER tag can be used to specify a program that Doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # @@ -851,6 +1078,15 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that Doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. INPUT_FILTER = @@ -860,11 +1096,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -881,10 +1121,19 @@ FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. +# and want to reuse the introduction page also for the Doxygen output. USE_MDFILE_AS_MAINPAGE = README.md +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -899,12 +1148,13 @@ USE_MDFILE_AS_MAINPAGE = README.md SOURCE_BROWSER = $(ENABLE_INTERNAL) # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. @@ -912,7 +1162,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -924,7 +1174,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -942,28 +1192,28 @@ REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# point to the HTML generated by the htags(1) tool instead of Doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # -# The result: instead of the source browser generated by doxygen, the links to +# The result: instead of the source browser generated by Doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. @@ -982,17 +1232,11 @@ VERBATIM_HEADERS = NO ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1001,10 +1245,9 @@ IGNORE_PREFIX = # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output # The default value is: YES. -# NOTE: You can turn this off by running "configure --disable-doxygen-html". GENERATE_HTML = $(GENERATE_HTML) # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a @@ -1013,7 +1256,6 @@ GENERATE_HTML = $(GENERATE_HTML) # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -# NOTE: The Makefile depends on this being 'html'. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each @@ -1024,40 +1266,40 @@ HTML_OUTPUT = html HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a +# each generated HTML page. If the tag is left blank Doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. +# that Doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally +# for information on how to generate the default header that Doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description +# default header when upgrading to a newer version of Doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard +# generated HTML page. If the tag is left blank Doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. +# that Doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. +# the HTML output. If left blank Doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. +# sheet that Doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. @@ -1065,13 +1307,20 @@ HTML_FOOTER = HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by Doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1086,10 +1335,23 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1098,7 +1360,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1116,13 +1378,16 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1132,6 +1397,33 @@ HTML_TIMESTAMP = NO HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then Doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1147,13 +1439,14 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, Doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1167,6 +1460,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1189,14 +1489,18 @@ DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for @@ -1205,7 +1509,6 @@ DOCSET_PUBLISHER_NAME = Publisher # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -# NOTE: You can turn this off by running "configure --disable-doxygen-chm". GENERATE_HTMLHELP = $(GENERATE_HTMLHELP) # The CHM_FILE tag can be used to specify the file name of the resulting .chm @@ -1213,37 +1516,32 @@ GENERATE_HTMLHELP = $(GENERATE_HTMLHELP) # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -# NOTE: This seems to be relative to the HTML directory. The Makefile depends -# on it ending up being directly in the OUTPUT_DIRECTORY. Since DOCDIR is -# relative, using '..' seems the only safe way to specify this. CHM_FILE = ../$(PROJECT).chm # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# Doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -# NOTE: configure finds HHC automatically for you; if it can't, it will turn -# CHM generation off. HHC_LOCATION = $(HHC_PATH) -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -# NOTE: You can generate the CHI by running "configure # --doxygen-enable-chi" GENERATE_CHI = $(GENERATE_CHI) -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1256,6 +1554,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1274,7 +1582,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1282,8 +1591,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1291,30 +1600,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1356,19 +1665,31 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by Doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. +# Doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. @@ -1377,6 +1698,12 @@ GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 +# When the SHOW_ENUM_VALUES tag is set doxygen will show the specified +# enumeration values besides the enumeration mnemonics. +# The default value is: NO. + +SHOW_ENUM_VALUES = NO + # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. @@ -1384,36 +1711,49 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML +# Doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. -FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1422,11 +1762,29 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1439,33 +1797,40 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and +# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for +# the HTML output. The underlying search engine uses JavaScript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then +# For large projects the JavaScript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically @@ -1482,26 +1847,27 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# implemented using a web server instead of a web client using JavaScript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, Doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. SERVER_BASED_SEARCH = NO -# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# When EXTERNAL_SEARCH tag is enabled Doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1512,10 +1878,11 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1536,7 +1903,7 @@ SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = -# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through Doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of @@ -1550,11 +1917,9 @@ EXTRA_SEARCH_MAPPINGS = # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output. # The default value is: YES. -# NOTE: This is automatically YES if you generate PS or PDF output. You can -# disable it by running "configure --disable-doxygen-ps --disable-doxygen-pdf" GENERATE_LATEX = $(GENERATE_LATEX) # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a @@ -1563,34 +1928,41 @@ GENERATE_LATEX = $(GENERATE_LATEX) # The default directory is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. -# NOTE: The Makefile depends on this being 'latex'. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -# NOTE: It doesn't really matter, because the Makefile generated by Doxygen is -# not used. Explicit rules in the Automake generated Makefile handle building -# the documentation instead. LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. -# NOTE: It doesn't really matter, because the Makefile generated by Doxygen is -# not used. Explicit rules in the Automake generated Makefile handle building -# the documentation instead. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, Doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1605,43 +1977,60 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -# NOTE: You can control this using "configure DOXYGEN_PAPER_SIZE=a4" etc. PAPER_TYPE = $(PAPER_SIZE) # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank Doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that Doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of Doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank Doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that Doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by Doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or @@ -1659,59 +2048,63 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, Doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -# NOTE: You can disable this by running "configure --disable-doxygen-pdf" USE_PDFLATEX = $(GENERATE_PDF) -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BATCHMODE = NO -# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# If the LATEX_HIDE_INDICES tag is set to YES then Doxygen will not include the # index chapters (such as File Index, Compound Index, etc.) in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, Doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. -# NOTE: You can enable this by running "configure --enable-doxygen-rtf" GENERATE_RTF = $(GENERATE_RTF) # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a @@ -1720,10 +2113,9 @@ GENERATE_RTF = $(GENERATE_RTF) # The default directory is: rtf. # This tag requires that the tag GENERATE_RTF is set to YES. -# NOTE: The Makefile depends on this being 'rtf'. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, Doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1743,32 +2135,39 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to Doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the -# default style sheet that doxygen normally uses. +# default style sheet that Doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to Doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTRA_FILES = + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, Doxygen will generate man pages for # classes and files. # The default value is: NO. -# NOTE: You can enable this by running "configure --enable-doxygen-man" GENERATE_MAN = $(GENERATE_MAN) # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a @@ -1778,7 +2177,6 @@ GENERATE_MAN = $(GENERATE_MAN) # The default directory is: man. # This tag requires that the tag GENERATE_MAN is set to YES. -# NOTE: The Makefile depends on this being 'man'. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to the generated @@ -1790,7 +2188,14 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without # them the man command would be unable to find the correct page. @@ -1803,11 +2208,10 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, Doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. -# NOTE: You can enable this by running "configure --enable-doxygen-xml" GENERATE_XML = $(GENERATE_XML) # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a @@ -1816,22 +2220,9 @@ GENERATE_XML = $(GENERATE_XML) # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. -# NOTE: The Makefile depends on this being 'xml'. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, Doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1840,11 +2231,18 @@ XML_DTD = XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, Doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, Doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1862,40 +2260,63 @@ DOCBOOK_OUTPUT = docbook # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, Doxygen will generate an +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. -# NOTE: There's no support for this in the Makefile yet. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES Doxygen will generate a Sqlite3 +# database with symbols found by Doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each Doxygen run. If set to NO, Doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, Doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. # The default value is: NO. -# NOTE: There's no support for this in the Makefile yet. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, Doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -# NOTE: There's no support for this in the Makefile yet. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1915,14 +2336,14 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, Doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, Doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1938,7 +2359,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1947,7 +2368,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -1968,7 +2390,6 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -# NOTE: This allows hiding code from Doxygen using #ifndef _DOXYGEN. PREDEFINED = _DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this @@ -1980,10 +2401,10 @@ PREDEFINED = _DOXYGEN EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# If the SKIP_FUNCTION_MACROS tag is set to YES then Doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -2003,88 +2424,60 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include -# the path). If a tag file is not located in the directory in which doxygen is +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which Doxygen is # run, you must also specify the path to the tagfile here. TAGFILES = -# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# When a file name is specified after GENERATE_TAGFILE, Doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -# NOTE: The Makefile relies on this file, and it is good practice to provide it -# anyway. GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -# NOTE: Not important (since we don't PERLMOD?) -PERL_PATH = /bin/false - #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# If you set the HAVE_DOT tag to YES then Doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. -# NOTE: This is computed automatically by "configure". Use the --disable-dot -# flag if you have it but don't want to use it. HAVE_DOT = $(HAVE_DOT) -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed -# to run in parallel. When set to 0 doxygen will base this on the number of +# The DOT_NUM_THREADS specifies the number of dot invocations Doxygen is allowed +# to run in parallel. When set to 0 Doxygen will base this on the number of # processors available in the system. You can set it explicitly to a value # larger than 0 to get control over the balance between CPU load and processing # speed. @@ -2093,55 +2486,83 @@ HAVE_DOT = $(HAVE_DOT) DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# Doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then Doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# If the COLLABORATION_GRAPH tag is set to YES then Doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# If the GROUP_GRAPHS tag is set to YES then Doxygen will generate a graph for +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, Doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2158,10 +2579,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, Doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, Doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, Doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2171,67 +2614,88 @@ UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to -# YES then doxygen will generate a graph for each documented file showing the +# YES then Doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are -# set to YES then doxygen will generate a graph for each documented file showing +# set to YES then Doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# If the CALL_GRAPH tag is set to YES then Doxygen will generate a call # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALL_GRAPH = NO -# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# If the CALLER_GRAPH tag is set to YES then Doxygen will generate a caller # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALLER_GRAPH = NO -# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# If the GRAPHICAL_HIERARCHY tag is set to YES then Doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# If the DIRECTORY_GRAPH tag is set to YES then Doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2253,8 +2717,6 @@ INTERACTIVE_SVG = NO # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -# NOTE: Computed automatically by "configure". If not found, HAVE_DOT is -# automatically set to NO. DOT_PATH = $(DOT_PATH) # The DOTFILE_DIRS tag can be used to specify one or more directories that @@ -2264,16 +2726,41 @@ DOT_PATH = $(DOT_PATH) DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile +# You can include diagrams made with dia in Doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile # command). -MSCFILE_DIRS = +DIAFILE_DIRS = + +# When using PlantUML, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using PlantUML, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for PlantUML. + +PLANTUML_CFG_FILE = + +# When using PlantUML, the specified paths are searched for files specified by +# the !include statement in a PlantUML block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes -# larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# larger than this value, Doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2294,19 +2781,7 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2315,17 +2790,37 @@ DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO -# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# If the GENERATE_LEGEND tag is set to YES Doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the Doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, Doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + +# You can define message sequence charts within Doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then Doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, Doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/Makefile.am b/Makefile.am index bb1ff383..065127ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,10 +21,7 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = include src tests examples -if BUILD_PYTHON_EXT -SUBDIRS += python -endif +SUBDIRS = include src tests tools examples dist_noinst_DATA = \ COPYING.GPLv2 \ diff --git a/NEWS b/NEWS index 4aea7305..21c280a9 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ next ---- + * Remove legacy Python bindings. Use pykdumpfile instead. + +0.5.5 +----- * Incompatible API changes: - kdump_get_typed_attr(): parameters and type mismatch behaviour - kdump_attr_ref_get(): result must be discarded @@ -8,6 +12,7 @@ next * Parse QEMU CPU state ELF notes. * Use kernel page tables when initializing X86-64 Linux with PTI from CR3 register value. + * Include the kdumpid utility. * Fix direct mapping if LDT PTI remapping is used in Linux on X86-64. * Minor cache improvements and a NULL-pointer dereference fix. * Fix test suite for 32-bit architectures. diff --git a/README.md b/README.md index 90ca1733..71d5ce01 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ To compile this package, you'll need the following: * [GCC](http://gcc.gnu.org/). The source uses a few construct specific to GCC (such as variable attributes). Porting should be easy, though. +If you want to build kdumpid, you'll also need: + +* [BFD](http://www.gnu.org/software/binutils/). Any version with + disassemblers for x86, ppc and s390 will do. This usually comes with + the distro packaged as binutils-devel or similar. + To create documentation files, you'll need: * [Doxygen](http://www.doxygen.org/). Usually packaged as doxygen. @@ -50,8 +56,7 @@ To generate the `configure` script, run Python ------ -This repository contains some manually written Python bindings. These are now -deprecated in favour of a fresh rewrite using CFFI. See +There are official Python bindings for `libkdumpfile`; see [pykdumpfile](https://github.com/ptesarik/pykdumpfile). Making Releases diff --git a/configure.ac b/configure.ac index 93ebb39d..0e8a586e 100644 --- a/configure.ac +++ b/configure.ac @@ -20,10 +20,14 @@ dnl along with this program. If not, see . dnl Package release versioning m4_define([pkg_major_version], [0]) m4_define([pkg_minor_version], [5]) -m4_define([pkg_micro_version], [4]) +m4_define([pkg_micro_version], [5]) m4_define([pkg_version], [pkg_major_version.pkg_minor_version.pkg_micro_version]) +dnl FIXME: kdumpid has a different versioning scheme +m4_define([kdumpid_major_version], [1]) +m4_define([kdumpid_minor_version], [7]) + AC_INIT([libkdumpfile],[pkg_version],[petr@tesarici.cz]) AC_CONFIG_SRCDIR([src/kdumpfile/diskdump.c]) @@ -101,8 +105,10 @@ AC_ARG_ENABLE(debug, AS_IF([test "x$enable_debug" = xyes], [AC_DEFINE(ENABLE_DEBUG, 1, Define to enable extra debugging features)]) -dnl check for Python -kdump_PYTHON([2.7.0]) +dnl check whether to build optional tools +AC_SUBST(KDUMPID_VER_MAJOR, kdumpid_major_version) +AC_SUBST(KDUMPID_VER_MINOR, kdumpid_minor_version) +KDUMP_TOOL_KDUMPID AC_CONFIG_FILES([ Makefile @@ -112,8 +118,9 @@ AC_CONFIG_FILES([ src/Makefile src/addrxlat/Makefile src/kdumpfile/Makefile - python/Makefile tests/Makefile + tools/Makefile + tools/kdumpid/Makefile libaddrxlat.pc libkdumpfile.pc include/libkdumpfile/kdumpfile.h diff --git a/include/libkdumpfile/addrxlat.h.in b/include/libkdumpfile/addrxlat.h.in index b212e4fb..e4597c3f 100644 --- a/include/libkdumpfile/addrxlat.h.in +++ b/include/libkdumpfile/addrxlat.h.in @@ -134,7 +134,7 @@ typedef uint_fast64_t addrxlat_pte_t; #define ADDRXLAT_PRIuPTE PRIuFAST64 /**< Decimal PTE */ #define ADDRXLAT_PRIxPTE PRIxFAST64 /**< Lowercase hex PTE */ #define ADDRXLAT_PRIXPTE PRIXFAST64 /**< Uppercase hex PTE */ -/* @} */ +/** @} */ /** Address spaces * diff --git a/include/libkdumpfile/kdumpfile.h.in b/include/libkdumpfile/kdumpfile.h.in index 66064b00..4af3c0d5 100644 --- a/include/libkdumpfile/kdumpfile.h.in +++ b/include/libkdumpfile/kdumpfile.h.in @@ -80,7 +80,7 @@ typedef uint_fast64_t kdump_num_t; #define KDUMP_PRIuNUM PRIuFAST64 /**< Decimal @c kdump_num_t */ #define KDUMP_PRIxNUM PRIxFAST64 /**< Lowercase hex @c kdump_num_t */ #define KDUMP_PRIXNUM PRIXFAST64 /**< Uppercase hex @c kdump_num_t */ -/* @} */ +/** @} */ /** Type of a physical or virtual address. * @@ -118,7 +118,7 @@ typedef kdump_addr_t kdump_vaddr_t; #define KDUMP_PRIuADDR ADDRXLAT_PRIuADDR /**< Decimal address */ #define KDUMP_PRIxADDR ADDRXLAT_PRIxADDR /**< Lowercase hex address */ #define KDUMP_PRIXADDR ADDRXLAT_PRIXADDR /**< Uppercase hex address */ -/* @} */ +/** @} */ /** Representation of a dump file. * @@ -217,7 +217,7 @@ enum kdump_clone_bits { */ /** Do not share address translation. */ #define KDUMP_CLONE_XLAT (1UL << KDUMP_CLONE_BIT_XLAT) -/* @} */ +/** @} */ /** Clone a dump file object. * @param orig Original dump file object. @@ -1034,7 +1034,7 @@ void kdump_attr_iter_end(kdump_ctx_t *ctx, kdump_attr_iter_t *iter); #define KDUMP_ARCH_S390 "s390" /**< IBM z/Architecture, 31-bit */ #define KDUMP_ARCH_S390X "s390x" /**< IBM z/Architecture, 64-bit */ #define KDUMP_ARCH_X86_64 "x86_64" /**< AMD64, Intel 64 */ -/* @} */ +/** @} */ /** Byte order attribute. * @sa kdump_byte_order_t diff --git a/m4/python.m4 b/m4/python.m4 deleted file mode 100644 index a4db116a..00000000 --- a/m4/python.m4 +++ /dev/null @@ -1,42 +0,0 @@ -AC_DEFUN([kdump_PYTHON],[dnl check for Python support -AC_ARG_WITH(python,[dnl - AS_HELP_STRING([--with-python], - [build Python bindings @<:@default=check@:>@])], - [],[withval=check]) -have_python=no -AS_IF([test "x$withval" != xno],[dnl - case "$withval" in - yes|check) - ;; - *) - AS_IF([test -x "$withval"],[PYTHON="$withval"],[dnl - AC_PATH_PROG(PYTHON,"$withval") - AS_IF([test -z "$PYTHON"],[dnl - AC_MSG_ERROR([Requested Python interpreter ($withval) not found]) - ]) - ]) - ;; - esac - AM_PATH_PYTHON([$1],[have_python=yes],[:]) -]) -AS_IF([test "$have_python" = yes],[dnl - PYTHON_CONFIG="$PYTHON-config" - AS_IF([test -x "$PYTHON_CONFIG"],[],[dnl - AC_PATH_PROG(PYTHON_CONFIG,"$PYTHON-config") - ]) - AS_IF([test -x "$PYTHON_CONFIG"],[dnl - PYTHON_CFLAGS=`$PYTHON_CONFIG --cflags` - PYTHON_LIBS=`$PYTHON_CONFIG --libs` - AC_SUBST(PYTHON_CFLAGS) - AC_SUBST(PYTHON_LIBS) - ],[dnl - AC_MSG_ERROR([Python found as $PYTHON, but there is no $PYTHON_CONFIG]) - have_python=no - ]) -],[dnl - AS_IF([test "x$with_python" = xyes],[dnl - AC_MSG_ERROR([Python support requested but not found]) - ]) -]) -AM_CONDITIONAL(BUILD_PYTHON_EXT, test "x$have_python" = xyes) -]) diff --git a/m4/tools.m4 b/m4/tools.m4 new file mode 100644 index 00000000..35e82e4b --- /dev/null +++ b/m4/tools.m4 @@ -0,0 +1,100 @@ +# KDUMP_TRY_LINK(LIBRARIES) +# --------------------------------------------------------- +# Try to link the existing test source file with additional +# libraries. +# Set kdump_res to "yes" on success, else set it to "no". +# Standard error output is saved to conftest.linkerr. +AC_DEFUN([KDUMP_TRY_LINK],[dnl +kdump_save_LIBS="$LIBS" +kdump_save_ac_link="$ac_link" +LIBS="$1 $LIBS" +ac_link="$ac_link 2>conftest.linkerr" +AC_LINK_IFELSE([], kdump_res=yes, [kdump_res=no + $2]) +LIBS="$kdump_save_LIBS" +ac_link="$kdump_save_ac_link" +])# KDUMP_TRY_LINK + +AC_DEFUN([KDUMP_REPORT_LINKERR],[dnl +AS_ECHO("$as_me:$LINENO: all linker errors") >&AS_MESSAGE_LOG_FD +cat conftest.linkerr >&AS_MESSAGE_LOG_FD +])# KDUMP_REPORT_LINKERR + +AC_DEFUN([KDUMP_TRY_LINK_UNDEF],[dnl +kdump_save_LDFLAGS="$LDFLAGS" +LDFLAGS="-z undefs $2 $LDFLAGS" +KDUMP_TRY_LINK($1, KDUMP_REPORT_LINKERR) +LDFLAGS="$kdump_save_LDFLAGS" +])# KDUMP_TRY_LINK_UNDEF + +AC_DEFUN([KDUMP_DIS_ASM_CHECK_UNDEF],[dnl +AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([whether disassembler requires $1]) +KDUMP_TRY_LINK($DIS_ASM_LIBS) +AS_ECHO("$as_me:$LINENO: matching linker errors") >&AS_MESSAGE_LOG_FD +AS_IF([$EGREP "@<:@^A-Za-z0-9_@:>@($2)" conftest.linkerr >&AS_MESSAGE_LOG_FD], + [AC_MSG_RESULT(yes) + DIS_ASM_LIBS="$DIS_ASM_LIBS $1" + KDUMP_TRY_LINK_UNDEF($DIS_ASM_LIBS) + AS_IF([test yes != "$kdump_res"], + [AC_MSG_FAILURE([Link fails with $1])])], + [AC_MSG_RESULT(no)])dnl +])# KDUMP_DIS_ASM_CHECK_UNDEF + +AC_DEFUN([KDUMP_DIS_ASM_LIBS],[dnl determine disassembler libraries +DIS_ASM_LIBS=-lopcodes +AC_LANG_CONFTEST([AC_LANG_PROGRAM( + [#include ], + [disassembler(bfd_arch_i386, FALSE, bfd_mach_x86_64, NULL);])]) +dnl ignore undefined symbols from missing linker dependencies +AC_MSG_CHECKING([for disassembler in $DIS_ASM_LIBS]) +KDUMP_TRY_LINK_UNDEF($DIS_ASM_LIBS, [-Wl,--require-defined=disassembler]) +AC_MSG_RESULT($kdump_res) +AS_IF([test yes = "$kdump_res"], [dnl + KDUMP_DIS_ASM_CHECK_UNDEF(-lbfd, bfd_) + KDUMP_DIS_ASM_CHECK_UNDEF(-lsframe, sframe_) + KDUMP_DIS_ASM_CHECK_UNDEF(-liberty, htab_create|splay_tree_new) + KDUMP_DIS_ASM_CHECK_UNDEF(-lz, inflate) + KDUMP_DIS_ASM_CHECK_UNDEF(-lzstd, ZSTD_) + KDUMP_DIS_ASM_CHECK_UNDEF(-ldl, dlopen) + AS_IF([test yes != "$kdump_res"], + [KDUMP_REPORT_LINKERR] + [AC_MSG_FAILURE([Tried everything, still cannot link disassembler.])]) + AC_SUBST(DIS_ASM_LIBS) +])dnl +])# KDUMP_DIS_ASM_LIBS + +AC_DEFUN([KDUMP_DIS_ASM],[dnl determine disassembler options +AC_CHECK_HEADERS(dis-asm.h, [], + [AC_MSG_ERROR([Disassembler headers not found])]) +AC_MSG_CHECKING([whether disassembler supports syntax highlighting]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#include +void fn(struct disassemble_info *info, void *stream, + fprintf_ftype fprintf_func, fprintf_styled_ftype fprintf_styled_func) +{ + init_disassemble_info(info, stream, fprintf_func, fprintf_styled_func); +} +])], + [dnl +AC_MSG_RESULT(yes) +AC_DEFINE(DIS_ASM_STYLED_PRINTF, [1], + [Define if init_disassemble_info() has a printf_styled_func parameter])], + [AC_MSG_RESULT(no)]) +KDUMP_DIS_ASM_LIBS +])# KDUMP_DIS_ASM + +AC_DEFUN([KDUMP_TOOL_KDUMPID],[dnl enable/disable kdumpid build +AC_ARG_ENABLE(kdumpid, + [AS_HELP_STRING(--disable-kdumpid, + [do not build kdumpid])], + [], + [enable_kdumpid=yes]) +AS_IF([test no != "$enable_kdumpid"], [dnl + KDUMP_DIS_ASM + AS_IF([test yes != "$kdump_res"], + [AC_MSG_FAILURE( + [disassembler test failed (--disable-kdumpid to disable)])] + )]) +AM_CONDITIONAL(BUILD_KDUMPID, [test yes = "$enable_kdumpid"]) +])# KDUMP_TOOL_KDUMPID diff --git a/python/.gitignore b/python/.gitignore deleted file mode 100644 index 29fb1699..00000000 --- a/python/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# generated by Makefile -setup.cfg - -# distutils build -build - -# Test results -*.log -*.trs diff --git a/python/Makefile.am b/python/Makefile.am deleted file mode 100644 index ecc7a89b..00000000 --- a/python/Makefile.am +++ /dev/null @@ -1,106 +0,0 @@ -## Process this file with automake to create Makefile.in -## Configure input file for libkdumpfile. -## -## Copyright (C) 2015 Ales Novak -## -## This file is part of libkdumpfile. -## -## This file 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 3 of the License, or -## (at your option) any later version. -## -## libkdumpfile 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, see . -## - -AM_CPPFLAGS = -I$(top_builddir)/include -AM_CFLAGS = $(PYTHON_CFLAGS) -AM_LDFLAGS = -module -avoid-version - -installed_list = installed.list - -setup.cfg: Makefile - $(AM_V_GEN) - $(AM_V_at)echo "[kdumpfile]" > $@ - $(AM_V_at)echo "version=$(VERSION)" >> $@ - $(AM_V_at)echo "srcdir=$(srcdir)" >> $@ - $(AM_V_at)echo "top_builddir=$(top_builddir)" >> $@ - $(AM_V_at)echo >> $@ - $(AM_V_at)echo "[build_ext]" >> $@ - $(AM_V_at)echo "libtool=$(LIBTOOL)" >> $@ - $(AM_V_at)echo "pyexecdir=$(pyexecdir)" >> $@ - $(AM_V_at)echo >> $@ - $(AM_V_at)echo "[install_lib]" >> $@ - $(AM_V_at)echo "libtool_install=$(LIBTOOL) --mode=install $(INSTALL)" >> $@ - -all-local: setup.cfg - $(PYTHON) $(srcdir)/setup.py build - -install-exec-local: setup.cfg - $(PYTHON) $(srcdir)/setup.py install \ - --root "$(DESTDIR)"/ \ - --install-purelib $(pythondir) \ - --install-platlib $(pyexecdir) \ - --record $(installed_list) - -uninstall-local: $(installed_list) - while read f ; do \ - $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)/$$f" ; \ - done < $< - -mostlyclean-local: setup.cfg - $(PYTHON) $(srcdir)/setup.py clean --all - rm $< - -CLEANFILES = $(installed_list) - -check_LTLIBRARIES = _test_addrxlat.la - -_test_addrxlat_la_SOURCES = test_addrxlat.c -_test_addrxlat_la_LDFLAGS = \ - $(AM_LDFLAGS) \ - -export-symbols $(srcdir)/test_addrxlat.sym \ - -rpath $(abs_builddir) -_test_addrxlat_la_LIBADD = $(PYTHON_LIBS) $(top_builddir)/src/addrxlat/libaddrxlat.la -EXTRA__test_addrxlat_la_DEPENDENCIES = test_addrxlat.sym - -dist_noinst_SCRIPTS = \ - setup.py \ - disthelpers.py \ - libtoolize.py \ - addrxlat/__init__.py \ - addrxlat/exceptions.py \ - kdumpfile/__init__.py \ - kdumpfile/exceptions.py \ - kdumpfile/views.py \ - showxlat.py \ - vtop.py - -dist_noinst_DATA = \ - addrxlat.c \ - kdumpfile.c \ - test_addrxlat.sym - -noinst_HEADERS = \ - addrxlatmod.h - -test_scripts = \ - test_addrxlat.py - -dist_check_SCRIPTS = \ - $(test_scripts) - -TESTS = $(test_scripts) - -LOG_COMPILER = $(PYTHON) - -AM_TESTS_ENVIRONMENT = \ -eval " $$($(LIBTOOL) --config)"; \ -platlib=$$($(PYTHON) $(srcdir)/setup.py -q get_build_platlib); \ -PYTHONPATH="$$srcdir:$$objdir:$$platlib/$$objdir" diff --git a/python/addrxlat.c b/python/addrxlat.c deleted file mode 100644 index 4e6c15ee..00000000 --- a/python/addrxlat.c +++ /dev/null @@ -1,6161 +0,0 @@ -/** @internal @file python/addrxlat.c - * @brief Python bindings for libaddrxlat. - */ -/* Copyright (C) 2014 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. - - libkdumpfile 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 . -*/ - -#include -#include -#include -#include -#include -#include "addrxlatmod.h" - -#if PY_MAJOR_VERSION >= 3 -#define PyInt_FromLong(x) PyLong_FromLong(x) -#define PyInt_FromSize_t(x) PyLong_FromSize_t(x) - -#define Text_FromUTF8(x) PyUnicode_FromString(x) -#define Text_AsUTF8(x) PyUnicode_AsUTF8(x) -#else -#define Text_FromUTF8(x) PyString_FromString(x) -#define Text_AsUTF8(x) PyString_AsString(x) -#endif - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#define MOD_NAME "_addrxlat" -#define MOD_DOC "low-level interface to libaddrxlat" - -/** Python exception status code. - * This code is returned when a callback raises an exception, so - * it can be passed correctly up the chain. - */ -#define STATUS_PYEXC ADDRXLAT_ERR_CUSTOM_BASE - -static PyObject *ctx_status_result(PyObject *_self, addrxlat_status status); -static PyObject *make_meth_param(PyObject *meth); - -/** Default type converter object. */ -static PyObject *convert; - -/* Conversion functions */ -static PyObject *fulladdr_FromPointer( - PyObject *_conv, const addrxlat_fulladdr_t *faddr); -static addrxlat_fulladdr_t *fulladdr_AsPointer(PyObject *self); -static PyObject *ctx_FromPointer(PyObject *_conv, addrxlat_ctx_t *ctx); -static addrxlat_ctx_t *ctx_AsPointer(PyObject *self); -static PyObject *meth_FromPointer( - PyObject *_conv, const addrxlat_meth_t *meth); -static addrxlat_meth_t *meth_AsPointer(PyObject *self); -static PyObject *range_FromPointer( - PyObject *_conv, const addrxlat_range_t *range); -static addrxlat_range_t *range_AsPointer(PyObject *self); -static PyObject *map_FromPointer(PyObject *_conv, addrxlat_map_t *map); -static addrxlat_map_t *map_AsPointer(PyObject *self); -static PyObject *sys_FromPointer(PyObject *_conv, addrxlat_sys_t *sys); -static addrxlat_sys_t *sys_AsPointer(PyObject *self); -static PyObject *step_FromPointer( - PyObject *_conv, const addrxlat_step_t *step); -static int step_Init(PyObject *self, const addrxlat_step_t *step); -static addrxlat_step_t *step_AsPointer(PyObject *self); -static PyObject *op_FromPointer( - PyObject *conv, const addrxlat_op_ctl_t *opctl); -static int op_Init(PyObject *self, const addrxlat_op_ctl_t *opctl); -static addrxlat_op_ctl_t *op_AsPointer(PyObject *self); - -/** Capsule data. */ -static struct addrxlat_CAPI CAPI; - -/** Documentation for the convert attribute (multiple types). */ -PyDoc_STRVAR(attr_convert__doc__, -"C type converter"); - -/** Convert a PyLong or PyInt to a C long. - * @param num a @c PyLong or @c PyInt object - * @returns numeric value of @c num or -1 - * - * Since all possible return values error are valid, error conditions - * must be detected by calling @c PyErr_Occurred. - */ -static long -Number_AsLong(PyObject *num) -{ - long result; - - if (PyLong_Check(num)) - return PyLong_AsLong(num); -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(num)) - return PyInt_AsLong(num); -#endif - - num = PyNumber_Long(num); - if (!num) - return -1L; - result = PyLong_AsLong(num); - Py_DECREF(num); - return result; -} - -/** Convert a PyLong or PyInt to a C unsigned long long. - * @param num a @c PyLong or @c PyInt object - * @returns numeric value of @c num or -1 - * - * Since all possible return values error are valid, error conditions - * must be detected by calling @c PyErr_Occurred. - */ -static unsigned long long -Number_AsUnsignedLongLong(PyObject *num) -{ - unsigned long long result; - - if (PyLong_Check(num)) - return PyLong_AsUnsignedLongLong(num); -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(num)) - return PyInt_AsLong(num); -#endif - - num = PyNumber_Long(num); - if (!num) - return -1LL; - result = PyLong_AsUnsignedLongLong(num); - Py_DECREF(num); - return result; -} - -/** Convert a PyLong or PyInt to a C unsigned long long with no overflow. - * @param num a @c PyLong or @c PyInt object - * @returns numeric value of @c num or -1 - * - * Since all possible return values error are valid, error conditions - * must be detected by calling @c PyErr_Occurred. - */ -static unsigned long long -Number_AsUnsignedLongLongMask(PyObject *num) -{ - unsigned long long result; - - if (PyLong_Check(num)) - return PyLong_AsUnsignedLongLongMask(num); -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check(num)) - return PyInt_AsLong(num); -#endif - - num = PyNumber_Long(num); - if (!num) - return -1LL; - result = PyLong_AsUnsignedLongLongMask(num); - Py_DECREF(num); - return result; -} - -/** Convert a Python sequence of integers to a memory buffer. - * @param seq a Python sequence - * @param buffer buffer for the result - * @param buflen maximum buffer length - * @returns zero on success, -1 otherwise - */ -static int -ByteSequence_AsBuffer(PyObject *seq, void *buffer, size_t buflen) -{ - Py_ssize_t i, len; - - if (!PySequence_Check(seq)) { - PyErr_SetString(PyExc_TypeError, - "'%.200s' object is not a sequence"); - return -1; - } - - len = PySequence_Length(seq); - if (len > buflen) { - PyErr_Format(PyExc_ValueError, - "sequence bigger than %zd bytes", buflen); - return -1; - } - - if (PyByteArray_Check(seq)) { - memcpy(buffer, PyByteArray_AsString(seq), len); - return 0; - } - - for (i = 0; i < len; ++i) { - long byte = 0; - PyObject *obj = PySequence_GetItem(seq, i); - - if (seq) { - byte = Number_AsLong(obj); - Py_DECREF(obj); - } - if (PyErr_Occurred()) - return -1; - if (byte < 0 || byte > 0xff) { - PyErr_SetString(PyExc_OverflowError, - "byte value out of range"); - return -1; - } - ((char*)buffer)[i] = byte; - } - - return 0; -} - -/** Check whether an attribute is being deleted. - * @param obj new value - * @param name name of the attribute (used in the exception message) - * @returns zero if attribute is not NULL, -1 otherwise - */ -static int -check_null_attr(PyObject *obj, const char *name) -{ - if (obj) - return 0; - - PyErr_Format(PyExc_TypeError, - "'%s' attribute cannot be deleted", name); - return -1; -} - -/** Fetch positional and keyword arguments. - * @param kwds NULL-terminated array of recognized keywords - * @param min minimum required number of arguments - * @param pargs positional arguments - * @param pkwargs keyword arguments - * @returns zero on success, -1 otherwise - * - * Fetch all arguments listed in @c kwds and put them into variables - * passed as variadic. The variables referenced by @c pargs and - * @c pkwargs are updated to hold a tuple and dictionary with unprocessed - * arguments. - * - * On failure, the variables referenced by @c pargs and @c pkwargs are not - * touched, but the values of argument variables (variadic) are undefined. - */ -static int -fetch_args(const char *kwds[], Py_ssize_t min, - PyObject **pargs, PyObject **pkwargs, ...) -{ - const char **kw; - PyObject *args, *kwargs; - PyObject **argvar; - Py_ssize_t argc, n; - va_list ap; - - args = *pargs; - if (*pkwargs) { - kwargs = PyDict_Copy(*pkwargs); - if (!kwargs) - return -1; - } else - kwargs = NULL; - - va_start(ap, pkwargs); - argc = PyTuple_GET_SIZE(args); - for (n = 0, kw = kwds; n < argc; ++n, ++kw) { - if (!*kw) - break; - argvar = va_arg(ap, PyObject **); - *argvar = PyTuple_GET_ITEM(args, n); - } - min -= n; - - if (kwargs) { - const char **kw2; - for (kw2 = kwds; kw2 < kw; ++kw2) { - if (PyDict_GetItemString(kwargs, *kw2)) { - /* arg present in tuple and in dict */ - PyErr_Format(PyExc_TypeError, - "Argument given by name ('%s') " - "and position (%zd)", - *kw2, kw2 - kwds); - goto err; - } - PyErr_Clear(); - } - } - - for ( ; *kw; ++kw, --min) { - argvar = va_arg(ap, PyObject **); - if (kwargs) { - *argvar = PyDict_GetItemString(kwargs, *kw); - if (*argvar) - PyDict_DelItemString(kwargs, *kw); - } else - *argvar = NULL; - - if (!*argvar && min > 0) { - PyErr_Format(PyExc_TypeError, - "Required argument '%s' missing", *kw); - goto err; - } - } - va_end(ap); - - args = PyTuple_GetSlice(args, n, argc); - if (!args) - goto err; - - *pargs = args; - *pkwargs = kwargs; - return 0; - -err: - Py_XDECREF(kwargs); - va_end(ap); - return -1; -} - -/** Call a method by name - * @param obj object - * @param name method name - * @param args positional arguments - * @param kwargs keyword arguments - * @returns method return value, or @c NULL on failure - */ -static PyObject * -call_method(PyObject *obj, const char *name, PyObject *args, PyObject *kwargs) -{ - PyObject *func; - PyObject *result; - - func = PyObject_GetAttrString(obj, name); - if (!func) - return NULL; - - result = PyObject_Call(func, args, kwargs); - Py_DECREF(func); - return result; -} - -/** Copy the value of an attribute to another attribute of the same object. - * @param obj Python object - * @param srcname Name of the source attribute. - * @param dstname Name of the destination attribute. - * @returns Zero on success, -1 on failure. - */ -static int -copy_attr(PyObject *obj, const char *srcname, const char *dstname) -{ - PyObject *attr; - int result; - - attr = PyObject_GetAttrString(obj, srcname); - if (!attr) - return 0; - - result = PyObject_SetAttrString(obj, dstname, attr); - Py_DECREF(attr); - return result; -} - -/** Call a cooperative superclass method - * @param type derived class type - * @param obj object - * @param name method name - * @param args positional arguments - * @param kwargs keyword arguments - * @returns method return value, or @c NULL on failure - */ -static PyObject * -call_super(PyTypeObject *type, PyObject *obj, - const char *name, PyObject *args, PyObject *kwargs) -{ - PyObject *super; - PyObject *result; - - super = PyObject_CallFunction((PyObject*)&PySuper_Type, - "(OO)", type, obj); - if (!super) - return NULL; - - result = call_method(super, name, args, kwargs); - Py_DECREF(super); - return result; -} - -/** Offset of a type member as a void pointer. */ -#define OFFSETOF_PTR(type, member) ((void*)&(((type*)0)->member)) - -/** Getter for a Python object. - * @param self any object - * @param data offset of the meth member - * @returns referenced PyObject - */ -static PyObject * -get_object(PyObject *self, void *data) -{ - Py_ssize_t off = (intptr_t)data; - PyObject **pobj = (PyObject**)((char*)self + off); - - if (!*pobj) - Py_RETURN_NONE; - - Py_INCREF(*pobj); - return *pobj; -} - -/** Getter for the addrxlat_addr_t type. - * @param self any object - * @param data offset of the addrxlat_addr_t member - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -get_addr(PyObject *self, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_addr_t *paddr = (addrxlat_addr_t*)((char*)self + off); - return PyLong_FromUnsignedLongLong(*paddr); -} - -/** Setter for the addrxlat_addr_t type. - * @param self any object - * @param value new value (a @c PyLong or @c PyInt) - * @param data offset of the addrxlat_addr_t member - * @returns zero on success, -1 otherwise - */ -static int -set_addr(PyObject *self, PyObject *value, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_addr_t *paddr = (addrxlat_addr_t*)((char*)self + off); - unsigned long long addr = Number_AsUnsignedLongLong(value); - - if (PyErr_Occurred()) - return -1; - - *paddr = addr; - return 0; -} - -/** Getter for the addrxlat_off_t type. - * @param self any object - * @param data offset of the addrxlat_off_t member - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -get_off(PyObject *self, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_off_t *paddr = (addrxlat_off_t*)((char*)self + off); - return PyLong_FromUnsignedLongLong(*paddr); -} - -/** Setter for the addrxlat_off_t type. - * @param self any object - * @param value new value (a @c PyLong or @c PyInt) - * @param data offset of the addrxlat_off_t member - * @returns zero on success, -1 otherwise - */ -static int -set_off(PyObject *self, PyObject *value, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_off_t *paddr = (addrxlat_off_t*)((char*)self + off); - unsigned long long addr = Number_AsUnsignedLongLongMask(value); - - if (PyErr_Occurred()) - return -1; - - *paddr = addr; - return 0; -} - -/** Getter for the addrxlat_addrspace_t type. - * @param self any object - * @param data offset of the addrxlat_addrspace_t member - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -get_addrspace(PyObject *self, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_addrspace_t *paddrspace = - (addrxlat_addrspace_t*)((char*)self + off); - return PyInt_FromLong(*paddrspace); -} - -/** Setter for the addrxlat_addr_t type. - * @param self any object - * @param value new value (a @c PyLong or @c PyInt) - * @param data offset of the addrxlat_addrspace_t member - * @returns zero on success, -1 otherwise - */ -static int -set_addrspace(PyObject *self, PyObject *value, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_addrspace_t *paddrspace = - (addrxlat_addrspace_t*)((char*)self + off); - long addrspace = Number_AsLong(value); - - if (PyErr_Occurred()) - return -1; - - *paddrspace = addrspace; - return 0; -} - -/** Getter for the addrxlat_pte_t type. - * @param self any object - * @param data offset of the addrxlat_pte_t member - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -get_pte(PyObject *self, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_pte_t *pval = (addrxlat_pte_t*)((char*)self + off); - return PyLong_FromUnsignedLongLong(*pval); -} - -/** Setter for the addrxlat_pte_t type. - * @param self any object - * @param value new value (a @c PyLong or @c PyInt) - * @param data offset of the addrxlat_pte_t member - * @returns zero on success, -1 otherwise - */ -static int -set_pte(PyObject *self, PyObject *value, void *data) -{ - Py_ssize_t off = (intptr_t)data; - addrxlat_pte_t *pval = (addrxlat_pte_t*)((char*)self + off); - unsigned long long pte = Number_AsUnsignedLongLongMask(value); - - if (PyErr_Occurred()) - return -1; - - *pval = pte; - return 0; -} - -/** An object with a C pointer. - * This object is used to create a Python object from a C pointer to - * the corresponding libaddrxlat object passed as a _C_POINTER argument. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - /** Pointer to the C structure. */ - void *ptr; -} c_pointer_object; - -PyDoc_STRVAR(c_pointer__doc__, -"Internal-only type for creating Python objects from C pointers."); - -static PyTypeObject c_pointer_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".c-pointer", /* tp_name */ - sizeof (c_pointer_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - c_pointer__doc__, /* tp_doc */ -}; - -/** Create a c-pointer object with a given pointer value. - * @param ptr C pointer to an object - * @returns Python object, or @c NULL on error - * - * This function returns @c NULL on error, or if the argument is not - * found. To distinguish between these two cases, the caller should - * use @c PyErr_Occurred(). - */ -static PyObject * -make_c_pointer(void *ptr) -{ - PyTypeObject *type = &c_pointer_type; - PyObject *result; - - result = type->tp_alloc(type, 0); - if (result) - ((c_pointer_object*)result)->ptr = ptr; - return result; -} - -/** Name of the C pointer parameter. - * Use this variable instead of a literal string to prevent typos. - */ -static const char _C_POINTER[] = "_C_POINTER"; - -/** Create keyword args with a _C_POINTER value. - * @param ptr C pointer - * @returns Python dictionary to be used as kwargs - */ -static PyObject * -c_pointer_arg(void *ptr) -{ - PyObject *obj; - PyObject *result; - - result = PyDict_New(); - if (result) { - obj = make_c_pointer(ptr); - if (!obj) - goto err_dict; - if (PyDict_SetItemString(result, _C_POINTER, obj)) - goto err_obj; - } - return result; - - err_obj: - Py_DECREF(obj); - err_dict: - Py_DECREF(result); - return NULL; -} - -/** Get the _C_POINTER from keyword arguments (with type check). - * @param kwargs keyword arguments - * @returns C pointer, or @c NULL - * - * This function returns @c NULL on error, or if the argument is not - * found. To distinguish between these two cases, the caller should - * use @c PyErr_Occurred(). - */ -static void * -get_c_pointer(PyObject *kwargs) -{ - PyObject *obj; - - if (!kwargs) - return NULL; - - obj = PyDict_GetItemString(kwargs, _C_POINTER); - if (!obj) - return NULL; - - if (!PyObject_TypeCheck(obj, &c_pointer_type)) { - PyErr_Format(PyExc_TypeError, - "need a c-pointer, not '%.200s'", - Py_TYPE(obj)->tp_name); - return NULL; - } - - return ((c_pointer_object*)obj)->ptr; -} - -/** Call superclass init, removing a C-pointer from args. - * @param type derived class type - * @param self calling object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns zero on success, -1 on failure - */ -static int -c_pointer_super_init(PyTypeObject *type, PyObject *self, - PyObject *args, PyObject *kwargs) -{ - PyObject *result; - - if (kwargs) { - kwargs = PyDict_Copy(kwargs); - if (!kwargs) - return -1; - - if (PyDict_DelItemString(kwargs, _C_POINTER)) - PyErr_Clear(); - } - - result = call_super(type, self, "__init__", args, kwargs); - Py_XDECREF(kwargs); - if (!result) - return -1; - - if (result != Py_None) { - PyErr_Format(PyExc_TypeError, - "__init__() should return None, not '%.200s'", - Py_TYPE(result)->tp_name); - Py_DECREF(result); - return -1; - } - - Py_DECREF(result); - return 0; -} - -/** Create a new Python object from a C pointer. - * @param type type of object - * @param ptr C pointer used for initialization - * @returns new Python object, or @c NULL on failure - */ -static PyObject * -object_FromPointer(PyTypeObject *type, void *ptr) -{ - PyObject *args, *kwargs; - PyObject *result; - - args = PyTuple_New(0); - if (!args) - return NULL; - - kwargs = c_pointer_arg(ptr); - if (!kwargs) { - Py_DECREF(args); - return NULL; - } - - result = PyObject_Call((PyObject*)type, args, kwargs); - Py_DECREF(kwargs); - Py_DECREF(args); - return result; -} - -static PyObject *BaseException; - -PyDoc_STRVAR(BaseException__doc__, -"Common base for all addrxlat exceptions.\n\ -\n\ -Attributes:\n\ - status addrxlat status code, see ERR_xxx\n\ - message verbose error message"); - -PyDoc_STRVAR(BaseException_init__doc__, -"__init__(status[, message])\n\ -\n\ -Initialize status code and error message. If message is not specified,\n\ -use addrxlat_strerror(status)."); - -static PyObject * -BaseException_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"status", "message", NULL}; - PyTypeObject *basetype = ((PyTypeObject*)BaseException)->tp_base; - PyObject *statobj, *msgobj; - addrxlat_status status; - int result; - - msgobj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:BaseException", - keywords, &statobj, &msgobj)) - return NULL; - - args = msgobj - ? Py_BuildValue("(OO)", statobj, msgobj) - : Py_BuildValue("(O)", statobj); - if (!args) - return NULL; - result = basetype->tp_init(self, args, NULL); - Py_DECREF(args); - if (result) - return NULL; - - status = Number_AsLong(statobj); - if (PyErr_Occurred()) - return NULL; - - if (PyObject_SetAttrString(self, "status", statobj)) - return NULL; - if (msgobj) { - if (PyObject_SetAttrString(self, "message", msgobj)) - return NULL; - Py_RETURN_NONE; - } - - msgobj = Text_FromUTF8(addrxlat_strerror(status)); - if (!msgobj) - return NULL; - result = PyObject_SetAttrString(self, "message", msgobj); - Py_DECREF(msgobj); - if (result) - return NULL; - - Py_RETURN_NONE; -} - -static PyMethodDef BaseException_init_method = { - "__init__", (PyCFunction)BaseException_init, - METH_VARARGS | METH_KEYWORDS, - BaseException_init__doc__ -}; - -static PyObject * -make_BaseException(PyObject *mod) -{ - PyObject *descr; - PyObject *result; - - result = PyErr_NewExceptionWithDoc(MOD_NAME ".BaseException", - BaseException__doc__, NULL, NULL); - if (!result) - return result; - - descr = PyDescr_NewMethod((PyTypeObject*)result, - &BaseException_init_method); - if (!descr) - goto err; - if (PyObject_SetAttrString(result, "__init__", descr)) - goto err; - Py_DECREF(descr); - - return result; - - err: - Py_DECREF(result); - return NULL; -} - -/** Raise an _addrxlat.BaseException. - * @param ctx Address translation context - * @param status Status code (see @c ADDRXLAT_ERR_xxx) - * - * Use the provided context object to construct the arguments of - * an addrxlat exception. - */ -static PyObject * -raise_exception(addrxlat_ctx_t *ctx, addrxlat_status status) -{ - const char *err = ctx - ? addrxlat_ctx_get_err(ctx) - : NULL; - PyObject *exc_val = err - ? Py_BuildValue("(is)", (int)status, err) - : Py_BuildValue("(i)", (int)status); - if (exc_val) { - PyErr_SetObject(BaseException, exc_val); - Py_DECREF(exc_val); - if (ctx) - addrxlat_ctx_clear_err(ctx); - } - return NULL; -} - -/** Raise an NotImplemented exception. - * @param msg Verbose message - * @returns Always @c NULL - */ -static PyObject * -raise_notimpl(const char *msg) -{ - PyObject *exc_val; - - exc_val= Py_BuildValue("(is)", (int)ADDRXLAT_ERR_NOTIMPL, msg); - if (exc_val) { - PyErr_SetObject(BaseException, exc_val); - Py_DECREF(exc_val); - } - return NULL; -} - -/** Converter between C types and Python types. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - - /** Target type for FullAddress conversions. */ - PyTypeObject *fulladdr_type; - /** Target type for Context conversions. */ - PyTypeObject *ctx_type; - /** Target type for Method conversions. */ - PyTypeObject *meth_type; - /** Target type for CustomMethod conversions. */ - PyTypeObject *custommeth_type; - /** Target type for LinearMethod conversions. */ - PyTypeObject *linearmeth_type; - /** Target type for PageTableMethod conversions. */ - PyTypeObject *pgtmeth_type; - /** Target type for LookupMethod conversions. */ - PyTypeObject *lookupmeth_type; - /** Target type for MemoryArrayMethod conversions. */ - PyTypeObject *memarrmeth_type; - /** Target type for Range conversions. */ - PyTypeObject *range_type; - /** Target type for Map conversions. */ - PyTypeObject *map_type; - /** Target type for System conversions. */ - PyTypeObject *sys_type; - /** Target type for Step conversions. */ - PyTypeObject *step_type; - /** Target type for Operator conversions. */ - PyTypeObject *op_type; -} convert_object; - -static PyTypeObject fulladdr_type; -static PyTypeObject ctx_type; -static PyTypeObject meth_type; -static PyTypeObject custommeth_type; -static PyTypeObject linearmeth_type; -static PyTypeObject pgtmeth_type; -static PyTypeObject lookupmeth_type; -static PyTypeObject memarrmeth_type; -static PyTypeObject range_type; -static PyTypeObject map_type; -static PyTypeObject sys_type; -static PyTypeObject step_type; -static PyTypeObject op_type; - -PyDoc_STRVAR(convert__doc__, -"Converter type between C pointer types and Python types"); - -/** Create a new convert object. - * @param type convert type - * @param args ignored - * @param kwargs ignored - * @returns new convert object, or @c NULL on failure - */ -static PyObject * -convert_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - convert_object *self; - - self = (convert_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - self->fulladdr_type = &fulladdr_type; - Py_INCREF(self->fulladdr_type); - self->ctx_type = &ctx_type; - Py_INCREF(self->ctx_type); - self->meth_type = &meth_type; - Py_INCREF(self->meth_type); - self->custommeth_type = &custommeth_type; - Py_INCREF(self->custommeth_type); - self->linearmeth_type = &linearmeth_type; - Py_INCREF(self->linearmeth_type); - self->pgtmeth_type = &pgtmeth_type; - Py_INCREF(self->pgtmeth_type); - self->lookupmeth_type = &lookupmeth_type; - Py_INCREF(self->lookupmeth_type); - self->memarrmeth_type = &memarrmeth_type; - Py_INCREF(self->memarrmeth_type); - self->range_type = &range_type; - Py_INCREF(self->range_type); - self->map_type = &map_type; - Py_INCREF(self->map_type); - self->sys_type = &sys_type; - Py_INCREF(self->sys_type); - self->step_type = &step_type; - Py_INCREF(self->step_type); - self->op_type = &op_type; - Py_INCREF(self->op_type); - - return (PyObject*)self; -} - -static void -convert_dealloc(PyObject *_self) -{ - convert_object *self = (convert_object *)_self; - - PyObject_GC_UnTrack(_self); - - Py_XDECREF(self->fulladdr_type); - Py_XDECREF(self->ctx_type); - Py_XDECREF(self->meth_type); - Py_XDECREF(self->custommeth_type); - Py_XDECREF(self->linearmeth_type); - Py_XDECREF(self->pgtmeth_type); - Py_XDECREF(self->lookupmeth_type); - Py_XDECREF(self->memarrmeth_type); - Py_XDECREF(self->range_type); - Py_XDECREF(self->map_type); - Py_XDECREF(self->sys_type); - Py_XDECREF(self->step_type); - Py_XDECREF(self->op_type); -} - -static int -convert_traverse(PyObject *_self, visitproc visit, void *arg) -{ - convert_object *self = (convert_object *)_self; - - Py_VISIT(self->fulladdr_type); - Py_VISIT(self->ctx_type); - Py_VISIT(self->meth_type); - Py_VISIT(self->custommeth_type); - Py_VISIT(self->linearmeth_type); - Py_VISIT(self->pgtmeth_type); - Py_VISIT(self->lookupmeth_type); - Py_VISIT(self->memarrmeth_type); - Py_VISIT(self->range_type); - Py_VISIT(self->map_type); - Py_VISIT(self->sys_type); - Py_VISIT(self->step_type); - Py_VISIT(self->op_type); - return 0; -} - -PyDoc_STRVAR(convert_fulladdr__doc__, -"target type for FullAddress conversions"); - -PyDoc_STRVAR(convert_ctx__doc__, -"Target type for Context conversions."); - -PyDoc_STRVAR(convert_meth__doc__, -"Target type for Method conversions."); - -PyDoc_STRVAR(convert_custommeth__doc__, -"Target type for CustomMethod conversions."); - -PyDoc_STRVAR(convert_linearmeth__doc__, -"Target type for LinearMethod conversions."); - -PyDoc_STRVAR(convert_pgtmeth__doc__, -"Target type for PageTableMethod conversions."); - -PyDoc_STRVAR(convert_lookupmeth__doc__, -"Target type for LookupMethod conversions."); - -PyDoc_STRVAR(convert_memarrmeth__doc__, -"Target type for MemoryArrayMethod conversions."); - -PyDoc_STRVAR(convert_range__doc__, -"Target type for Range conversions."); - -PyDoc_STRVAR(convert_map__doc__, -"Target type for Map conversions."); - -PyDoc_STRVAR(convert_sys__doc__, -"Target type for System conversions."); - -PyDoc_STRVAR(convert_step__doc__, -"Target type for Step conversions."); - -PyDoc_STRVAR(convert_op__doc__, -"Target type for Operator conversions."); - -static PyMemberDef convert_members[] = { - { "FullAddress", T_OBJECT, offsetof(convert_object, fulladdr_type), - 0, convert_fulladdr__doc__ }, - { "Context", T_OBJECT, offsetof(convert_object, ctx_type), - 0, convert_ctx__doc__ }, - { "Method", T_OBJECT, offsetof(convert_object, meth_type), - 0, convert_meth__doc__ }, - { "CustomMethod", T_OBJECT, - offsetof(convert_object, custommeth_type), - 0, convert_custommeth__doc__ }, - { "LinearMethod", T_OBJECT, - offsetof(convert_object, linearmeth_type), - 0, convert_linearmeth__doc__ }, - { "PageTableMethod", T_OBJECT, - offsetof(convert_object, pgtmeth_type), - 0, convert_pgtmeth__doc__ }, - { "LookupMethod", T_OBJECT, - offsetof(convert_object, lookupmeth_type), - 0, convert_lookupmeth__doc__ }, - { "MemoryArrayMethod", T_OBJECT, - offsetof(convert_object, memarrmeth_type), - 0, convert_memarrmeth__doc__ }, - { "Range", T_OBJECT, offsetof(convert_object, range_type), - 0, convert_range__doc__ }, - { "Map", T_OBJECT, offsetof(convert_object, map_type), - 0, convert_map__doc__ }, - { "System", T_OBJECT, offsetof(convert_object, sys_type), - 0, convert_sys__doc__ }, - { "Step", T_OBJECT, offsetof(convert_object, step_type), - 0, convert_step__doc__ }, - { "Operator", T_OBJECT, offsetof(convert_object, op_type), - 0, convert_op__doc__ }, - - { NULL } -}; - -static PyTypeObject convert_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".TypeConvert", /* tp_name */ - sizeof (convert_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - convert_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - convert__doc__, /* tp_doc */ - convert_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - convert_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - convert_new, /* tp_new */ -}; - -/** Python representation of @ref addrxlat_fulladdr_t. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - /** Full address in libaddrxlat format. */ - addrxlat_fulladdr_t faddr; -} fulladdr_object; - -PyDoc_STRVAR(fulladdr__doc__, -"FullAddress() -> fulladdr\n\ -\n\ -Construct a full address, that is an address within a given\n\ -address space (ADDRXLAT_xxxADDR)."); - -/** Construct a fulladdr object from an @c addrxlat_fulladdr_t pointer. - * @param _conv TypeConvert object. - * @param faddr New value as a C object. - * @returns Corresponding Python object (or @c NULL on failure). - * - * This function makes a new copy of the full address. - */ -static PyObject * -fulladdr_FromPointer(PyObject *_conv, const addrxlat_fulladdr_t *faddr) -{ - convert_object *conv = (convert_object *)_conv; - PyTypeObject *type = conv->fulladdr_type; - PyObject *result; - - result = type->tp_alloc(type, 0); - if (result) - ((fulladdr_object*)result)->faddr = *faddr; - return result; -} - -static int -fulladdr_equal(fulladdr_object *v, fulladdr_object *w) -{ - return v->faddr.addr == w->faddr.addr && - v->faddr.as == w->faddr.as; -} - -static PyObject * -fulladdr_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - - if ((op == Py_EQ || op == Py_NE) && - PyObject_TypeCheck(v, &fulladdr_type) && - PyObject_TypeCheck(w, &fulladdr_type)) { - int cmp = fulladdr_equal((fulladdr_object*)v, - (fulladdr_object*)w); - result = (cmp == (op == Py_EQ)) - ? Py_True - : Py_False; - } else - result = Py_NotImplemented; - - Py_INCREF(result); - return result; -} - -PyDoc_STRVAR(fulladdr_addr__doc__, -"address (unsigned)"); - -PyDoc_STRVAR(fulladdr_addrspace__doc__, -"address space"); - -static PyGetSetDef fulladdr_getset[] = { - { "addr", get_addr, set_addr, fulladdr_addr__doc__, - OFFSETOF_PTR(fulladdr_object, faddr.addr) }, - { "addrspace", get_addrspace, set_addrspace, - fulladdr_addrspace__doc__ , - OFFSETOF_PTR(fulladdr_object, faddr.as) }, - { NULL } -}; - -PyDoc_STRVAR(fulladdr_conv__doc__, -"FULLADDR.conv(addrspace, ctx, sys) -> status\n\ -\n\ -Convert a full address to a given target address space."); - -/** Wrapper for @ref addrxlat_fulladdr_conv - * @param _self step object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns status code (or @c NULL on failure) - */ -static PyObject * -fulladdr_conv(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - fulladdr_object *self = (fulladdr_object*)_self; - static char *keywords[] = {"addrspace", "ctx", "sys", NULL}; - PyObject *ctxobj, *sysobj; - addrxlat_ctx_t *ctx; - addrxlat_sys_t *sys; - int addrspace; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iOO:conv", - keywords, &addrspace, - &ctxobj, &sysobj)) - return NULL; - - ctx = ctx_AsPointer(ctxobj); - if (!ctx) - return NULL; - - sys = sys_AsPointer(sysobj); - if (PyErr_Occurred()) - return NULL; - - status = addrxlat_fulladdr_conv(&self->faddr, addrspace, ctx, sys); - return ctx_status_result(ctxobj, status); -} - -static PyMethodDef fulladdr_methods[] = { - { "conv", (PyCFunction)fulladdr_conv, - METH_VARARGS | METH_KEYWORDS, - fulladdr_conv__doc__ }, - { NULL } -}; - -static PyTypeObject fulladdr_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".FullAddress", /* tp_name */ - sizeof (fulladdr_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - fulladdr__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - fulladdr_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - fulladdr_methods, /* tp_methods */ - 0, /* tp_members */ - fulladdr_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Python fulladdr object. - * @param self FullAddress object. - * @returns Address of the embedded @c libaddrxlat_fulladdr_t, - * or @c NULL on error. - * - * The returned pointer refers to a @c libaddrxlat_fulladdr_t - * structure embedded in the Python object, i.e. the pointer is - * valid only as long as the containing Python object exists. - * - * If @c self is @c Py_None, return a pointer to a null address singleton. - * This singleton should not be modified, as it would affect all other - * @c None full addresses. - */ -static addrxlat_fulladdr_t * -fulladdr_AsPointer(PyObject *self) -{ - static addrxlat_fulladdr_t nulladdr = { 0, ADDRXLAT_NOADDR }; - - if (self == Py_None) - return &nulladdr; - - if (!PyObject_TypeCheck(self, &fulladdr_type)) { - PyErr_Format(PyExc_TypeError, - "need a FullAddress or None, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - return &((fulladdr_object*)self)->faddr; -} - -typedef struct tag_ctx_object { - PyObject_HEAD - - addrxlat_ctx_t *ctx; - addrxlat_cb_t *cb; - - PyObject *exc_type, *exc_val, *exc_tb; - - PyObject *convert; -} ctx_object; - -static void -ctx_set_exception(ctx_object *self, - PyObject *exc_type, PyObject *exc_val, PyObject *exc_tb) -{ - PyObject *old_type, *old_val, *old_tb; - - old_type = self->exc_type; - old_val = self->exc_val; - old_tb = self->exc_tb; - self->exc_type = exc_type; - self->exc_val = exc_val; - self->exc_tb = exc_tb; - Py_XDECREF(old_type); - Py_XDECREF(old_val); - Py_XDECREF(old_tb); -} - -static addrxlat_status -ctx_error_status(ctx_object *self) -{ - PyObject *exc_type, *exc_val, *exc_tb; - PyObject *obj; - addrxlat_status status; - const char *msg; - - PyErr_Fetch(&exc_type, &exc_val, &exc_tb); - if (!exc_type) - return ADDRXLAT_OK; - - if (!PyErr_GivenExceptionMatches(exc_type, BaseException)) - goto err; - - PyErr_NormalizeException(&exc_type, &exc_val, &exc_tb); - obj = PyObject_GetAttrString(exc_val, "status"); - if (!obj) - goto err; - status = Number_AsLong(obj); - if (PyErr_Occurred()) { - Py_DECREF(obj); - goto err; - } - Py_DECREF(obj); - - obj = PyObject_GetAttrString(exc_val, "message"); - if (!obj) - goto err; - msg = Text_AsUTF8(obj); - if (!msg) { - Py_DECREF(obj); - goto err; - } - addrxlat_ctx_err(self->ctx, status, "%s", msg); - Py_DECREF(obj); - - Py_DECREF(exc_type); - Py_DECREF(exc_val); - Py_XDECREF(exc_tb); - return status; - - err: - PyErr_Clear(); - ctx_set_exception(self, exc_type, exc_val, exc_tb); - return STATUS_PYEXC; -} - -/** Handle a possible exception raised by a callback. - * @param self Context object - * @param status Error status - * @returns Negative if an exception was restored, zero otherwise. - * - * A special return code is used to pass Python exceptions from a callback - * to the caller. The exception is stored in the Context object in that - * case. - * - * However, the library code may decide to ignore any errors returned by - * the callback. If that happens, the exception must be cleared accordingly. - */ -static int -handle_cb_exception(ctx_object *self, addrxlat_status status) -{ - if (status == STATUS_PYEXC && self->exc_type) { - PyErr_Restore(self->exc_type, self->exc_val, self->exc_tb); - self->exc_type = NULL; - self->exc_val = NULL; - self->exc_tb = NULL; - return -1; - } - ctx_set_exception(self, NULL, NULL, NULL); - return 0; -} - -static PyObject * -ctx_status_result(PyObject *_self, addrxlat_status status) -{ - ctx_object *self = (ctx_object*)_self; - return !handle_cb_exception(self, status) - ? PyInt_FromLong(status) - : NULL; -} - -/** Callback function return on None return. - * @param self Python Context object - * @returns Always ADDRXLAT_ERR_NODATA - */ -static addrxlat_status -cb_none(ctx_object *self) -{ - return addrxlat_ctx_err(self->ctx, ADDRXLAT_ERR_NODATA, - "Callback returned None"); -} - -static void -cb_put_page(const addrxlat_buffer_t *buf) -{ - PyMem_Free(buf->priv); -} - -static addrxlat_status -cb_get_page(const addrxlat_cb_t *cb, addrxlat_buffer_t *buf) -{ - ctx_object *self = (ctx_object*)cb->priv; - PyObject *addrobj, *result, *bufferobj; - addrxlat_fulladdr_t *addr; - int byte_order; - Py_buffer view; - - addrobj = fulladdr_FromPointer(self->convert, &buf->addr); - if (!addrobj) - return ctx_error_status(self); - result = PyObject_CallMethod( - (PyObject*)self, "cb_get_page", "O", addrobj); - if (!result) { - Py_DECREF(addrobj); - return ctx_error_status(self); - } - if (result == Py_None) { - Py_DECREF(result); - Py_DECREF(addrobj); - return cb_none(self); - } - - byte_order = ADDRXLAT_HOST_ENDIAN; - if (PyTuple_Check(result)) { - if (!PyArg_ParseTuple(result, "O|i:cb_get_page", - &bufferobj, &byte_order)) { - Py_DECREF(result); - Py_DECREF(addrobj); - return ctx_error_status(self); - } - Py_INCREF(bufferobj); - Py_DECREF(result); - } else - bufferobj = result; - - addr = fulladdr_AsPointer(addrobj); - if (!addr) { - Py_DECREF(addrobj); - Py_DECREF(bufferobj); - return ctx_error_status(self); - } - buf->addr = *addr; - Py_DECREF(addrobj); - - if (PyObject_GetBuffer(bufferobj, &view, PyBUF_CONTIG_RO) < 0) { - Py_DECREF(bufferobj); - return ctx_error_status(self); - } - Py_DECREF(bufferobj); - buf->put_page = cb_put_page; - buf->priv = PyMem_Malloc(view.len); - if (buf->priv == NULL) { - PyBuffer_Release(&view); - PyErr_NoMemory(); - return ctx_error_status(self); - } - if (PyBuffer_ToContiguous(buf->priv, &view, view.len, 'C') < 0) { - PyBuffer_Release(&view); - return ctx_error_status(self); - } - buf->ptr = buf->priv; - buf->size = view.len; - buf->byte_order = byte_order; - PyBuffer_Release(&view); - - return ADDRXLAT_OK; -} - -static unsigned long -cb_read_caps(const addrxlat_cb_t *cb) -{ - ctx_object *self = (ctx_object*)cb->priv; - PyObject *result; - unsigned long caps; - - result = PyObject_CallMethod((PyObject*)self, "cb_read_caps", NULL); - if (!result) - return 0; - if (result == Py_None) { - Py_DECREF(result); - return 0; - } - - caps = Number_AsUnsignedLongLong(result); - Py_DECREF(result); - if (PyErr_Occurred()) - return 0; - - return caps; -} - -static addrxlat_status -cb_sym_offsetof(const addrxlat_cb_t *cb, const char *obj, - const char *elem, addrxlat_addr_t *val) -{ - ctx_object *self = (ctx_object*)cb->priv; - PyObject *result; - unsigned long tmpval; - - result = PyObject_CallMethod((PyObject*)self, "cb_sym_offsetof", - "ss", obj, elem); - if (!result) - return ctx_error_status(self); - if (result == Py_None) { - Py_DECREF(result); - return cb_none(self); - } - - tmpval = Number_AsUnsignedLongLong(result); - Py_DECREF(result); - if (PyErr_Occurred()) - return ctx_error_status(self); - - *val = tmpval; - return ADDRXLAT_OK; -} - -static addrxlat_status -cb_arg1_value(const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val, - const char *method) -{ - ctx_object *self = (ctx_object*)cb->priv; - PyObject *result; - unsigned long tmpval; - - result = PyObject_CallMethod((PyObject*)self, method, "s", name); - if (!result) - return ctx_error_status(self); - if (result == Py_None) { - Py_DECREF(result); - return cb_none(self); - } - - tmpval = Number_AsUnsignedLongLong(result); - Py_DECREF(result); - if (PyErr_Occurred()) - return ctx_error_status(self); - - *val = tmpval; - return ADDRXLAT_OK; -} - -static addrxlat_status -cb_reg_value(const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val) -{ - return cb_arg1_value(cb, name, val, "cb_reg_value"); -} - -static addrxlat_status -cb_sym_value(const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val) -{ - return cb_arg1_value(cb, name, val, "cb_sym_value"); -} - -static addrxlat_status -cb_sym_sizeof(const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val) -{ - return cb_arg1_value(cb, name, val, "cb_sym_sizeof"); -} - -static addrxlat_status -cb_num_value(const addrxlat_cb_t *cb, const char *name, addrxlat_addr_t *val) -{ - return cb_arg1_value(cb, name, val, "cb_num_value"); -} - -PyDoc_STRVAR(ctx__doc__, -"Context() -> address translation context"); - -static PyObject * -ctx_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - ctx_object *self; - - self = (ctx_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - self->ctx = get_c_pointer(kwargs); - if (!self->ctx) { - if (PyErr_Occurred()) - return NULL; - - self->ctx = addrxlat_ctx_new(); - if (!self->ctx) { - Py_DECREF(self); - return PyErr_NoMemory(); - } - } else { - addrxlat_ctx_incref(self->ctx); - - if (copy_attr((PyObject*)self, "next_cb_get_page", "cb_get_page")) - goto err; - if (copy_attr((PyObject*)self, "next_cb_reg_value", "cb_reg_value")) - goto err; - if (copy_attr((PyObject*)self, "next_cb_sym_value", "cb_sym_value")) - goto err; - if (copy_attr((PyObject*)self, "next_cb_sym_sizeof", "cb_sym_sizeof")) - goto err; - if (copy_attr((PyObject*)self, "next_cb_sym_offsetof", "cb_sym_offsetof")) - goto err; - if (copy_attr((PyObject*)self, "next_cb_num_value", "cb_num_value")) - goto err; - } - - self->cb = addrxlat_ctx_add_cb(self->ctx); - if (!self->cb) { - addrxlat_ctx_decref(self->ctx); - Py_DECREF(self); - return PyErr_NoMemory(); - } - self->cb->priv = self; - self->cb->get_page = cb_get_page; - self->cb->read_caps = cb_read_caps; - self->cb->reg_value = cb_reg_value; - self->cb->sym_value = cb_sym_value; - self->cb->sym_sizeof = cb_sym_sizeof; - self->cb->sym_offsetof = cb_sym_offsetof; - self->cb->num_value = cb_num_value; - - Py_INCREF(convert); - self->convert = convert; - - return (PyObject*)self; - - err: - Py_DECREF(self); - return NULL; -} - -static int -ctx_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - return c_pointer_super_init(&ctx_type, self, args, kwargs); -} - -/** Construct a context object from an @c addrxlat_ctx_t pointer. - * @param _conv TypeConvert object. - * @param ctx New value as a C object, or @c NULL. - * @returns Corresponding Python object (or @c NULL on failure). - * - * The Python object contains a new reference to the translation context. - */ -static PyObject * -ctx_FromPointer(PyObject *_conv, addrxlat_ctx_t *ctx) -{ - convert_object *conv = (convert_object *)_conv; - - if (!ctx) - Py_RETURN_NONE; - - return object_FromPointer(conv->ctx_type, ctx); -} - -static void -ctx_dealloc(PyObject *_self) -{ - ctx_object *self = (ctx_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - - Py_XDECREF(self->exc_type); - Py_XDECREF(self->exc_val); - Py_XDECREF(self->exc_tb); - - if (self->ctx) { - addrxlat_ctx_del_cb(self->ctx, self->cb); - addrxlat_ctx_decref(self->ctx); - } - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -ctx_traverse(PyObject *_self, visitproc visit, void *arg) -{ - ctx_object *self = (ctx_object*)_self; - - Py_VISIT(self->exc_type); - Py_VISIT(self->exc_val); - Py_VISIT(self->exc_tb); - - Py_VISIT(self->convert); - - return 0; -} - -static PyObject * -ctx_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - - if ((op == Py_EQ || op == Py_NE) && - PyObject_TypeCheck(v, &ctx_type) && - PyObject_TypeCheck(w, &ctx_type)) { - int cmp = (((ctx_object*)v)->ctx == ((ctx_object*)w)->ctx); - result = (cmp == (op == Py_EQ)) - ? Py_True - : Py_False; - } else - result = Py_NotImplemented; - - Py_INCREF(result); - return result; -} - -PyDoc_STRVAR(ctx_err__doc__, -"CTX.err(status, str) -> error status\n\ -\n\ -Set the error message."); - -static PyObject * -ctx_err(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - ctx_object *self = (ctx_object*)_self; - static char *keywords[] = {"status", "str", NULL}; - int statusparam; - const char *msg; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "is:err", - keywords, &statusparam, &msg)) - return NULL; - - status = addrxlat_ctx_err(self->ctx, statusparam, "%s", msg); - return ctx_status_result((PyObject*)self, status); -} - -PyDoc_STRVAR(ctx_clear_err__doc__, -"CTX.clear_err()\n\ -\n\ -Clear the error message."); - -static PyObject * -ctx_clear_err(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - - addrxlat_ctx_clear_err(self->ctx); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(ctx_get_err__doc__, -"CTX.get_err() -> error string\n\ -\n\ -Return a detailed error description of the last error condition."); - -static PyObject * -ctx_get_err(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *err = addrxlat_ctx_get_err(self->ctx); - - return err - ? Text_FromUTF8(err) - : (Py_INCREF(Py_None), Py_None); -} - -PyDoc_STRVAR(ctx_cb_get_page__doc__, -"CTX.cb_get_page(fulladdr) -> (value, [byte_order])\n\ -\n\ -Callback function to read a page at a given address. The first element\n\ -of the return tuple must implement the buffer protocol. The second\n\ -element is optional and defaults to HOST_ENDIAN."); - -PyDoc_STRVAR(ctx_next_cb_get_page__doc__, -"CTX.next_cb_get_page(type, *args) -> value\n\ -\n\ -Call the next callback to read a page."); - -static PyObject * -ctx_next_cb_get_page(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - PyObject *addrobj, *bytearrayobj, *result; - addrxlat_fulladdr_t *addr; - addrxlat_buffer_t buffer; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "O", &addrobj)) - return NULL; - addr = fulladdr_AsPointer(addrobj); - if (!addr) - return NULL; - - buffer.addr = *addr; - status = self->cb->next->get_page(self->cb->next, &buffer); - *addr = buffer.addr; - - if (self->cb->next->get_page == cb_get_page && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - bytearrayobj = PyByteArray_FromStringAndSize(buffer.ptr, buffer.size); - if (!bytearrayobj) - goto err; - result = Py_BuildValue("(Oi)", bytearrayobj, buffer.byte_order); - if (!result) - goto err_bytearray; - return result; - - err_bytearray: - Py_DECREF(bytearrayobj); - err: - return NULL; -} - -PyDoc_STRVAR(ctx_cb_read_caps__doc__, -"CTX.cb_read_caps() -> capabilities\n\ -\n\ -Callback function to get a bitmask of address spaces accepted by\n\ -the cb_get_page callback."); - -PyDoc_STRVAR(ctx_next_cb_read_caps__doc__, -"CTX.next_cb_read_caps() -> value\n\ -\n\ -Call the next callback to get the capabilities."); - -static PyObject * -ctx_next_cb_read_caps(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - unsigned long caps; - PyObject *result; - - caps = self->cb->next->read_caps(self->cb->next); - if (PyErr_Occurred()) - return NULL; - - result = Py_BuildValue("(k)", caps); - if (!result) - return NULL; - return result; -} - -PyDoc_STRVAR(ctx_cb_reg_value__doc__, -"CTX.cb_reg_value(type, name) -> value\n\ -\n\ -Callback function to read register value."); - -PyDoc_STRVAR(ctx_next_cb_reg_value__doc__, -"CTX.next_cb_reg_value(type, name) -> value\n\ -\n\ -Call the next register value callback."); - -static PyObject * -ctx_next_cb_reg_value(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *name; - addrxlat_addr_t val; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - - status = self->cb->next->reg_value(self->cb->next, name, &val); - - if (self->cb->next->reg_value == cb_reg_value && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - return PyLong_FromUnsignedLongLong(val); -} - -PyDoc_STRVAR(ctx_cb_sym_value__doc__, -"CTX.cb_sym_value(type, name) -> value\n\ -\n\ -Callback function to get the value of a symbol."); - -PyDoc_STRVAR(ctx_next_cb_sym_value__doc__, -"CTX.next_cb_sym_value(type, name) -> value\n\ -\n\ -Call the next symbol value callback."); - -static PyObject * -ctx_next_cb_sym_value(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *name; - addrxlat_addr_t val; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - - status = self->cb->next->sym_value(self->cb->next, name, &val); - - if (self->cb->next->sym_value == cb_sym_value && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - return PyLong_FromUnsignedLongLong(val); -} - -PyDoc_STRVAR(ctx_cb_sym_sizeof__doc__, -"CTX.cb_sym_sizeof(type, name) -> value\n\ -\n\ -Callback function to get the size of a symbol."); - -PyDoc_STRVAR(ctx_next_cb_sym_sizeof__doc__, -"CTX.next_cb_sym_sizeof(type, name) -> value\n\ -\n\ -Call the next symbol size callback."); - -static PyObject * -ctx_next_cb_sym_sizeof(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *name; - addrxlat_addr_t val; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - - status = self->cb->next->sym_sizeof(self->cb->next, name, &val); - - if (self->cb->next->sym_sizeof == cb_sym_sizeof && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - return PyLong_FromUnsignedLongLong(val); -} - -PyDoc_STRVAR(ctx_cb_sym_offsetof__doc__, -"CTX.cb_sym_offsetof(type, obj, elem) -> value\n\ -\n\ -Callback function to get the offset of an element within a container object."); - -PyDoc_STRVAR(ctx_next_cb_sym_offsetof__doc__, -"CTX.next_cb_sym_offsetof(type, obj, elem) -> value\n\ -\n\ -Call the next element offset callback."); - -static PyObject * -ctx_next_cb_sym_offsetof(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *obj, *elem; - addrxlat_addr_t val; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "ss", &obj, &elem)) - return NULL; - - status = self->cb->next->sym_offsetof(self->cb->next, obj, elem, &val); - - if (self->cb->next->sym_offsetof == cb_sym_offsetof && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - return PyLong_FromUnsignedLongLong(val); -} - -PyDoc_STRVAR(ctx_cb_num_value__doc__, -"CTX.cb_num_value(type, name) -> value\n\ -\n\ -Callback function to get the value of a numeric parameter."); - -PyDoc_STRVAR(ctx_next_cb_num_value__doc__, -"CTX.next_cb_num_value(type, name) -> value\n\ -\n\ -Call the next numeric parameter callback."); - -static PyObject * -ctx_next_cb_num_value(PyObject *_self, PyObject *args) -{ - ctx_object *self = (ctx_object*)_self; - const char *name; - addrxlat_addr_t val; - addrxlat_status status; - - addrxlat_ctx_clear_err(self->ctx); - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - - status = self->cb->next->num_value(self->cb->next, name, &val); - - if (self->cb->next->num_value == cb_num_value && - handle_cb_exception((ctx_object*)self->cb->next->priv, status)) - return NULL; - - if (status != ADDRXLAT_OK) - return raise_exception(self->ctx, status); - - return PyLong_FromUnsignedLongLong(val); -} - -static PyMethodDef ctx_methods[] = { - { "err", (PyCFunction)ctx_err, METH_VARARGS | METH_KEYWORDS, - ctx_err__doc__ }, - { "clear_err", ctx_clear_err, METH_NOARGS, - ctx_clear_err__doc__ }, - { "get_err", ctx_get_err, METH_NOARGS, - ctx_get_err__doc__ }, - - /* Callbacks */ - { "cb_get_page", ctx_next_cb_get_page, METH_VARARGS, - ctx_cb_get_page__doc__ }, - { "cb_read_caps", ctx_next_cb_read_caps, METH_VARARGS, - ctx_cb_read_caps__doc__ }, - { "cb_reg_value", ctx_next_cb_reg_value, METH_VARARGS, - ctx_cb_reg_value__doc__ }, - { "cb_sym_value", ctx_next_cb_sym_value, METH_VARARGS, - ctx_cb_sym_value__doc__ }, - { "cb_sym_sizeof", ctx_next_cb_sym_sizeof, METH_VARARGS, - ctx_cb_sym_sizeof__doc__ }, - { "cb_sym_offsetof", ctx_next_cb_sym_offsetof, METH_VARARGS, - ctx_cb_sym_offsetof__doc__ }, - { "cb_num_value", ctx_next_cb_num_value, METH_VARARGS, - ctx_cb_num_value__doc__ }, - - { "next_cb_get_page", ctx_next_cb_get_page, METH_VARARGS, - ctx_next_cb_get_page__doc__ }, - { "next_read_caps", ctx_next_cb_read_caps, METH_VARARGS, - ctx_next_cb_read_caps__doc__ }, - { "next_cb_reg_value", ctx_next_cb_reg_value, METH_VARARGS, - ctx_next_cb_reg_value__doc__ }, - { "next_cb_sym_value", ctx_next_cb_sym_value, METH_VARARGS, - ctx_next_cb_sym_value__doc__ }, - { "next_cb_sym_sizeof", ctx_next_cb_sym_sizeof, METH_VARARGS, - ctx_next_cb_sym_sizeof__doc__ }, - { "next_cb_sym_offsetof", ctx_next_cb_sym_offsetof, METH_VARARGS, - ctx_next_cb_sym_offsetof__doc__ }, - { "next_cb_num_value", ctx_next_cb_num_value, METH_VARARGS, - ctx_next_cb_num_value__doc__ }, - - { NULL } -}; - -static PyMemberDef ctx_members[] = { - { "convert", T_OBJECT, offsetof(ctx_object, convert), 0, - attr_convert__doc__ }, - { NULL } -}; - -static PyTypeObject ctx_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Context", /* tp_name */ - sizeof (ctx_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - ctx_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - ctx__doc__, /* tp_doc */ - ctx_traverse, /* tp_traverse */ - 0, /* tp_clear */ - ctx_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctx_methods, /* tp_methods */ - ctx_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - ctx_init, /* tp_init */ - 0, /* tp_alloc */ - ctx_new, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Context object. - * @param self Context object. - * @returns Associated @c libaddrxlat_ctx_t, or @c NULL on error. - * - * This function does not increment the reference count of the returned - * C object. It is assumed that the caller holds a reference to the Python - * object, which in turn holds a reference to the C object. - */ -static addrxlat_ctx_t * -ctx_AsPointer(PyObject *self) -{ - if (!PyObject_TypeCheck(self, &ctx_type)) { - PyErr_Format(PyExc_TypeError, - "need a Context, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - return ((ctx_object*)self)->ctx; -} - -static int -replace_ctx(PyObject **pctxobj, addrxlat_ctx_t **pctx, PyObject *newval) -{ - addrxlat_ctx_t *ctx; - PyObject *oldval; - - ctx = ctx_AsPointer(newval); - if (!ctx) - return -1; - - addrxlat_ctx_incref(ctx); - if (*pctx) - addrxlat_ctx_decref(*pctx); - *pctx = ctx; - - Py_INCREF(newval); - oldval = *pctxobj; - *pctxobj = newval; - Py_XDECREF(oldval); - return 0; -} - -typedef struct { - void *ptr; - unsigned off; - unsigned len; -} param_loc; - -static void -loc_scatter(const param_loc *loc, unsigned n, const void *buffer) -{ - unsigned i; - for (i = 0; i < n; ++i, ++loc) - if (loc->ptr && loc->ptr != buffer + loc->off) - memcpy(loc->ptr, buffer + loc->off, loc->len); -} - -static void -loc_gather(const param_loc *loc, unsigned n, void *buffer) -{ - unsigned i; - for (i = 0; i < n; ++i, ++loc) - if (loc->ptr && loc->ptr != buffer + loc->off) - memcpy(buffer + loc->off, loc->ptr, loc->len); -} - -/** Location of a fulladdr parameter within another object. */ -typedef struct { - /** Offset of the Python object. */ - size_t off_obj; - - /** Offset of the corresponding @ref param_loc structure. */ - size_t off_loc; - - /** Name of the attribute (used in exception messages). */ - const char name[]; -} fulladdr_loc; - -/** Getter for the fulladdr type. - * @param self any object - * @param data fulladdr attribute location - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -get_fulladdr(PyObject *self, void *data) -{ - fulladdr_loc *addrloc = data; - PyObject **fulladdr = (PyObject**)((char*)self + addrloc->off_obj); - Py_INCREF(*fulladdr); - return *fulladdr; -} - -/** Setter for the fulladdr type. - * @param self any object - * @param value new value (a fulladdr object) - * @param data fulladdr attribute location - * @returns zero on success, -1 otherwise - */ -static int -set_fulladdr(PyObject *self, PyObject *value, void *data) -{ - fulladdr_loc *addrloc = data; - PyObject **pobj = (PyObject**)((char*)self + addrloc->off_obj); - param_loc *loc = (param_loc*)((char*)self + addrloc->off_loc); - PyObject *oldval; - addrxlat_fulladdr_t *addr; - - if (check_null_attr(value, addrloc->name)) - return -1; - - addr = fulladdr_AsPointer(value); - if (!addr) - return -1; - - Py_INCREF(value); - oldval = *pobj; - *pobj = value; - loc->ptr = (value == Py_None ? NULL : addr); - Py_XDECREF(oldval); - return 0; -} - -/** Maximum number of parameter locations in meth_object. - * This is not checked anywhere, but should be less than the maximum - * possible number of parameter locations. The assignment is currently: - * - * - @c loc[0] corresponds to the whole raw param object - * - @c loc[1] is the root address (for PageTableMethod) or - * base address (for MemoryArrayMethod) - */ -#define MAXLOC 2 - -#define meth_HEAD \ - PyObject_HEAD \ - addrxlat_meth_t meth; \ - PyObject *paramobj; \ - unsigned nloc; \ - param_loc loc[MAXLOC]; \ - PyObject *convert; - -typedef struct { - meth_HEAD -} meth_object; - -/** Number of parameter locations in meth_object. */ -#define METH_NLOC 1 - -PyDoc_STRVAR(meth__doc__, -"Method(kind) -> address translation method\n\ -\n\ -This is a generic base class for all translation descriptions.\n\ -Use a subclass to get a more suitable interface to the parameters\n\ -of a specific translation kind."); - -static PyObject * -meth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - static const char *keywords[] = {"kind", NULL}; - meth_object *self; - PyObject *value; - long kind; - - if (fetch_args(keywords, 1, &args, &kwargs, &value)) - return NULL; - Py_DECREF(args); - Py_XDECREF(kwargs); - kind = Number_AsLong(value); - if (PyErr_Occurred()) - return NULL; - - self = (meth_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - self->meth.kind = kind; - self->meth.target_as = ADDRXLAT_NOADDR; - self->nloc = METH_NLOC; - self->loc[0].ptr = &self->meth.param; - self->loc[0].off = 0; - self->loc[0].len = sizeof(self->meth.param); - self->paramobj = make_meth_param((PyObject*)self); - if (!self->paramobj) { - Py_DECREF(self); - return NULL; - } - Py_INCREF(convert); - self->convert = convert; - - return (PyObject*)self; -} - -/** Initialize a Method object using a C @c addrxlat_meth_t object. - * @param _self Python Method object - * @param meth libaddrxlat translation method - * @returns zero on success, -1 otherwise - */ -static int -meth_Init(PyObject *_self, const addrxlat_meth_t *meth) -{ - meth_object *self = (meth_object*)_self; - - self->meth.target_as = meth->target_as; - loc_scatter(self->loc, self->nloc, &meth->param); - return 0; -} - -static void -meth_dealloc(PyObject *_self) -{ - meth_object *self = (meth_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - Py_XDECREF(self->paramobj); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -meth_traverse(PyObject *_self, visitproc visit, void *arg) -{ - meth_object *self = (meth_object*)_self; - Py_VISIT(self->paramobj); - Py_VISIT(self->convert); - return 0; -} - -static int -meth_equal(meth_object *v, meth_object *w) -{ - return v->loc[0].len == w->loc[0].len && - !memcmp(&v->meth, &w->meth, v->loc[0].len); -} - -static PyObject * -meth_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - - if ((op == Py_EQ || op == Py_NE) && - PyObject_TypeCheck(v, &meth_type) && - PyObject_TypeCheck(w, &meth_type)) { - int cmp = meth_equal((meth_object*)v, (meth_object*)w); - result = (cmp == (op == Py_EQ)) - ? Py_True - : Py_False; - } else - result = Py_NotImplemented; - - Py_INCREF(result); - return result; -} - -static PyMemberDef meth_members[] = { - { "convert", T_OBJECT, offsetof(meth_object, convert), 0, - attr_convert__doc__ }, - { NULL } -}; - -PyDoc_STRVAR(meth_kind__doc__, -"translation kind"); - -static PyObject * -meth_get_kind(PyObject *_self, void *data) -{ - meth_object *self = (meth_object*)_self; - return PyInt_FromLong(self->meth.kind); -} - -PyDoc_STRVAR(meth_target_as__doc__, -"target address space"); - -PyDoc_STRVAR(meth_param__doc__, -"metho parameters as a raw bytearray"); - -static int -meth_set_param(PyObject *_self, PyObject *value, void *data) -{ - meth_object *self = (meth_object*)_self; - - if (check_null_attr(value, "param")) - return -1; - - if (ByteSequence_AsBuffer(value, &self->meth.param, - sizeof(self->meth.param))) - return -1; - - loc_scatter(self->loc, self->nloc, &self->meth.param); - - return 0; -} - -static PyGetSetDef meth_getset[] = { - { "kind", meth_get_kind, 0, meth_kind__doc__ }, - { "target_as", get_addrspace, set_addrspace, meth_target_as__doc__, - OFFSETOF_PTR(meth_object, meth.target_as) }, - { "param", get_object, meth_set_param, meth_param__doc__, - OFFSETOF_PTR(meth_object, paramobj) }, - { NULL } -}; - -static PyTypeObject meth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Method", /* tp_name */ - sizeof (meth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - meth__doc__, /* tp_doc */ - meth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - meth_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - meth_members, /* tp_members */ - meth_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - meth_new, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Method object. - * @param self Method object. - * @returns Address of the embedded @c libaddrxlat_meth_t, - * or @c NULL on error. - * - * The returned pointer refers to a @c libaddrxlat_meth_t structure embedded - * in the Python object, i.e. the pointer is valid only as long as the - * containing Python object exists. - * - * NB: Some fields are updated dynamically, so the returned data may be stale - * after the Python object is modified. - */ -static addrxlat_meth_t * -meth_AsPointer(PyObject *self) -{ - meth_object *methobj; - - if (!PyObject_TypeCheck(self, &meth_type)) { - PyErr_Format(PyExc_TypeError, - "need a Method, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - methobj = (meth_object*)self; - loc_gather(methobj->loc, methobj->nloc, &methobj->meth.param); - return &methobj->meth; -} - -static PyObject * -make_meth(PyTypeObject *type, addrxlat_kind_t kind, PyObject *kwargs) -{ - PyObject *args, *result; - - args = Py_BuildValue("(l)", (long)kind); - if (!args) - return NULL; - result = meth_new(type, args, kwargs); - Py_DECREF(args); - - return result; -} - -typedef struct { - PyObject_HEAD - PyObject *meth; -} meth_param_object; - -static void -meth_param_dealloc(PyObject *_self) -{ - meth_param_object *self = (meth_param_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_DECREF(self->meth); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -meth_param_traverse(PyObject *_self, visitproc visit, void *arg) -{ - meth_param_object *self = (meth_param_object*)_self; - Py_VISIT(self->meth); - return 0; -} - -static Py_ssize_t -meth_param_len(PyObject *_self) -{ - meth_param_object *self = (meth_param_object*)_self; - meth_object *param = (meth_object*)self->meth; - - return param->loc[0].len; -} - -static void * -meth_param_ptr(meth_object *param, Py_ssize_t index) -{ - param_loc *loc; - void *ptr = NULL; - - for (loc = param->loc; loc < ¶m->loc[param->nloc]; ++loc) - if (loc->ptr && - loc->off <= index && index < loc->off + loc->len) - ptr = loc->ptr + index - loc->off; - return ptr; -} - -static PyObject * -meth_param_item(PyObject *_self, Py_ssize_t index) -{ - meth_param_object *self = (meth_param_object*)_self; - unsigned char *ptr = meth_param_ptr((meth_object*)self->meth, index); - - if (!ptr) { - PyErr_SetString(PyExc_IndexError, - "param index out of range"); - return NULL; - } - - return PyInt_FromLong(*ptr); -} - -static int -meth_param_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value) -{ - meth_param_object *self = (meth_param_object*)_self; - unsigned char *ptr; - long byte; - - if (!value) { - PyErr_SetString(PyExc_TypeError, - "param items cannot be deleted"); - return -1; - } - - ptr = meth_param_ptr((meth_object*)self->meth, index); - if (!ptr) { - PyErr_SetString(PyExc_IndexError, - "param assignment index out of range"); - return -1; - } - - byte = Number_AsLong(value); - if (byte < 0 || byte > 0xff) { - PyErr_SetString(PyExc_OverflowError, - "param byte value out of range"); - return -1; - } - - *ptr = byte; - return 0; -} - -static PySequenceMethods meth_param_as_sequence = { - meth_param_len, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - meth_param_item, /* sq_item */ - 0, /* sq_slice */ - meth_param_ass_item, /* sq_ass_item */ - 0, /* sq_ass_slice */ - 0, /* sq_contains */ -}; - -static PyTypeObject meth_param_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".meth-param", /* tp_name */ - sizeof (meth_param_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - meth_param_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &meth_param_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - meth_param_traverse, /* tp_traverse */ -}; - -static PyObject * -make_meth_param(PyObject *meth) -{ - PyTypeObject *type = &meth_param_type; - PyObject *result; - - result = type->tp_alloc(type, 0); - if (!result) - return NULL; - - Py_INCREF(meth); - ((meth_param_object*)result)->meth = meth; - return result; -} - -PyDoc_STRVAR(linearmeth__doc__, -"LinearMethod() -> linear address translation method"); - -static PyObject * -linearmeth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - meth_object *self; - - self = (meth_object*) make_meth(type, ADDRXLAT_LINEAR, kwargs); - if (self) - self->loc[0].len = sizeof(addrxlat_param_linear_t); - - return (PyObject*)self; -} - -PyDoc_STRVAR(linearmeth_kind__doc__, -"translation kind (always ADDRXLAT_LINEAR)"); - -PyDoc_STRVAR(linearmeth_off__doc__, -"target linear offset from source"); - -static PyGetSetDef linearmeth_getset[] = { - { "kind", meth_get_kind, 0, linearmeth_kind__doc__ }, - { "off", get_off, set_off, linearmeth_off__doc__, - OFFSETOF_PTR(meth_object, meth.param.linear.off) }, - { NULL } -}; - -static PyTypeObject linearmeth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".LinearMethod", /* tp_name */ - sizeof (meth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - linearmeth__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - linearmeth_getset, /* tp_getset */ - &meth_type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - linearmeth_new, /* tp_new */ -}; - -typedef struct { - meth_HEAD - addrxlat_param_custom_t origparam; -} custommeth_object; - -static addrxlat_status -meth_error_status(custommeth_object *self, addrxlat_step_t *step) -{ - PyObject *ctx; - addrxlat_status status; - - ctx = ctx_FromPointer(self->convert, step->ctx); - if (!ctx) { - PyErr_Clear(); - return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_NOMEM, - "Cannot allocate context"); - } - - status = ctx_error_status((ctx_object*) ctx); - Py_DECREF(ctx); - return status; -} - -/** Update an @c addrxlat_step_t using another object. - * @param step Object to be updated. - * @param other Desired new values for @c step. - */ -static void -update_step(addrxlat_step_t *step, const addrxlat_step_t *other) -{ - if (step->ctx != other->ctx) { - if (step->ctx) - addrxlat_ctx_decref(step->ctx); - if (other->ctx) - addrxlat_ctx_incref(other->ctx); - } - if (step->sys != other->sys) { - if (step->sys) - addrxlat_sys_decref(step->sys); - if (other->sys) - addrxlat_sys_incref(other->sys); - } - memcpy(step, other, sizeof(*step)); -} - -PyDoc_STRVAR(custommeth__doc__, -"CustomMethod() -> custom address translation method"); - -static addrxlat_status -cb_first_step(addrxlat_step_t *step, addrxlat_addr_t addr) -{ - const addrxlat_meth_t *meth = step->meth; - custommeth_object *self = meth->param.custom.data; - PyObject *func; - PyObject *stepobj; - PyObject *result; - - func = PyObject_GetAttrString((PyObject*)self, "cb_first_step"); - if (!func) - return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_NOTIMPL, - "NULL callback"); - - stepobj = step_FromPointer(self->convert, step); - if (!stepobj) { - Py_DECREF(func); - return meth_error_status(self, step); - } - - result = PyObject_CallFunction(func, "OK", - stepobj, (unsigned PY_LONG_LONG) addr); - if (result) - update_step(step, step_AsPointer(stepobj)); - Py_DECREF(stepobj); - Py_DECREF(func); - if (!result) - return meth_error_status(self, step); - - Py_DECREF(result); - return ADDRXLAT_OK; -} - -static addrxlat_status -cb_next_step(addrxlat_step_t *step) -{ - const addrxlat_meth_t *meth = step->meth; - custommeth_object *self = meth->param.custom.data; - PyObject *func; - PyObject *stepobj; - PyObject *result; - - func = PyObject_GetAttrString((PyObject*)self, "cb_next_step"); - if (!func) - return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_NOTIMPL, - "NULL callback"); - - stepobj = step_FromPointer(self->convert, step); - if (!stepobj) { - Py_DECREF(func); - return meth_error_status(self, step); - } - - result = PyObject_CallFunction(func, "O", stepobj); - if (result) - update_step(step, step_AsPointer(stepobj)); - Py_DECREF(stepobj); - Py_DECREF(func); - if (!result) - return meth_error_status(self, step); - - Py_DECREF(result); - return ADDRXLAT_OK; -} - -static PyObject * -custommeth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - custommeth_object *self; - - self = (custommeth_object*) make_meth(type, ADDRXLAT_CUSTOM, kwargs); - if (self) { - self->loc[0].len = sizeof(addrxlat_param_custom_t); - - self->meth.param.custom.first_step = cb_first_step; - self->meth.param.custom.next_step = cb_next_step; - self->meth.param.custom.data = self; - } - - return (PyObject*)self; -} - -static int -custommeth_Init(PyObject *_self, const addrxlat_meth_t *meth) -{ - custommeth_object *self = (custommeth_object*)_self; - - if (meth_Init(_self, meth)) - return -1; - - self->origparam = meth->param.custom; - self->meth.param.custom.first_step = cb_first_step; - self->meth.param.custom.next_step = cb_next_step; - self->meth.param.custom.data = self; - - return 0; -} - -PyDoc_STRVAR(custommeth_first_step__doc__, -"METH.cb_first_step(step, addr)\n\ -\n\ -Callback to perform the initial translation step."); - -static PyObject * -custommeth_first_step(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"step", "addr", NULL}; - - custommeth_object *self = (custommeth_object*)_self; - PyObject *stepobj; - addrxlat_step_t *step; - const addrxlat_meth_t *origmeth; - addrxlat_meth_t tmpmeth; - PyObject *addrobj; - addrxlat_addr_t addr; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:first_step", - keywords, &stepobj, &addrobj)) - return NULL; - step = step_AsPointer(stepobj); - if (!step) - return NULL; - addr = Number_AsUnsignedLongLong(addrobj); - if (PyErr_Occurred()) - return NULL; - - if (!self->origparam.first_step) - return raise_notimpl("NULL callback"); - - origmeth = step->meth; - tmpmeth.kind = step->meth->kind; - tmpmeth.target_as = step->meth->target_as; - tmpmeth.param.custom = self->origparam; - step->meth = &tmpmeth; - status = self->origparam.first_step(step, addr); - self->origparam = step->meth->param.custom; - step->meth = origmeth; - if (status != ADDRXLAT_OK) - return raise_exception(step->ctx, status); - - if (step_Init(stepobj, step)) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(custommeth_next_step__doc__, -"METH.cb_next_step(step)\n\ -\n\ -Callback to perform further translation steps."); - -static PyObject * -custommeth_next_step(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"step", NULL}; - - custommeth_object *self = (custommeth_object*)_self; - PyObject *stepobj; - addrxlat_step_t *step; - const addrxlat_meth_t *origmeth; - addrxlat_meth_t tmpmeth; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:next_step", - keywords, &stepobj)) - return NULL; - step = step_AsPointer(stepobj); - if (!step) - return NULL; - - if (!self->origparam.next_step) - return raise_notimpl("NULL callback"); - - origmeth = step->meth; - tmpmeth.kind = step->meth->kind; - tmpmeth.target_as = step->meth->target_as; - tmpmeth.param.custom = self->origparam; - step->meth = &tmpmeth; - status = self->origparam.next_step(step); - self->origparam = step->meth->param.custom; - step->meth = origmeth; - if (status != ADDRXLAT_OK) - return raise_exception(step->ctx, status); - - if (step_Init(stepobj, step)) - return NULL; - - Py_RETURN_NONE; -} - -static PyMethodDef custommeth_methods[] = { - { "cb_first_step", (PyCFunction)custommeth_first_step, - METH_VARARGS | METH_KEYWORDS, - custommeth_first_step__doc__ }, - { "cb_next_step", (PyCFunction)custommeth_next_step, - METH_VARARGS | METH_KEYWORDS, - custommeth_next_step__doc__ }, - - { NULL } -}; - -PyDoc_STRVAR(custommeth_kind__doc__, -"translation kind (always ADDRXLAT_CUSTOM)"); - -static PyGetSetDef custommeth_getset[] = { - { "kind", meth_get_kind, 0, custommeth_kind__doc__ }, - { NULL } -}; - -static PyTypeObject custommeth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".CustomMethod", /* tp_name */ - sizeof (custommeth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - custommeth__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - custommeth_methods, /* tp_methods */ - 0, /* tp_members */ - custommeth_getset, /* tp_getset */ - &meth_type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - custommeth_new, /* tp_new */ -}; - -typedef struct { - meth_HEAD - PyObject *root; -} pgtmeth_object; - -PyDoc_STRVAR(pgtmeth__doc__, -"PageTableMethod() -> page table address translation method"); - -static PyObject * -pgtmeth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - pgtmeth_object *self; - - self = (pgtmeth_object*) make_meth(type, ADDRXLAT_PGT, kwargs); - if (self) { - param_loc *loc; - - self->loc[0].len = sizeof(addrxlat_param_pgt_t); - - Py_INCREF(Py_None); - self->root = Py_None; - self->meth.param.pgt.root = *fulladdr_AsPointer(self->root); - loc = &self->loc[METH_NLOC]; - loc->ptr = NULL; - loc->off = offsetof(addrxlat_param_t, pgt.root); - loc->len = sizeof(addrxlat_fulladdr_t); - self->nloc = METH_NLOC + 1; - } - - return (PyObject*)self; -} - -static int -pgtmeth_Init(PyObject *_self, const addrxlat_meth_t *meth) -{ - pgtmeth_object *self = (pgtmeth_object*)_self; - PyObject *addr, *oldaddr; - - if (meth_Init(_self, meth)) - return -1; - - addr = fulladdr_FromPointer(self->convert, &meth->param.pgt.root); - if (!addr) - return -1; - - oldaddr = self->root; - self->root = addr; - self->loc[METH_NLOC].ptr = fulladdr_AsPointer(addr); - Py_DECREF(oldaddr); - return 0; -} - -static void -pgtmeth_dealloc(PyObject *_self) -{ - pgtmeth_object *self = (pgtmeth_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->root); - meth_dealloc(_self); -} - -static int -pgtmeth_traverse(PyObject *_self, visitproc visit, void *arg) -{ - pgtmeth_object *self = (pgtmeth_object*)_self; - Py_VISIT(self->root); - return meth_traverse(_self, visit, arg); -} - -PyDoc_STRVAR(pgtmeth_kind__doc__, -"translation kind (always ADDRXLAT_PGT)"); - -PyDoc_STRVAR(pgtmeth_pte_format__doc__, -"format of a page tabe entry (ADDRXLAT_PTE_xxx)"); - -static PyObject * -pgtmeth_get_pte_format(PyObject *_self, void *data) -{ - meth_object *self = (meth_object*)_self; - return PyInt_FromLong(self->meth.param.pgt.pf.pte_format); -} - -static int -pgtmeth_set_pte_format(PyObject *_self, PyObject *value, void *data) -{ - meth_object *self = (meth_object*)_self; - long pte_format; - - if (check_null_attr(value, "pte_format")) - return -1; - - pte_format = Number_AsLong(value); - if (PyErr_Occurred()) - return -1; - - self->meth.param.pgt.pf.pte_format = pte_format; - return 0; -} - -PyDoc_STRVAR(pgtmeth_fields__doc__, -"size of address fields in bits"); - -static PyObject * -pgtmeth_get_fields(PyObject *_self, void *data) -{ - meth_object *self = (meth_object*)_self; - const addrxlat_paging_form_t *pf = &self->meth.param.pgt.pf; - PyObject *result; - unsigned i; - - result = PyTuple_New(pf->nfields); - if (!result) - return NULL; - - for (i = 0; i < pf->nfields; ++i) { - PyObject *obj = PyInt_FromLong(pf->fieldsz[i]); - if (!obj) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, obj); - } - - return result; -} - -static int -pgtmeth_set_fields(PyObject *_self, PyObject *value, void *data) -{ - meth_object *self = (meth_object*)_self; - addrxlat_paging_form_t pf; - Py_ssize_t n; - unsigned i; - - if (check_null_attr(value, "fields")) - return -1; - - if (!PySequence_Check(value)) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a sequence", - Py_TYPE(value)->tp_name); - return -1; - } - - n = PySequence_Length(value); - if (n > ADDRXLAT_FIELDS_MAX) { - PyErr_Format(PyExc_ValueError, - "cannot have more than %d address fields", - ADDRXLAT_FIELDS_MAX); - return -1; - } - - for (i = 0; i < n; ++i) { - long bits = 0; - PyObject *obj = PySequence_GetItem(value, i); - - if (obj) { - bits = Number_AsLong(obj); - Py_DECREF(obj); - } - if (PyErr_Occurred()) - return -1; - if (bits < 0 || bits > sizeof(addrxlat_addr_t) * 8) { - PyErr_Format(PyExc_OverflowError, - "address field %u out of range", i); - return -1; - } - pf.fieldsz[i] = bits; - } - - self->meth.param.pgt.pf.nfields = i; - memcpy(self->meth.param.pgt.pf.fieldsz, pf.fieldsz, - i * sizeof(pf.fieldsz[0])); - while (i < ADDRXLAT_FIELDS_MAX) - self->meth.param.pgt.pf.fieldsz[i++] = 0; - - return 0; -} - -PyDoc_STRVAR(pgtmeth_root__doc__, -"root page table address"); - -static fulladdr_loc pgtmeth_root_loc = { - offsetof(pgtmeth_object, root), - offsetof(pgtmeth_object, loc[METH_NLOC]), - "root" -}; - -PyDoc_STRVAR(pgtmeth_pte_mask__doc__, -"page table entry mask"); - -static PyGetSetDef pgtmeth_getset[] = { - { "kind", meth_get_kind, 0, pgtmeth_kind__doc__ }, - { "root", get_fulladdr, set_fulladdr, pgtmeth_root__doc__, - &pgtmeth_root_loc }, - { "pte_mask", get_pte, set_pte, pgtmeth_pte_mask__doc__, - OFFSETOF_PTR(meth_object, meth.param.pgt.pte_mask) }, - { "pte_format", pgtmeth_get_pte_format, pgtmeth_set_pte_format, - pgtmeth_pte_format__doc__ }, - { "fields", pgtmeth_get_fields, pgtmeth_set_fields, - pgtmeth_fields__doc__ }, - { NULL } -}; - -static PyTypeObject pgtmeth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".PageTableMethod", /* tp_name */ - sizeof (pgtmeth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - pgtmeth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pgtmeth__doc__, /* tp_doc */ - pgtmeth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - pgtmeth_getset, /* tp_getset */ - &meth_type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - pgtmeth_new, /* tp_new */ -}; - -static PyObject * -lookupmeth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - meth_object *self; - - self = (meth_object*) make_meth(type, ADDRXLAT_LOOKUP, kwargs); - if (self) { - self->loc[0].len = sizeof(addrxlat_param_lookup_t); - } - - return (PyObject*)self; -} - -static void -lookupmeth_dealloc(PyObject *_self) -{ - meth_object *self = (meth_object*)_self; - if (self->meth.param.lookup.tbl) { - free(self->meth.param.lookup.tbl); - self->meth.param.lookup.tbl = NULL; - } - meth_dealloc(_self); -} - -PyDoc_STRVAR(lookupmeth__doc__, -"LookupMethod() -> table lookup address translation method"); - -PyDoc_STRVAR(lookupmeth_kind__doc__, -"translation kind (always ADDRXLAT_LOOKUP)"); - -PyDoc_STRVAR(lookupmeth_endoff__doc__, -"max address offset inside each object"); - -PyDoc_STRVAR(lookupmeth_tbl__doc__, -"lookup table"); - -static PyObject * -lookupmeth_get_tbl(PyObject *_self, void *data) -{ - meth_object *self = (meth_object*)_self; - const addrxlat_lookup_elem_t *elem; - PyObject *result; - size_t i; - - result = PyTuple_New(self->meth.param.lookup.nelem); - if (!result) - return NULL; - - for (i = 0, elem = self->meth.param.lookup.tbl; - i < self->meth.param.lookup.nelem; - ++i, ++elem) { - PyObject *tuple; - - tuple = Py_BuildValue("(KK)", - (unsigned PY_LONG_LONG)elem->orig, - (unsigned PY_LONG_LONG)elem->dest); - if (!tuple) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, tuple); - } - - return result; -} - -static int -lookupmeth_set_tbl(PyObject *_self, PyObject *value, void *data) -{ - meth_object *self = (meth_object*)_self; - PyObject *pair, *obj; - addrxlat_lookup_elem_t *tbl, *elem; - size_t i, n; - - if (!PySequence_Check(value)) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a sequence", - Py_TYPE(value)->tp_name); - return -1; - } - - n = PySequence_Length(value); - if (!n) { - tbl = NULL; - goto out; - } - - tbl = malloc(n * sizeof(addrxlat_lookup_elem_t)); - if (!tbl) { - PyErr_NoMemory(); - return -1; - } - - for (elem = tbl, i = 0; i < n; ++i, ++elem) { - pair = PySequence_GetItem(value, i); - if (!pair) - goto err_tbl; - if (!PySequence_Check(pair)) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a sequence", - Py_TYPE(pair)->tp_name); - goto err_pair; - } - if (PySequence_Length(pair) != 2) { - PyErr_SetString(PyExc_ValueError, - "Table elements must be integer pairs"); - goto err_pair; - } - - obj = PySequence_GetItem(pair, 0); - if (obj) { - elem->orig = Number_AsUnsignedLongLong(obj); - Py_DECREF(obj); - } - if (PyErr_Occurred()) - goto err_pair; - - obj = PySequence_GetItem(pair, 1); - if (obj) { - elem->dest = Number_AsUnsignedLongLong(obj); - Py_DECREF(obj); - } - if (PyErr_Occurred()) - goto err_pair; - - Py_DECREF(pair); - } - - out: - self->meth.param.lookup.nelem = n; - if (self->meth.param.lookup.tbl) - free(self->meth.param.lookup.tbl); - self->meth.param.lookup.tbl = tbl; - return 0; - - err_pair: - Py_DECREF(pair); - err_tbl: - free(tbl); - return -1; -} - -static PyGetSetDef lookupmeth_getset[] = { - { "kind", meth_get_kind, 0, lookupmeth_kind__doc__ }, - { "endoff", get_addr, set_addr, lookupmeth_endoff__doc__, - OFFSETOF_PTR(meth_object, meth.param.lookup.endoff) }, - { "tbl", lookupmeth_get_tbl, lookupmeth_set_tbl, - lookupmeth_tbl__doc__ }, - { NULL } -}; - -static PyTypeObject lookupmeth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".LookupMethod", /* tp_name */ - sizeof (meth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - lookupmeth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - lookupmeth__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - lookupmeth_getset, /* tp_getset */ - &meth_type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - lookupmeth_new, /* tp_new */ -}; - -typedef struct { - meth_HEAD - PyObject *base; -} memarrmeth_object; - -PyDoc_STRVAR(memarrmeth__doc__, -"MemoryArrayMethod() -> memory array address translation method"); - -static PyObject * -memarrmeth_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - memarrmeth_object *self; - - self = (memarrmeth_object*) make_meth(type, ADDRXLAT_MEMARR, kwargs); - if (self) { - param_loc *loc; - - self->loc[0].len = sizeof(addrxlat_param_memarr_t); - - Py_INCREF(Py_None); - self->base = Py_None; - self->meth.param.memarr.base = *fulladdr_AsPointer(self->base); - loc = &self->loc[METH_NLOC]; - loc->ptr = NULL; - loc->off = offsetof(addrxlat_param_t, memarr.base); - loc->len = sizeof(addrxlat_fulladdr_t); - self->nloc = METH_NLOC + 1; - } - - return (PyObject*)self; -} - -static int -memarrmeth_Init(PyObject *_self, const addrxlat_meth_t *meth) -{ - memarrmeth_object *self = (memarrmeth_object*)_self; - PyObject *addr, *oldaddr; - - if (meth_Init(_self, meth)) - return -1; - - addr = fulladdr_FromPointer(self->convert, &meth->param.memarr.base); - if (!addr) - return -1; - - oldaddr = self->base; - self->base = addr; - self->loc[METH_NLOC].ptr = fulladdr_AsPointer(addr); - Py_DECREF(oldaddr); - return 0; -} - -static void -memarrmeth_dealloc(PyObject *_self) -{ - memarrmeth_object *self = (memarrmeth_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->base); - meth_dealloc(_self); -} - -static int -memarrmeth_traverse(PyObject *_self, visitproc visit, void *arg) -{ - memarrmeth_object *self = (memarrmeth_object*)_self; - Py_VISIT(self->base); - return meth_traverse(_self, visit, arg); -} - -PyDoc_STRVAR(memarrmeth_kind__doc__, -"translation kind (always ADDRXLAT_MEMARR)"); - -PyDoc_STRVAR(memarrmeth_shift__doc__, -"address bit shift"); - -PyDoc_STRVAR(memarrmeth_elemsz__doc__, -"size of each array element"); - -PyDoc_STRVAR(memarrmeth_valsz__doc__, -"size of the value"); - -static PyMemberDef memarrmeth_members[] = { - { "shift", T_UINT, offsetof(meth_object, meth.param.memarr.shift), - 0, memarrmeth_shift__doc__ }, - { "elemsz", T_UINT, offsetof(meth_object, meth.param.memarr.elemsz), - 0, memarrmeth_elemsz__doc__ }, - { "valsz", T_UINT, offsetof(meth_object, meth.param.memarr.valsz), - 0, memarrmeth_valsz__doc__ }, - { NULL } -}; - -PyDoc_STRVAR(memarrmeth_base__doc__, -"base address of the translation array"); - -static fulladdr_loc memarrmeth_base_loc = { - offsetof(memarrmeth_object, base), - offsetof(memarrmeth_object, loc[METH_NLOC]), - "base" -}; - -static PyGetSetDef memarrmeth_getset[] = { - { "kind", meth_get_kind, 0, memarrmeth_kind__doc__ }, - { "base", get_fulladdr, set_fulladdr, - memarrmeth_base__doc__, &memarrmeth_base_loc }, - { NULL } -}; - -static PyTypeObject memarrmeth_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".MemoryArrayMethod", /* tp_name */ - sizeof (memarrmeth_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - memarrmeth_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - memarrmeth__doc__, /* tp_doc */ - memarrmeth_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - memarrmeth_members, /* tp_members */ - memarrmeth_getset, /* tp_getset */ - &meth_type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - memarrmeth_new, /* tp_new */ -}; - -/** Construct a Method object from an @c addrxlat_meth_t pointer. - * @param _conv TypeConvert object. - * @param meth New value as a C object, or @c NULL. - * @returns Corresponding Python object (or @c NULL on failure). - * - * This function makes a new copy of the method. - */ -static PyObject * -meth_FromPointer(PyObject *_conv, const addrxlat_meth_t *meth) -{ - convert_object *conv = (convert_object *)_conv; - PyTypeObject *type; - PyObject *args; - int (*init)(PyObject *, const addrxlat_meth_t *); - PyObject *result; - - if (!meth) - Py_RETURN_NONE; - - init = meth_Init; - switch (meth->kind) { - case ADDRXLAT_CUSTOM: - type = conv->custommeth_type; - init = custommeth_Init; - break; - - case ADDRXLAT_LINEAR: - type = conv->linearmeth_type; - break; - - case ADDRXLAT_PGT: - type = conv->pgtmeth_type; - init = pgtmeth_Init; - break; - - case ADDRXLAT_LOOKUP: - type = conv->lookupmeth_type; - break; - - case ADDRXLAT_MEMARR: - type = conv->memarrmeth_type; - init = memarrmeth_Init; - break; - - default: - type = conv->meth_type; - break; - } - - args = (type == conv->meth_type - ? Py_BuildValue("(k)", meth->kind) - : PyTuple_New(0)); - if (!args) - return NULL; - result = PyObject_Call((PyObject*)type, args, NULL); - Py_DECREF(args); - if (!result) - return NULL; - - if (init(result, meth)) - goto err; - - return result; - - err: - Py_DECREF(result); - return NULL; -} - -/** Python representation of @ref addrxlat_range_t. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - /** Range in libaddrxlat format. */ - addrxlat_range_t range; -} range_object; - -PyDoc_STRVAR(range__doc__, -"Range() -> range\n\ -\n\ -Construct an empty address range."); - -/** Construct a range object from an @c addrxlat_range_t pointer. - * @param _conv TypeConvert object. - * @param range New value as a C object. - * @returns Corresponding Python object (or @c NULL on failure). - * - * This function makes a new copy of the range. - */ -static PyObject * -range_FromPointer(PyObject *_conv, const addrxlat_range_t *range) -{ - convert_object *conv = (convert_object *)_conv; - PyTypeObject *type = conv->range_type; - PyObject *result; - - result = type->tp_alloc(type, 0); - if (!result) - return NULL; - - ((range_object*)result)->range = *range; - return result; -} - -PyDoc_STRVAR(range_meth__doc__, -"translation method for this range"); - -/** Getter for the meth attribute. - * @param self Range object - * @param data ignored - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -range_get_meth(PyObject *_self, void *data) -{ - range_object *self = (range_object*)_self; - return PyInt_FromLong(self->range.meth); -} - -/** Setter for the meth attribute. - * @param self Range object - * @param value new value (see @c SYS_METH_xxx) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -range_set_meth(PyObject *_self, PyObject *value, void *data) -{ - range_object *self = (range_object*)_self; - addrxlat_sys_meth_t meth; - - if (check_null_attr(value, "meth")) - return -1; - - meth = Number_AsLong(value); - if (PyErr_Occurred()) - return -1; - - self->range.meth = meth; - return 0; -} - -PyDoc_STRVAR(range_endoff__doc__, -"maximum offset contained in the range"); - -static PyGetSetDef range_getset[] = { - { "endoff", get_addr, set_addr, range_endoff__doc__, - OFFSETOF_PTR(range_object, range.endoff) }, - { "meth", range_get_meth, range_set_meth, range_meth__doc__ }, - { NULL } -}; - -static PyTypeObject range_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Range", /* tp_name */ - sizeof (range_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - range__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - range_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Python range object. - * @param self Range object. - * @returns Address of the embedded @c libaddrxlat_range_t, - * or @c NULL on error. - * - * The returned pointer refers to a @c libaddrxlat_range_t - * structure embedded in the Python object, i.e. the pointer is - * valid only as long as the containing Python object exists. - */ -static addrxlat_range_t * -range_AsPointer(PyObject *self) -{ - if (!PyObject_TypeCheck(self, &range_type)) { - PyErr_Format(PyExc_TypeError, "need a Range, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - return &((range_object*)self)->range; -} - -typedef struct { - PyObject_HEAD - - addrxlat_map_t *map; - - PyObject *convert; -} map_object; - -PyDoc_STRVAR(map__doc__, -"Map() -> address translation map"); - -static PyObject * -map_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - map_object *self; - - self = (map_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - self->map = get_c_pointer(kwargs); - if (!self->map) { - if (PyErr_Occurred()) - return NULL; - - self->map = addrxlat_map_new(); - if (!self->map) { - Py_DECREF(self); - return PyErr_NoMemory(); - } - } else - addrxlat_map_incref(self->map); - - Py_INCREF(convert); - self->convert = convert; - - return (PyObject*)self; -} - -static int -map_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - return c_pointer_super_init(&map_type, self, args, kwargs); -} - -/** Construct a map object from an @c addrxlat_map_t pointer. - * @param _conv TypeConvert object. - * @param map New value as a C object, or @c NULL. - * @returns corresponding Python object (or @c NULL on failure). - * - * The Python object contains a new reference to the translation map. - */ -static PyObject * -map_FromPointer(PyObject *_conv, addrxlat_map_t *map) -{ - convert_object *conv = (convert_object *)_conv; - - if (!map) - Py_RETURN_NONE; - - return object_FromPointer(conv->map_type, map); -} - -static void -map_dealloc(PyObject *_self) -{ - map_object *self = (map_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - - if (self->map) { - addrxlat_map_decref(self->map); - self->map = NULL; - } - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -map_traverse(PyObject *_self, visitproc visit, void *arg) -{ - map_object *self = (map_object*)_self; - Py_VISIT(self->convert); - return 0; -} - -static PyObject * -map_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - - if ((op == Py_EQ || op == Py_NE) && - PyObject_TypeCheck(v, &map_type) && - PyObject_TypeCheck(w, &map_type)) { - int cmp = (((map_object*)v)->map == ((map_object*)w)->map); - result = (cmp == (op == Py_EQ)) - ? Py_True - : Py_False; - } else - result = Py_NotImplemented; - - Py_INCREF(result); - return result; -} - -static Py_ssize_t -map_len(PyObject *_self) -{ - map_object *self = (map_object*)_self; - return self->map - ? addrxlat_map_len(self->map) - : 0; -} - -static PyObject * -map_item(PyObject *_self, Py_ssize_t index) -{ - map_object *self = (map_object*)_self; - const addrxlat_range_t *ranges; - Py_ssize_t n; - - n = map_len((PyObject*)self); - if (index < 0) - index = n - index; - if (index >= n) { - PyErr_SetString(PyExc_IndexError, "map index out of range"); - return NULL; - } - - ranges = addrxlat_map_ranges(self->map); - return range_FromPointer(self->convert, &ranges[index]); -} - -static PySequenceMethods map_as_sequence = { - map_len, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - map_item, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - 0, /* sq_contains */ -}; - -PyDoc_STRVAR(map_set__doc__, -"MAP.set(addr, range) -> status\n\ -\n\ -Modify map so that addresses between addr and addr+range.off\n\ -(inclusive) are mapped using range.meth."); - -static PyObject * -map_set(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - map_object *self = (map_object*)_self; - static char *keywords[] = {"addr", "range", NULL}; - unsigned long long addr; - PyObject *rangeobj; - addrxlat_range_t *range; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "KO:set", - keywords, &addr, &rangeobj)) - return NULL; - - range = range_AsPointer(rangeobj); - if (!range) - return NULL; - - status = addrxlat_map_set(self->map, addr, range); - return PyInt_FromLong(status); -} - -PyDoc_STRVAR(map_search__doc__, -"MAP.search(addr) -> meth\n\ -\n\ -Find the translation method for the given address."); - -static PyObject * -map_search(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - map_object *self = (map_object*)_self; - static char *keywords[] = {"addr", NULL}; - unsigned long long addr; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:search", - keywords, &addr)) - return NULL; - - return PyInt_FromLong(addrxlat_map_search(self->map, addr)); -} - -PyDoc_STRVAR(map_copy__doc__, -"M.copy() -> map\n\ -\n\ -Return a shallow copy of a translation map."); - -static PyObject * -map_copy(PyObject *_self, PyObject *args) -{ - map_object *self = (map_object*)_self; - addrxlat_map_t *map; - PyObject *result; - - map = addrxlat_map_copy(self->map); - if (!map) - return PyErr_NoMemory(); - - result = map_FromPointer(self->convert, map); - addrxlat_map_decref(map); - return result; -} - -static PyMethodDef map_methods[] = { - { "set", (PyCFunction)map_set, METH_VARARGS | METH_KEYWORDS, - map_set__doc__ }, - { "search", (PyCFunction)map_search, METH_VARARGS | METH_KEYWORDS, - map_search__doc__ }, - { "copy", map_copy, METH_NOARGS, - map_copy__doc__ }, - { NULL } -}; - -static PyMemberDef map_members[] = { - { "convert", T_OBJECT, offsetof(map_object, convert), 0, - attr_convert__doc__ }, - { NULL } -}; - -static PyTypeObject map_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Map", /* tp_name */ - sizeof (map_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - map_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &map_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - map__doc__, /* tp_doc */ - map_traverse, /* tp_traverse */ - 0, /* tp_clear */ - map_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - map_methods, /* tp_methods */ - map_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - map_init, /* tp_init */ - 0, /* tp_alloc */ - map_new, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Python map object. - * @param self Map object. - * @returns Associated @c libaddrxlat_map_t, - * @c NULL if @c self is None or on failure. - * - * This function does not increment the reference count of the returned - * C object. It is assumed that the caller holds a reference to the Python - * object, which in turn holds a reference to the C object. - * - * Since all possible return values error are valid, error conditions - * must be detected by calling @c PyErr_Occurred. - */ -static addrxlat_map_t * -map_AsPointer(PyObject *self) -{ - if (self == Py_None) - return NULL; - - if (!PyObject_TypeCheck(self, &map_type)) { - PyErr_Format(PyExc_TypeError, - "need a Map or None, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - return ((map_object*)self)->map; -} - -typedef struct { - PyObject_HEAD - - addrxlat_sys_t *sys; - - PyObject *convert; -} sys_object; - -PyDoc_STRVAR(sys__doc__, -"System() -> address translation system"); - -static PyObject * -sys_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - sys_object *self; - - self = (sys_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - self->sys = get_c_pointer(kwargs); - if (!self->sys) { - if (PyErr_Occurred()) - return NULL; - - self->sys = addrxlat_sys_new(); - if (!self->sys) { - Py_DECREF(self); - return PyErr_NoMemory(); - } - } else - addrxlat_sys_incref(self->sys); - - Py_INCREF(convert); - self->convert = convert; - - return (PyObject*)self; -} - -static int -sys_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - return c_pointer_super_init(&sys_type, self, args, kwargs); -} - -/** Construct a sys object from an @c addrxlat_sys_t pointer. - * @param _conv TypeConvert object. - * @param sys New value as a C object, or @c NULL. - * @returns Corresponding Python object (or @c NULL on failure). - * - * The Python object contains a new reference to the translation system. - */ -static PyObject * -sys_FromPointer(PyObject *_conv, addrxlat_sys_t *sys) -{ - convert_object *conv = (convert_object *)_conv; - - if (!sys) - Py_RETURN_NONE; - - return object_FromPointer(conv->sys_type, sys); -} - -static void -sys_dealloc(PyObject *_self) -{ - sys_object *self = (sys_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - - if (self->sys) { - addrxlat_sys_decref(self->sys); - self->sys = NULL; - } - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -sys_traverse(PyObject *_self, visitproc visit, void *arg) -{ - sys_object *self = (sys_object*)_self; - Py_VISIT(self->convert); - return 0; -} - -static PyObject * -sys_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - - if ((op == Py_EQ || op == Py_NE) && - PyObject_TypeCheck(v, &sys_type) && - PyObject_TypeCheck(w, &sys_type)) { - int cmp = (((sys_object*)v)->sys == ((sys_object*)w)->sys); - result = (cmp == (op == Py_EQ)) - ? Py_True - : Py_False; - } else - result = Py_NotImplemented; - - Py_INCREF(result); - return result; -} - -PyDoc_STRVAR(sys_os_init__doc__, -"SYS.os_init(ctx, arch=None, os_type=None, version_code=None, phys_bits=None, virt_bits=None, page_shift=None, phys_base=None, rootpgt=None, xen_p2m_mfn=None, xen_xlat=None) -> status\n\ -\n\ -Set up a translation system for a pre-defined operating system."); - -static PyObject * -sys_os_init(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - sys_object *self = (sys_object*)_self; - static char *keywords[] = { - "ctx", - "arch", - "os_type", - "version_code", - "phys_bits", - "virt_bits", - "page_shift", - "phys_base", - "rootpgt", - "xen_p2m_mfn", - "xen_xlat", - NULL - }; - PyObject *ctxobj; - PyObject *arch, *type, *ver, *page_shift, *phys_base, - *rootpgt, *xen_p2m_mfn, *xen_xlat, *phys_bits, *virt_bits; - addrxlat_ctx_t *ctx; - addrxlat_opt_t opts[ADDRXLAT_OPT_NUM], *p; - addrxlat_status status; - - arch = type = ver = page_shift = phys_base = rootpgt = - xen_p2m_mfn = xen_xlat = phys_bits = virt_bits = Py_None; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "O|OOOOOOOOOO:os_init", keywords, - &ctxobj, &arch, &type, &ver, &phys_bits, &virt_bits, - &page_shift, &phys_base, &rootpgt, &xen_p2m_mfn, - &xen_xlat)) - return NULL; - - ctx = ctx_AsPointer(ctxobj); - if (!ctx) - return NULL; - - p = opts; - - if (arch != Py_None) { - const char *str = Text_AsUTF8(arch); - if (!str) - return NULL; - addrxlat_opt_arch(p, str); - ++p; - } - if (type != Py_None) { - const char *str = Text_AsUTF8(type); - if (!str) - return NULL; - addrxlat_opt_os_type(p, str); - ++p; - } - if (ver != Py_None) { - addrxlat_opt_version_code( - p, Number_AsUnsignedLongLong(ver)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (phys_bits != Py_None) { - addrxlat_opt_phys_bits( - p, Number_AsUnsignedLongLong(phys_bits)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (virt_bits != Py_None) { - addrxlat_opt_virt_bits( - p, Number_AsUnsignedLongLong(virt_bits)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (page_shift != Py_None) { - addrxlat_opt_page_shift( - p, Number_AsUnsignedLongLong(page_shift)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (phys_base != Py_None) { - addrxlat_opt_phys_base( - p, Number_AsUnsignedLongLong(phys_base)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (rootpgt != Py_None) { - addrxlat_fulladdr_t *faddr = fulladdr_AsPointer(rootpgt); - if (!faddr) - return NULL; - addrxlat_opt_rootpgt(p, faddr); - ++p; - } - if (xen_p2m_mfn != Py_None) { - addrxlat_opt_xen_p2m_mfn( - p, Number_AsUnsignedLongLong(xen_p2m_mfn)); - if (PyErr_Occurred()) - return NULL; - ++p; - } - if (xen_xlat != Py_None && Number_AsLong(xen_xlat)) { - addrxlat_opt_xen_xlat(p, 1); - ++p; - } - - status = addrxlat_sys_os_init(self->sys, ctx, p - opts, opts); - return ctx_status_result(ctxobj, status); -} - -PyDoc_STRVAR(sys_set_map__doc__, -"SYS.set_map(idx, map)\n\ -\n\ -Explicitly set the given translation map of a translation system.\n\ -See SYS_MAP_xxx for valid values of idx."); - -static PyObject * -sys_set_map(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - sys_object *self = (sys_object*)_self; - static char *keywords[] = { "idx", "map", NULL }; - unsigned long idx; - PyObject *mapobj; - addrxlat_map_t *map; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "kO:set_map", - keywords, &idx, &mapobj)) - return NULL; - - if (idx >= ADDRXLAT_SYS_MAP_NUM) { - PyErr_SetString(PyExc_IndexError, - "system map index out of range"); - return NULL; - } - - map = map_AsPointer(mapobj); - if (PyErr_Occurred()) - return NULL; - - addrxlat_sys_set_map(self->sys, idx, map); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(sys_get_map__doc__, -"SYS.get_map(idx) -> Map or None\n\ -\n\ -Get the given translation map of a translation system.\n\ -See SYS_MAP_xxx for valid values of idx."); - -static PyObject * -sys_get_map(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - sys_object *self = (sys_object*)_self; - static char *keywords[] = { "idx", NULL }; - unsigned long idx; - addrxlat_map_t *map; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k:get_map", - keywords, &idx)) - return NULL; - - if (idx >= ADDRXLAT_SYS_MAP_NUM) { - PyErr_SetString(PyExc_IndexError, - "system map index out of range"); - return NULL; - } - - map = addrxlat_sys_get_map(self->sys, idx); - return map_FromPointer(self->convert, map); -} - -PyDoc_STRVAR(sys_set_meth__doc__, -"SYS.set_meth(idx, meth)\n\ -\n\ -Explicitly set a pre-defined translation method of a translation\n\ -system.\n\ -See SYS_METH_xxx for valid values of idx."); - -static PyObject * -sys_set_meth(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - sys_object *self = (sys_object*)_self; - static char *keywords[] = { "idx", "meth", NULL }; - unsigned long idx; - PyObject *methobj; - addrxlat_meth_t *meth; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "kO:set_meth", - keywords, &idx, &methobj)) - return NULL; - - if (idx >= ADDRXLAT_SYS_METH_NUM) { - PyErr_SetString(PyExc_IndexError, - "system meth index out of range"); - return NULL; - } - - meth = meth_AsPointer(methobj); - if (PyErr_Occurred()) - return NULL; - - addrxlat_sys_set_meth(self->sys, idx, meth); - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(sys_get_meth__doc__, -"SYS.get_meth(idx) -> Method\n\ -\n\ -Get the given translation method of a translation system.\n\ -See SYS_METH_xxx for valid values of idx."); - -static PyObject * -sys_get_meth(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - sys_object *self = (sys_object*)_self; - static char *keywords[] = { "idx", NULL }; - unsigned long idx; - const addrxlat_meth_t *meth; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k:get_meth", - keywords, &idx)) - return NULL; - - if (idx >= ADDRXLAT_SYS_METH_NUM) { - PyErr_SetString(PyExc_IndexError, - "system method index out of range"); - return NULL; - } - - meth = addrxlat_sys_get_meth(self->sys, idx); - return meth_FromPointer(self->convert, meth); -} - -static PyMethodDef sys_methods[] = { - { "os_init", (PyCFunction)sys_os_init, METH_VARARGS | METH_KEYWORDS, - sys_os_init__doc__ }, - { "set_map", (PyCFunction)sys_set_map, METH_VARARGS | METH_KEYWORDS, - sys_set_map__doc__ }, - { "get_map", (PyCFunction)sys_get_map, METH_VARARGS | METH_KEYWORDS, - sys_get_map__doc__ }, - { "set_meth", (PyCFunction)sys_set_meth, METH_VARARGS | METH_KEYWORDS, - sys_set_meth__doc__ }, - { "get_meth", (PyCFunction)sys_get_meth, METH_VARARGS | METH_KEYWORDS, - sys_get_meth__doc__ }, - { NULL } -}; - -static PyMemberDef sys_members[] = { - { "convert", T_OBJECT, offsetof(sys_object, convert), 0, - attr_convert__doc__ }, - { NULL } -}; - -static PyTypeObject sys_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".System", /* tp_name */ - sizeof (sys_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - sys_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_sysping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - sys__doc__, /* tp_doc */ - sys_traverse, /* tp_traverse */ - 0, /* tp_clear */ - sys_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - sys_methods, /* tp_methods */ - sys_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - sys_init, /* tp_init */ - 0, /* tp_alloc */ - sys_new, /* tp_new */ -}; - - -/** Get the libaddrxlat representation of a Python sys object. - * @param self System object. - * @returns Associated @c libaddrxlat_sys_t, - * @c NULL if @c self is None or on failure. - * - * Since all possible return values error are valid, error conditions - * must be detected by calling @c PyErr_Occurred. - */ -static addrxlat_sys_t * -sys_AsPointer(PyObject *self) -{ - if (self == Py_None) - return NULL; - - if (!PyObject_TypeCheck(self, &sys_type)) { - PyErr_Format(PyExc_TypeError, - "need a System or None, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - return ((sys_object*)self)->sys; -} - -static int -replace_sys(PyObject **psysobj, addrxlat_sys_t **psys, PyObject *newval) -{ - addrxlat_sys_t *sys; - PyObject *oldval; - - sys = sys_AsPointer(newval); - if (PyErr_Occurred()) - return -1; - - if (sys) - addrxlat_sys_incref(sys); - if (*psys) - addrxlat_sys_decref(*psys); - *psys = sys; - - Py_INCREF(newval); - oldval = *psysobj; - *psysobj = newval; - Py_XDECREF(oldval); - return 0; -} - -/** Number of parameter locations in @ref step_object. */ -#define STEP_NLOC 2 - -/** Python representation of @ref addrxlat_step_t. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - /** Translation step in libaddrxlat format. */ - addrxlat_step_t step; - - /** Translation context. */ - PyObject *ctx; - /** Translation system. */ - PyObject *sys; - /** Translation method. */ - PyObject *meth; - /** FullAddress object for @c base. */ - PyObject *base; - - /** Location configuration for @c step. */ - param_loc loc[STEP_NLOC]; - - PyObject *convert; -} step_object; - -/** Create a new Step object with. - * @param type Python type of the new object. - * @param conv Type converter object. - * @returns New object, or @c NULL on failure. - * - * This is the common code for brand new objects and objects created from - * a C pointer. - */ -static step_object * -step_new_common(PyTypeObject *type, PyObject *conv) -{ - step_object *self; - - self = (step_object*) type->tp_alloc(type, 0); - if (self) { - self->loc[0].ptr = &self->step; - self->loc[0].off = 0; - self->loc[0].len = sizeof(addrxlat_step_t); - - self->loc[1].ptr = NULL; - self->loc[1].off = offsetof(addrxlat_step_t, base); - self->loc[1].len = sizeof(addrxlat_fulladdr_t); - - Py_INCREF(conv); - self->convert = conv; - } - return self; -} - -PyDoc_STRVAR(step__doc__, -"Step(ctx) -> step"); - -/** Create a new, uninitialized step object. - * @param type step type - * @param args positional arguments - * @param kwargs keyword arguments - * @returns new step object, or @c NULL on failure - */ -static PyObject * -step_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - static const char *keywords[] = {"ctx", NULL}; - step_object *self; - PyObject *ctxobj; - - if (fetch_args(keywords, 1, &args, &kwargs, &ctxobj)) - return NULL; - Py_DECREF(args); - Py_XDECREF(kwargs); - if (!ctxobj) - return NULL; - - self = step_new_common(type, convert); - if (!self) - return NULL; - - if (replace_ctx(&self->ctx, &self->step.ctx, ctxobj)) { - Py_DECREF(self); - return NULL; - } - - Py_INCREF(Py_None); - self->base = Py_None; - - return (PyObject*)self; -} - -/** Construct a step object from an @c addrxlat_step_t pointer. - * @param conv TypeConvert object. - * @param step New value as a C object. - * @returns Corresponding Python object (or @c NULL on failure). - * - * This function makes a new copy of the step. - */ -static PyObject * -step_FromPointer(PyObject *conv, const addrxlat_step_t *step) -{ - PyTypeObject *type = ((convert_object *)conv)->step_type; - PyObject *result; - - result = (PyObject*) step_new_common(type, conv); - if (!result) - return NULL; - - if (step_Init(result, step)) { - Py_DECREF(result); - return NULL; - } - - return result; -} - -PyDoc_STRVAR(step_base__doc__, -"base address for next translation step"); - -static fulladdr_loc step_base_loc = { - offsetof(step_object, base), - offsetof(step_object, loc[1]), - "base" -}; - -/** Initialize a Step object using an C @c addrxlat_step_t pointer. - * @param _self Step object. - * @param step New value as a C object. - * @returns Zero on success, -1 otherwise. - */ -static int -step_Init(PyObject *_self, const addrxlat_step_t *step) -{ - step_object *self = (step_object *)_self; - PyObject *obj; - int result; - - obj = fulladdr_FromPointer(self->convert, &step->base); - if (!obj) - return -1; - result = set_fulladdr((PyObject*)self, obj, &step_base_loc); - Py_DECREF(obj); - if (result) - return result; - - obj = ctx_FromPointer(self->convert, step->ctx); - if (!obj) - return -1; - if (replace_ctx(&self->ctx, &self->step.ctx, obj)) - return -1; - - obj = sys_FromPointer(self->convert, step->sys); - if (!obj) - return -1; - if (replace_sys(&self->sys, &self->step.sys, obj)) - return -1; - - loc_scatter(self->loc, STEP_NLOC, step); - - return 0; -} - -static void -step_dealloc(PyObject *_self) -{ - step_object *self = (step_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - - if (self->step.ctx) { - addrxlat_ctx_decref(self->step.ctx); - self->step.ctx = NULL; - } - Py_XDECREF(self->ctx); - - if (self->step.sys) { - addrxlat_sys_decref(self->step.sys); - self->step.sys = NULL; - } - Py_XDECREF(self->sys); - - Py_XDECREF(self->meth); - Py_XDECREF(self->base); - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -step_traverse(PyObject *_self, visitproc visit, void *arg) -{ - step_object *self = (step_object*)_self; - Py_VISIT(self->ctx); - Py_VISIT(self->sys); - Py_VISIT(self->meth); - Py_VISIT(self->base); - Py_VISIT(self->convert); - return 0; -} - -PyDoc_STRVAR(step_ctx__doc__, -"translation context for the next step"); - -/** Setter for the ctx type. - * @param self any object - * @param value new value (a ctx object) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -step_set_ctx(PyObject *_self, PyObject *value, void *data) -{ - step_object *self = (step_object*)_self; - - if (check_null_attr(value, "ctx")) - return -1; - - return replace_ctx(&self->ctx, &self->step.ctx, value); -} - -PyDoc_STRVAR(step_sys__doc__, -"translation system for the next step"); - -/** Setter for the sys type. - * @param self any object - * @param value new value (a sys object) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -step_set_sys(PyObject *_self, PyObject *value, void *data) -{ - step_object *self = (step_object*)_self; - - if (check_null_attr(value, "sys")) - return -1; - - return replace_sys(&self->sys, &self->step.sys, value); -} - -PyDoc_STRVAR(step_meth__doc__, -"translation method for the next step"); - -/** Setter for the meth attribute. - * @param self any object - * @param value new value (a Method object) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -step_set_meth(PyObject *_self, PyObject *value, void *data) -{ - step_object *self = (step_object*)_self; - addrxlat_meth_t *meth; - PyObject *oldval; - - if (check_null_attr(value, "meth")) - return -1; - - meth = meth_AsPointer(value); - if (PyErr_Occurred()) - return -1; - self->step.meth = meth; - Py_INCREF(value); - oldval = self->meth; - self->meth = value; - Py_XDECREF(oldval); - - return 0; -} - -PyDoc_STRVAR(step_raw__doc__, -"raw value from last step"); - -/** Getter for the raw attribute. - * @param _self step object - * @param data ignored - * @returns PyLong object (or @c NULL on failure) - */ -static PyObject * -step_get_raw(PyObject *_self, void *data) -{ - step_object *self = (step_object*)_self; - const addrxlat_lookup_elem_t *elem; - - if (!self->step.meth) - Py_RETURN_NONE; - - switch (self->step.meth->kind) { - case ADDRXLAT_PGT: - return PyLong_FromUnsignedLongLong(self->step.raw.pte); - - case ADDRXLAT_LOOKUP: - elem = self->step.raw.elem; - return Py_BuildValue("(KK)", - (unsigned PY_LONG_LONG)elem->orig, - (unsigned PY_LONG_LONG)elem->dest); - - case ADDRXLAT_MEMARR: - return PyLong_FromUnsignedLongLong(self->step.raw.addr); - - default: - Py_RETURN_NONE; - } -} - -/** Setter for the raw attribute. - * @param _self step object - * @param value new value (a @c PyLong or @c PyInt) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -step_set_raw(PyObject *_self, PyObject *value, void *data) -{ - step_object *self = (step_object*)_self; - - if (self->step.meth) { - addrxlat_pte_t pte; - addrxlat_addr_t addr; - - switch (self->step.meth->kind) { - case ADDRXLAT_PGT: - pte = Number_AsUnsignedLongLong(value); - if (PyErr_Occurred()) - return -1; - self->step.raw.pte = pte; - return 0; - - case ADDRXLAT_MEMARR: - addr = Number_AsUnsignedLongLong(value); - if (PyErr_Occurred()) - return -1; - self->step.raw.addr = addr; - return 0; - - default: - break; - } - } - - PyErr_SetString(PyExc_TypeError, - "attribute cannot be changed for this method"); - return -1; -} - -PyDoc_STRVAR(step_idx__doc__, -"size of address idx in bits"); - -/** Getter for the idx attribute. - * @param _self step object - * @param data ignored - * @returns PyTuple object (or @c NULL on failure) - */ -static PyObject * -step_get_idx(PyObject *_self, void *data) -{ - step_object *self = (step_object*)_self; - PyObject *result; - unsigned i; - - result = PyTuple_New(ADDRXLAT_FIELDS_MAX + 1); - if (!result) - return NULL; - - for (i = 0; i < ADDRXLAT_FIELDS_MAX + 1; ++i) { - PyObject *obj; - obj = PyLong_FromUnsignedLongLong(self->step.idx[i]); - if (!obj) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, obj); - } - - return result; -} - -/** Setter for the idx attribute. - * @param _self step object - * @param value new value (a sequence of addresses) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -step_set_idx(PyObject *_self, PyObject *value, void *data) -{ - step_object *self = (step_object*)_self; - addrxlat_addr_t idx[ADDRXLAT_FIELDS_MAX + 1]; - Py_ssize_t n; - unsigned i; - - if (check_null_attr(value, "idx")) - return -1; - - if (!PySequence_Check(value)) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a sequence", - Py_TYPE(value)->tp_name); - return -1; - } - - n = PySequence_Length(value); - if (n > ADDRXLAT_FIELDS_MAX + 1) { - PyErr_Format(PyExc_ValueError, - "cannot have more than %d indices", - ADDRXLAT_FIELDS_MAX + 1); - return -1; - } - - for (i = 0; i < n; ++i) { - unsigned long long tmp = 0; - PyObject *obj = PySequence_GetItem(value, i); - - if (obj) { - tmp = Number_AsUnsignedLongLong(obj); - Py_DECREF(obj); - } - if (PyErr_Occurred()) - return -1; - idx[i] = tmp; - } - memcpy(self->step.idx, idx, n * sizeof(idx[0])); - while (i < ADDRXLAT_FIELDS_MAX) - self->step.idx[i++] = 0; - - return 0; -} - -static PyGetSetDef step_getset[] = { - { "ctx", get_object, step_set_ctx, step_ctx__doc__, - OFFSETOF_PTR(step_object, ctx) }, - { "sys", get_object, step_set_sys, step_sys__doc__, - OFFSETOF_PTR(step_object, sys) }, - { "meth", get_object, step_set_meth, step_meth__doc__, - OFFSETOF_PTR(step_object, meth) }, - { "base", get_fulladdr, set_fulladdr, step_base__doc__, - &step_base_loc }, - { "raw", step_get_raw, step_set_raw, - step_raw__doc__ }, - { "idx", step_get_idx, step_set_idx, - step_idx__doc__ }, - { NULL } -}; - -PyDoc_STRVAR(step_remain__doc__, -"remaining steps"); - -PyDoc_STRVAR(step_elemsz__doc__, -"size of the indexed element"); - -static PyMemberDef step_members[] = { - { "convert", T_OBJECT, offsetof(step_object, convert), 0, - attr_convert__doc__ }, - { "remain", T_USHORT, offsetof(step_object, step.remain), - 0, step_remain__doc__ }, - { "elemsz", T_UINT, offsetof(step_object, step.elemsz), - 0, step_elemsz__doc__ }, - { NULL } -}; - -PyDoc_STRVAR(step_launch__doc__, -"STEP.launch(addr) -> status\n\ -\n\ -Make the first translation step (launch a translation)."); - -/** Wrapper for @ref addrxlat_launch - * @param _self step object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns status code (or @c NULL on failure) - */ -static PyObject * -step_launch(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - step_object *self = (step_object*)_self; - static char *keywords[] = { "addr", NULL }; - unsigned long long addr; - addrxlat_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:launch", - keywords, &addr)) - return NULL; - - status = addrxlat_launch(&self->step, addr); - step_Init((PyObject*)self, &self->step); - return ctx_status_result(self->ctx, status); -} - -PyDoc_STRVAR(step_step__doc__, -"STEP.step() -> status\n\ -\n\ -Perform one translation step."); - -/** Wrapper for @ref addrxlat_step - * @param _self step object - * @param args ignored - * @returns status code (or @c NULL on failure) - */ -static PyObject * -step_step(PyObject *_self, PyObject *args) -{ - step_object *self = (step_object*)_self; - addrxlat_status status; - - status = addrxlat_step(&self->step); - step_Init((PyObject*)self, &self->step); - return ctx_status_result(self->ctx, status); -} - -PyDoc_STRVAR(step_walk__doc__, -"STEP.walk() -> status\n\ -\n\ -Perform one complete address translation."); - -/** Wrapper for @ref addrxlat_walk - * @param _self step object - * @param args ignored - * @returns status code (or @c NULL on failure) - */ -static PyObject * -step_walk(PyObject *_self, PyObject *args) -{ - step_object *self = (step_object*)_self; - addrxlat_status status; - - status = addrxlat_walk(&self->step); - return ctx_status_result(self->ctx, status); -} - -static PyMethodDef step_methods[] = { - { "launch", (PyCFunction)step_launch, METH_VARARGS | METH_KEYWORDS, - step_launch__doc__ }, - { "step", step_step, METH_NOARGS, step_step__doc__ }, - { "walk", step_walk, METH_NOARGS, step_walk__doc__ }, - { NULL } -}; - -static PyTypeObject step_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Step", /* tp_name */ - sizeof (step_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - step_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - step__doc__, /* tp_doc */ - step_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - step_methods, /* tp_methods */ - step_members, /* tp_members */ - step_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - step_new, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Python step object. - * @param self Step object. - * @returns Address of the embedded @c libaddrxlat_step_t, - * or @c NULL on error. - * - * The returned pointer refers to a @c libaddrxlat_step_t - * structure embedded in the Python object, i.e. the pointer is - * valid only as long as the containing Python object exists. - */ -static addrxlat_step_t * -step_AsPointer(PyObject *self) -{ - step_object *stepobj; - - if (!PyObject_TypeCheck(self, &step_type)) { - PyErr_Format(PyExc_TypeError, "need a Step, not '%.200s'", - Py_TYPE(self)->tp_name); - return NULL; - } - - stepobj = (step_object*)self; - loc_gather(stepobj->loc, STEP_NLOC, &stepobj->step); - return &stepobj->step; -} - -/** Python representation of @ref addrxlat_op_t. - */ -typedef struct { - /** Standard Python object header. */ - PyObject_HEAD - /** Translation context. */ - PyObject *ctx; - /** Translation system. */ - PyObject *sys; - /** Translation op in libaddrxlat format. */ - addrxlat_op_ctl_t opctl; - /** Result of the last callback. */ - PyObject *result; - - PyObject *convert; -} op_object; - -/** Operation callback wrapper */ -static addrxlat_status -cb_op(void *data, const addrxlat_fulladdr_t *addr) -{ - op_object *self = (op_object*)data; - PyObject *addrobj; - PyObject *result; - - addrobj = fulladdr_FromPointer(self->convert, addr); - if (!addrobj) - return ctx_error_status((ctx_object*)self->ctx); - - result = PyObject_CallMethod((PyObject*)self, "callback", - "O", addrobj); - Py_XDECREF(self->result); - if (!result) { - Py_INCREF(Py_None); - self->result = Py_None; - return ctx_error_status((ctx_object*)self->ctx); - } - self->result = result; - - return ADDRXLAT_OK; -} - -PyDoc_STRVAR(op__doc__, -"Operator(ctx) -> op\n\ -\n\ -Base class for generic addrxlat operations."); - -/** Create a new, uninitialized op object. - * @param type op type - * @param args positional arguments - * @param kwargs keyword arguments - * @returns new op object, or @c NULL on failure - */ -static PyObject * -op_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - static const char *keywords[] = {"ctx", NULL}; - op_object *self; - PyObject *ctxobj; - - if (fetch_args(keywords, 1, &args, &kwargs, &ctxobj)) - return NULL; - Py_DECREF(args); - Py_XDECREF(kwargs); - if (!ctxobj) - return NULL; - - self = (op_object*) type->tp_alloc(type, 0); - if (!self) - return NULL; - - if (replace_ctx(&self->ctx, &self->opctl.ctx, ctxobj)) { - Py_DECREF(self); - return NULL; - } - - self->opctl.op = cb_op; - self->opctl.data = self; - - Py_INCREF(convert); - self->convert = convert; - - return (PyObject*)self; -} - -/** Construct a op object from an @c addrxlat_op_ctl_t pointer. - * @param _conv TypeConvert object. - * @param opctl New value as a C object. - * @returns Corresponding Python object (or @c NULL on failure). - * - * This function makes a new copy of the op. - */ -static PyObject * -op_FromPointer(PyObject *_conv, const addrxlat_op_ctl_t *opctl) -{ - convert_object *conv = (convert_object *)_conv; - PyTypeObject *type = conv->op_type; - PyObject *result; - - result = type->tp_alloc(type, 0); - if (!result) - return NULL; - Py_INCREF(conv); - ((op_object*)result)->convert = (PyObject*)conv; - - if (op_Init(result, opctl)) { - Py_DECREF(result); - return NULL; - } - - return result; -} - -/** Initialize an Operator object using an C @c addrxlat_op_ctl_t pointer. - * @param _self Operator object. - * @param opctl New value as a C object. - * @returns Zero on success, -1 otherwise. - */ -static int -op_Init(PyObject *_self, const addrxlat_op_ctl_t *opctl) -{ - op_object *self = (op_object *)_self; - PyObject *obj; - - obj = ctx_FromPointer(self->convert, opctl->ctx); - if (!obj) - return -1; - if (replace_ctx(&self->ctx, &self->opctl.ctx, obj)) - return -1; - - obj = sys_FromPointer(self->convert, opctl->sys); - if (!obj) - return -1; - if (replace_sys(&self->sys, &self->opctl.sys, obj)) - return -1; - - self->opctl = *opctl; - return 0; -} - -static void -op_dealloc(PyObject *_self) -{ - op_object *self = (op_object*)_self; - - PyObject_GC_UnTrack(_self); - Py_XDECREF(self->convert); - - if (self->opctl.ctx) { - addrxlat_ctx_decref(self->opctl.ctx); - self->opctl.ctx = NULL; - } - Py_XDECREF(self->ctx); - - if (self->opctl.sys) { - addrxlat_sys_decref(self->opctl.sys); - self->opctl.sys = NULL; - } - Py_XDECREF(self->sys); - - Py_XDECREF(self->result); - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -op_traverse(PyObject *_self, visitproc visit, void *arg) -{ - op_object *self = (op_object*)_self; - Py_VISIT(self->ctx); - Py_VISIT(self->sys); - Py_VISIT(self->result); - Py_VISIT(self->convert); - return 0; -} - -static PyObject * -op_call(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - op_object *self = (op_object*)_self; - static char *keywords[] = {"addr", NULL}; - PyObject *addrobj; - const addrxlat_fulladdr_t *addr; - addrxlat_status status; - PyObject *result; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:Operator", - keywords, &addrobj)) - return NULL; - - addr = fulladdr_AsPointer(addrobj); - if (!addr) - return NULL; - - status = addrxlat_op(&self->opctl, addr); - result = ctx_status_result(self->ctx, status); - if (result) { - result = Py_BuildValue("(NN)", result, self->result); - self->result = NULL; - } - return result; -} - -PyDoc_STRVAR(op_ctx__doc__, -"translation context"); - -/** Setter for the ctx type. - * @param self any object - * @param value new value (a ctx object) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -op_set_ctx(PyObject *_self, PyObject *value, void *data) -{ - op_object *self = (op_object*)_self; - - if (check_null_attr(value, "ctx")) - return -1; - - return replace_ctx(&self->ctx, &self->opctl.ctx, value); -} - -PyDoc_STRVAR(op_sys__doc__, -"translation system"); - -/** Setter for the sys type. - * @param self any object - * @param value new value (a sys object) - * @param data ignored - * @returns zero on success, -1 otherwise - */ -static int -op_set_sys(PyObject *_self, PyObject *value, void *data) -{ - op_object *self = (op_object*)_self; - - if (check_null_attr(value, "sys")) - return -1; - - return replace_sys(&self->sys, &self->opctl.sys, value); -} - -static PyGetSetDef op_getset[] = { - { "ctx", get_object, op_set_ctx, op_ctx__doc__, - OFFSETOF_PTR(op_object, ctx) }, - { "sys", get_object, op_set_sys, op_sys__doc__, - OFFSETOF_PTR(op_object, sys) }, - { NULL } -}; - -PyDoc_STRVAR(op_caps__doc__, -"operation capabilities"); - -static PyMemberDef op_members[] = { - { "convert", T_OBJECT, offsetof(op_object, convert), 0, - attr_convert__doc__ }, - { "caps", T_ULONG, offsetof(op_object, opctl.caps), - 0, op_caps__doc__ }, - { NULL } -}; - -PyDoc_STRVAR(op_callback__doc__, -"operation callback"); - -/** Getter for the sys attribute. - * @param self op object - * @param args ignored - * @returns None - */ -static PyObject * -op_callback(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - Py_RETURN_NONE; -} - -static PyMethodDef op_methods[] = { - { "callback", (PyCFunction)op_callback, METH_VARARGS, - op_callback__doc__ }, - { NULL } -}; - -static PyTypeObject op_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".Operator", /* tp_name */ - sizeof (op_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - op_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - op_call, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - op__doc__, /* tp_doc */ - op_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - op_methods, /* tp_methods */ - op_members, /* tp_members */ - op_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - op_new, /* tp_new */ -}; - -/** Get the libaddrxlat representation of a Python op object. - * @param value a Python op object - * @returns address of the embedded @c libaddrxlat_op_ctl_t, - * or @c NULL on error - * - * The returned pointer refers to a @c libaddrxlat_op_ctl_t - * structure embedded in the Python object, i.e. the pointer is - * valid only as long as the containing Python object exists. - */ -static addrxlat_op_ctl_t * -op_AsPointer(PyObject *value) -{ - if (!PyObject_TypeCheck(value, &op_type)) { - PyErr_Format(PyExc_TypeError, "need an Operator, not '%.200s'", - Py_TYPE(value)->tp_name); - return NULL; - } - - return &((op_object*)value)->opctl; -} - -PyDoc_STRVAR(_addrxlat_strerror__doc__, -"strerror(status) -> error message\n\ -\n\ -Return the string describing a given error status."); - -/** Wrapper for @ref addrxlat_strerror - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns error message string (or @c NULL on failure) - */ -static PyObject * -_addrxlat_strerror(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"status", NULL}; - long status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", - keywords, &status)) - return NULL; - - return Text_FromUTF8(addrxlat_strerror(status)); -} - -PyDoc_STRVAR(_addrxlat_addrspace_name__doc__, -"addrspace_name(addrspace) -> name\n\ -\n\ -Return the name of an address space constant."); - -/** Wrapper for @ref addrxlat_addrspace_name - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns error message string (or @c NULL on failure) - */ -static PyObject * -_addrxlat_addrspace_name(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"addrspace", NULL}; - long addrspace; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", - keywords, &addrspace)) - return NULL; - - return Text_FromUTF8(addrxlat_addrspace_name(addrspace)); -} - -PyDoc_STRVAR(_addrxlat_CAPS__doc__, -"CAPS(addrspace) -> capability bitmask\n\ -\n\ -Translate an address space constant into a capability bitmask."); - -/** Wrapper for @ref ADDRXLAT_CAPS - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns integer capability mask (or @c NULL on failure) - */ -static PyObject * -_addrxlat_CAPS(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"addrspace", NULL}; - unsigned long addrspace; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", - keywords, &addrspace)) - return NULL; - - return PyLong_FromUnsignedLong(ADDRXLAT_CAPS(addrspace)); -} - -PyDoc_STRVAR(_addrxlat_VER_LINUX__doc__, -"VER_LINUX(a, b, c) -> version code\n\ -\n\ -Calculate the Linux kernel version code."); - -/** Wrapper for @ref ADDRXLAT_VER_LINUX - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns integer version code (or @c NULL on failure) - */ -static PyObject * -_addrxlat_VER_LINUX(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"a", "b", "c", NULL}; - unsigned long a, b, c; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "kkk", - keywords, &a, &b, &c)) - return NULL; - - return PyLong_FromUnsignedLong(ADDRXLAT_VER_LINUX(a, b, c)); -} - -PyDoc_STRVAR(_addrxlat_VER_XEN__doc__, -"VER_XEN(major, minor) -> version code\n\ -\n\ -Calculate the Xen hypervisor version code."); - -/** Wrapper for @ref ADDRXLAT_VER_XEN - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns integer version code (or @c NULL on failure) - */ -static PyObject * -_addrxlat_VER_XEN(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"major", "minor", NULL}; - unsigned long major, minor; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "kk", - keywords, &major, &minor)) - return NULL; - - return PyLong_FromUnsignedLong(ADDRXLAT_VER_XEN(major, minor)); -} - -PyDoc_STRVAR(_addrxlat_pte_format_name__doc__, -"pte_format_name(fmt) -> name\n\ -\n\ -Return the name of a page table entry format constant."); - -/** Wrapper for @ref addrxlat_pte_format_name - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns error message string (or @c NULL on failure) - */ -static PyObject * -_addrxlat_pte_format_name(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"fmt", NULL}; - long fmt; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", - keywords, &fmt)) - return NULL; - - return Text_FromUTF8(addrxlat_pte_format_name(fmt)); -} - -PyDoc_STRVAR(_addrxlat_pte_format__doc__, -"pte_format(name) -> fmt\n\ -\n\ -Return the page table entry format constant with the given name."); - -/** Wrapper for @ref addrxlat_pte_format - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns error message string (or @c NULL on failure) - */ -static PyObject * -_addrxlat_pte_format(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"name", NULL}; - const char *name; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", - keywords, &name)) - return NULL; - - return PyInt_FromLong(addrxlat_pte_format(name)); -} - -PyDoc_STRVAR(_addrxlat_pteval_shift__doc__, -"pteval_shift(fmt) -> capability bitmask\n\ -\n\ -Get the pteval shift for a PTE format.\n\ -See PTE_xxx for valid values of fmt."); - -/** Wrapper for @ref addrxlat_pteval_shift - * @param self module object - * @param args positional arguments - * @param kwargs keyword arguments - * @returns Log2 value of the PTE size, -1 if unknown / invalid - */ -static PyObject * -_addrxlat_pteval_shift(PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"fmt", NULL}; - unsigned long fmt; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", - keywords, &fmt)) - return NULL; - - return PyInt_FromLong(addrxlat_pteval_shift(fmt)); -} - -static PyMethodDef addrxlat_methods[] = { - { "strerror", (PyCFunction)_addrxlat_strerror, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_strerror__doc__ }, - { "addrspace_name", (PyCFunction)_addrxlat_addrspace_name, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_addrspace_name__doc__ }, - { "CAPS", (PyCFunction)_addrxlat_CAPS, METH_VARARGS | METH_KEYWORDS, - _addrxlat_CAPS__doc__ }, - { "VER_LINUX", (PyCFunction)_addrxlat_VER_LINUX, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_VER_LINUX__doc__ }, - { "VER_XEN", (PyCFunction)_addrxlat_VER_XEN, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_VER_XEN__doc__ }, - { "pte_format_name", (PyCFunction)_addrxlat_pte_format_name, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_pte_format_name__doc__ }, - { "pte_format", (PyCFunction)_addrxlat_pte_format, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_pte_format__doc__ }, - { "pteval_shift", (PyCFunction)_addrxlat_pteval_shift, - METH_VARARGS | METH_KEYWORDS, - _addrxlat_pteval_shift__doc__ }, - { NULL } -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef addrxlat_moddef = { - PyModuleDef_HEAD_INIT, - MOD_NAME, /* m_name */ - MOD_DOC, /* m_doc */ - -1, /* m_size */ - addrxlat_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -# define MOD_ERROR_VAL NULL -# define MOD_SUCCESS_VAL(val) val -#else -# define MOD_ERROR_VAL -# define MOD_SUCCESS_VAL(val) -#endif - -PyMODINIT_FUNC -#if PY_MAJOR_VERSION >= 3 -PyInit__addrxlat (void) -#else -init_addrxlat (void) -#endif -{ - PyObject *mod; - PyObject *obj; - int ret; - - if (PyType_Ready(&c_pointer_type) < 0) - return MOD_ERROR_VAL; - - fulladdr_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&fulladdr_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&ctx_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&meth_param_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&meth_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&custommeth_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&linearmeth_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&pgtmeth_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&lookupmeth_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&memarrmeth_type) < 0) - return MOD_ERROR_VAL; - - range_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&range_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&map_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&sys_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&step_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&op_type) < 0) - return MOD_ERROR_VAL; - - if (PyType_Ready(&convert_type) < 0) - return MOD_ERROR_VAL; - -#if PY_MAJOR_VERSION >= 3 - mod = PyModule_Create(&addrxlat_moddef); -#else - mod = Py_InitModule3(MOD_NAME, addrxlat_methods, MOD_DOC); -#endif - if (!mod) - goto err; - - BaseException = make_BaseException(mod); - if (!BaseException) - goto err_mod; - ret = PyModule_AddObject(mod, "BaseException", BaseException); - if (ret) - goto err_exception; - - Py_INCREF((PyObject*)&fulladdr_type); - ret = PyModule_AddObject(mod, "FullAddress", - (PyObject*)&fulladdr_type); - if (ret) - goto err_exception; - - Py_INCREF((PyObject*)&ctx_type); - ret = PyModule_AddObject(mod, "Context", (PyObject*)&ctx_type); - if (ret) - goto err_fulladdr; - - Py_INCREF((PyObject*)&meth_type); - ret = PyModule_AddObject(mod, "Method", (PyObject*)&meth_type); - if (ret) - goto err_ctx; - - Py_INCREF((PyObject*)&custommeth_type); - ret = PyModule_AddObject(mod, "CustomMethod", - (PyObject*)&custommeth_type); - if (ret) - goto err_meth; - - Py_INCREF((PyObject*)&linearmeth_type); - ret = PyModule_AddObject(mod, "LinearMethod", - (PyObject*)&linearmeth_type); - if (ret) - goto err_custommeth; - - Py_INCREF((PyObject*)&pgtmeth_type); - ret = PyModule_AddObject(mod, "PageTableMethod", - (PyObject*)&pgtmeth_type); - if (ret) - goto err_linearmeth; - - Py_INCREF((PyObject*)&lookupmeth_type); - ret = PyModule_AddObject(mod, "LookupMethod", - (PyObject*)&lookupmeth_type); - if (ret) - goto err_pgtmeth; - - Py_INCREF((PyObject*)&memarrmeth_type); - ret = PyModule_AddObject(mod, "MemoryArrayMethod", - (PyObject*)&memarrmeth_type); - if (ret) - goto err_lookupmeth; - - Py_INCREF((PyObject*)&range_type); - ret = PyModule_AddObject(mod, "Range", (PyObject*)&range_type); - if (ret) - goto err_memarrmeth; - - Py_INCREF((PyObject*)&map_type); - ret = PyModule_AddObject(mod, "Map", (PyObject*)&map_type); - if (ret) - goto err_range; - - Py_INCREF((PyObject*)&sys_type); - ret = PyModule_AddObject(mod, "System", (PyObject*)&sys_type); - if (ret) - goto err_map; - - Py_INCREF((PyObject*)&step_type); - ret = PyModule_AddObject(mod, "Step", (PyObject*)&step_type); - if (ret) - goto err_sys; - - Py_INCREF((PyObject*)&op_type); - ret = PyModule_AddObject(mod, "Operator", (PyObject*)&op_type); - if (ret) - goto err_step; - - Py_INCREF((PyObject*)&convert_type); - ret = PyModule_AddObject(mod, "TypeConvert", (PyObject*)&convert_type); - if (ret) - goto err_op; - -#define CONSTDEF(x) \ - if (PyModule_AddIntConstant(mod, #x, ADDRXLAT_ ## x)) \ - goto err_convert - - /* status codes */ - CONSTDEF(OK); - CONSTDEF(ERR_NOTIMPL); - CONSTDEF(ERR_NOTPRESENT); - CONSTDEF(ERR_INVALID); - CONSTDEF(ERR_NOMEM); - CONSTDEF(ERR_NODATA); - CONSTDEF(ERR_NOMETH); - CONSTDEF(ERR_CUSTOM_BASE); - - /* address spaces */ - CONSTDEF(KPHYSADDR); - CONSTDEF(MACHPHYSADDR); - CONSTDEF(KVADDR); - CONSTDEF(NOADDR); - - /* endianity */ - CONSTDEF(BIG_ENDIAN); - CONSTDEF(LITTLE_ENDIAN); - CONSTDEF(HOST_ENDIAN); - - /* translation kinds */ - CONSTDEF(NOMETH); - CONSTDEF(CUSTOM); - CONSTDEF(LINEAR); - CONSTDEF(PGT); - CONSTDEF(LOOKUP); - CONSTDEF(MEMARR); - - /* PTE types */ - CONSTDEF(PTE_NONE); - CONSTDEF(PTE_PFN32); - CONSTDEF(PTE_PFN64); - CONSTDEF(PTE_AARCH64); - CONSTDEF(PTE_AARCH64_LPA); - CONSTDEF(PTE_AARCH64_LPA2); - CONSTDEF(PTE_ARM); - CONSTDEF(PTE_IA32); - CONSTDEF(PTE_IA32_PAE); - CONSTDEF(PTE_X86_64); - CONSTDEF(PTE_RISCV32); - CONSTDEF(PTE_RISCV64); - CONSTDEF(PTE_S390X); - CONSTDEF(PTE_PPC64_LINUX_RPN30); - - /* Other paging form constants */ - CONSTDEF(FIELDS_MAX); - - /* system map indices */ - CONSTDEF(SYS_MAP_HW); - CONSTDEF(SYS_MAP_KV_PHYS); - CONSTDEF(SYS_MAP_KPHYS_DIRECT); - CONSTDEF(SYS_MAP_MACHPHYS_KPHYS); - CONSTDEF(SYS_MAP_KPHYS_MACHPHYS); - CONSTDEF(SYS_MAP_NUM); - - /* system method indices */ - CONSTDEF(SYS_METH_NONE); - CONSTDEF(SYS_METH_PGT); - CONSTDEF(SYS_METH_UPGT); - CONSTDEF(SYS_METH_DIRECT); - CONSTDEF(SYS_METH_KTEXT); - CONSTDEF(SYS_METH_VMEMMAP); - CONSTDEF(SYS_METH_RDIRECT); - CONSTDEF(SYS_METH_MACHPHYS_KPHYS); - CONSTDEF(SYS_METH_KPHYS_MACHPHYS); - CONSTDEF(SYS_METH_CUSTOM); - CONSTDEF(SYS_METH_NUM); - -#undef CONSTDEF - - /* too big for PyModule_AddIntConstant() */ - obj = PyLong_FromUnsignedLongLong(ADDRXLAT_ADDR_MAX); - if (!obj) - goto err_convert; - if (PyModule_AddObject(mod, "ADDR_MAX", obj)) { - Py_DECREF(obj); - goto err_convert; - } - - obj = PyTuple_New(0); - if (!obj) - goto err_convert; - convert = PyObject_Call((PyObject*)&convert_type, obj, NULL); - Py_DECREF(obj); - if (!convert) - goto err_convert; - - if (PyModule_AddObject(mod, "convert", convert)) { - Py_DECREF(convert); - goto err_convert; - } - - CAPI.ver = addrxlat_CAPI_VER; - CAPI.convert = convert; - CAPI.FullAddress_FromPointer = fulladdr_FromPointer; - CAPI.FullAddress_AsPointer = fulladdr_AsPointer; - CAPI.Context_FromPointer = ctx_FromPointer; - CAPI.Context_AsPointer = ctx_AsPointer; - CAPI.Method_FromPointer = meth_FromPointer; - CAPI.Method_AsPointer = meth_AsPointer; - CAPI.Range_FromPointer = range_FromPointer; - CAPI.Range_AsPointer = range_AsPointer; - CAPI.Map_FromPointer = map_FromPointer; - CAPI.Map_AsPointer = map_AsPointer; - CAPI.System_FromPointer = sys_FromPointer; - CAPI.System_AsPointer = sys_AsPointer; - CAPI.Step_FromPointer = step_FromPointer; - CAPI.Step_Init = step_Init; - CAPI.Step_AsPointer = step_AsPointer; - CAPI.Operator_FromPointer = op_FromPointer; - CAPI.Operator_Init = op_Init; - CAPI.Operator_AsPointer = op_AsPointer; - - obj = PyCapsule_New(&CAPI, addrxlat_CAPSULE_NAME, NULL); - if (!obj) - goto err_convert; - if (PyModule_AddObject(mod, "_C_API", obj)) { - Py_DECREF(obj); - goto err_convert; - } - - return MOD_SUCCESS_VAL(mod); - - err_convert: - Py_DECREF((PyObject*)&convert_type); - err_op: - Py_DECREF((PyObject*)&op_type); - err_step: - Py_DECREF((PyObject*)&step_type); - err_sys: - Py_DECREF((PyObject*)&sys_type); - err_map: - Py_DECREF((PyObject*)&map_type); - err_range: - Py_DECREF((PyObject*)&range_type); - err_memarrmeth: - Py_DECREF((PyObject*)&memarrmeth_type); - err_lookupmeth: - Py_DECREF((PyObject*)&lookupmeth_type); - err_pgtmeth: - Py_DECREF((PyObject*)&pgtmeth_type); - err_linearmeth: - Py_DECREF((PyObject*)&linearmeth_type); - err_custommeth: - Py_DECREF((PyObject*)&custommeth_type); - err_meth: - Py_DECREF((PyObject*)&meth_type); - err_ctx: - Py_DECREF((PyObject*)&ctx_type); - err_fulladdr: - Py_DECREF((PyObject*)&fulladdr_type); - err_exception: - Py_DECREF(BaseException); - err_mod: - Py_DECREF(mod); - err: - return MOD_ERROR_VAL; -} diff --git a/python/addrxlat.sym b/python/addrxlat.sym deleted file mode 100644 index 36334e12..00000000 --- a/python/addrxlat.sym +++ /dev/null @@ -1,2 +0,0 @@ -init_addrxlat -PyInit__addrxlat diff --git a/python/addrxlat/__init__.py b/python/addrxlat/__init__.py deleted file mode 100644 index 73cf383b..00000000 --- a/python/addrxlat/__init__.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -from _addrxlat import * -from addrxlat.exceptions import * -import sys - -class FullAddress(FullAddress): - def __init__(self, addrspace=NOADDR, addr=0, *args, **kwargs): - super(FullAddress, self).__init__(*args, **kwargs) - self.addrspace = addrspace - self.addr = addr - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.addrspace, self.addr) - - def conv(self, addrspace, ctx, sys): - status = super(FullAddress, self).conv(addrspace, ctx, sys) - if status != OK: - raise get_exception(status, ctx.get_err()) - - def copy(self): - "make a copy of self" - return type(self)(addrspace=self.addrspace, addr=self.addr) - -class Context(Context): - def __init__(self, *args, **kwargs): - super(Context, self).__init__(*args, **kwargs) - self.convert = convert - - def __repr__(self): - return '%s()' % (self.__class__.__name__,) - -class Method(Method): - def __init__(self, kind, target_as=NOADDR, param=(), *args, **kwargs): - super(Method, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = target_as - self.param = param - - def __repr__(self): - return '%s(%r, %r, %r)' % ( - self.__class__.__name__, - self.kind, - self.target_as, - self.param) - -class CustomMethod(CustomMethod): - def __init__(self, target_as=NOADDR, *args, **kwargs): - super(CustomMethod, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = target_as - - def __repr__(self): - return '%s(%r)' % ( - self.__class__.__name__, - self.target_as) - -class LinearMethod(LinearMethod): - def __init__(self, target_as=NOADDR, off=0, *args, **kwargs): - super(LinearMethod, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = target_as - self.off = off - - def __repr__(self): - return '%s(%r, %r)' % ( - self.__class__.__name__, - self.target_as, - self.off) - -class PageTableMethod(PageTableMethod): - def __init__(self, target_as=NOADDR, root=None, pte_format=PTE_NONE, fields=(), *args, **kwargs): - super(PageTableMethod, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = 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) - -class LookupMethod(LookupMethod): - def __init__(self, target_as=NOADDR, endoff=0, tbl=(), *args, **kwargs): - super(LookupMethod, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = 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) - -class MemoryArrayMethod(MemoryArrayMethod): - def __init__(self, target_as=NOADDR, base=None, shift=0, elemsz=0, valsz=0, *args, **kwargs): - super(MemoryArrayMethod, self).__init__(*args, **kwargs) - self.convert = convert - self.target_as = 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) - -class Range(Range): - def __init__(self, endoff=0, meth=SYS_METH_NONE, *args, **kwargs): - super(Range, self).__init__(*args, **kwargs) - self.endoff = endoff - self.meth = meth - - def __repr__(self): - return '%s(%r, %r)' % ( - self.__class__.__name__, - self.endoff, - self.meth) - -class Map(Map): - def __init__(self, *args, **kwargs): - super(Map, self).__init__(*args, **kwargs) - self.convert = convert - - def __repr__(self): - return '%s()' % (self.__class__.__name__) - - def set(self, addr, range): - status = super(Map, self).set(addr, range) - if status != OK: - raise get_exception(status) - -class System(System): - def __init__(self, *args, **kwargs): - super(System, self).__init__(*args, **kwargs) - self.convert = convert - - def __repr__(self): - return '%s()' % (self.__class__.__name__) - - def os_init(self, ctx, arch, *args, **kwargs): - status = super(System, self).os_init(ctx, arch, *args, **kwargs) - if status != OK: - raise get_exception(status, ctx.get_err()) - -class Step(Step): - def __init__(self, ctx, sys=None, meth=None, *args, **kwargs): - super(Step, self).__init__(*args, **kwargs) - self.convert = convert - if sys is not None: - self.sys = sys - if meth is not None: - self.meth = meth - - def __repr__(self): - return '%s(%r, %r, %r)' % ( - self.__class__.__name__, - self.ctx, - self.sys, - self.meth) - - def launch(self, *args, **kwargs): - status = super(Step, self).launch(*args, **kwargs) - if status != OK: - raise get_exception(status, self.ctx.get_err()) - - def step(self, *args, **kwargs): - status = super(Step, self).step(*args, **kwargs) - if status != OK: - raise get_exception(status, self.ctx.get_err()) - - def walk(self, *args, **kwargs): - status = super(Step, self).walk(*args, **kwargs) - if status != OK: - raise get_exception(status, self.ctx.get_err()) - -class Operator(Operator): - def __init__(self, ctx, sys=None, caps=None): - super(Operator, self).__init__() - self.convert = convert - if sys is not None: - self.sys = sys - if caps is not None: - self.caps = caps - - def __repr__(self): - return '%s(%r, %r)' % ( - self.__class__.__name__, - self.ctx, - self.sys) - - def __call__(self, *args, **kwargs): - (status, result) = super(Operator, self).__call__(*args, **kwargs) - if status != OK: - raise get_exception(status, self.ctx.get_err()) - return result - -convert = TypeConvert() -convert.FullAddress = FullAddress -convert.Context = Context -convert.Method = Method -convert.CustomMethod = CustomMethod -convert.LinearMethod = LinearMethod -convert.PageTableMethod = PageTableMethod -convert.LookupMethod = LookupMethod -convert.MemoryArrayMethod = MemoryArrayMethod -convert.Range = Range -convert.Map = Map -convert.System = System -convert.Step = Step -convert.Operator = Operator - -import inspect as _inspect -_values = globals().values() -if sys.version_info.major >= 3: - _values = list(_values) -for _cls in _values: - if not _inspect.isclass(_cls): - continue - for _name, _method in _inspect.getmembers(_cls, - lambda x: - (_inspect.ismethod(x), - _inspect.isfunction(x)) - [sys.version_info.major >= 3]): - if _method.__doc__: - continue - for _parent in _inspect.getmro(_cls)[1:]: - if hasattr(_parent, _name): - if _inspect.ismethod(_method): - _method.__func__.__doc__ = getattr(_parent, _name).__doc__ - else: - _method.__doc__ = getattr(_parent, _name).__doc__ - break - -# Free up temporary variables -del _values, _cls, _name, _method, _parent, _inspect diff --git a/python/addrxlat/exceptions.py b/python/addrxlat/exceptions.py deleted file mode 100644 index 4c34329d..00000000 --- a/python/addrxlat/exceptions.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -import _addrxlat -from _addrxlat import BaseException - -_exceptions = ( - ('NotImplementedError', _addrxlat.ERR_NOTIMPL, (NotImplementedError,)), - ('NotPresentError', _addrxlat.ERR_NOTPRESENT), - ('InvalidError', _addrxlat.ERR_INVALID), - ('MemoryError', _addrxlat.ERR_NOMEM, (MemoryError,)), - ('NoDataError', _addrxlat.ERR_NODATA), - ('NoMethodError', _addrxlat.ERR_NOMETH), -) - -def new_exception(name, status, addbases=()): - '''Create an addrxlat exception for a given status code. - The new exception is derived from BaseException, 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, (BaseException,) + addbases, di) - return cls - -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 BaseException. - ''' - for exc in BaseException.__subclasses__(): - if status == exc.status: - return exc(*args, **kwargs) - return BaseException(status, *args, **kwargs) - -for _exc in _exceptions: - _cls = new_exception(*_exc) - globals()[_cls.__name__] = _cls - -# Free up temporary variables -del _exc, _cls, _exceptions diff --git a/python/addrxlatmod.h b/python/addrxlatmod.h deleted file mode 100644 index eb886e2d..00000000 --- a/python/addrxlatmod.h +++ /dev/null @@ -1,86 +0,0 @@ -/** @internal @file python/addrxlatmod.h - * @brief Header file with addrxlat module's C API bindings. - */ -/* Copyright (C) 2017 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. - - libkdumpfile 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 . -*/ - -#ifndef ADDRXLATMOD_H -#define ADDRXLATMOD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define addrxlat_CAPSULE_NAME "_addrxlat._C_API" -#define addrxlat_CAPI_VER 1UL - -struct addrxlat_CAPI { - unsigned long ver; /**< Structure version. */ - - PyObject *convert; /**< Default conversion object. */ - - PyObject *(*FullAddress_FromPointer)( - PyObject *conv, const addrxlat_fulladdr_t *faddr); - addrxlat_fulladdr_t *(*FullAddress_AsPointer)(PyObject *self); - - PyObject *(*Context_FromPointer)(PyObject *conv, addrxlat_ctx_t *ctx); - addrxlat_ctx_t *(*Context_AsPointer)(PyObject *self); - - PyObject *(*Method_FromPointer)( - PyObject *conv, const addrxlat_meth_t *meth); - addrxlat_meth_t *(*Method_AsPointer)(PyObject *self); - - PyObject *(*Range_FromPointer)( - PyObject *conv, const addrxlat_range_t *range); - addrxlat_range_t *(*Range_AsPointer)(PyObject *self); - - PyObject *(*Map_FromPointer)(PyObject *conv, addrxlat_map_t *map); - addrxlat_map_t *(*Map_AsPointer)(PyObject *self); - - PyObject *(*System_FromPointer)(PyObject *conv, addrxlat_sys_t *sys); - addrxlat_sys_t *(*System_AsPointer)(PyObject *self); - - PyObject *(*Step_FromPointer)( - PyObject *conv, const addrxlat_step_t *step); - int (*Step_Init)(PyObject *self, const addrxlat_step_t *step); - addrxlat_step_t *(*Step_AsPointer)(PyObject *self); - - PyObject *(*Operator_FromPointer)( - PyObject *conv, const addrxlat_op_ctl_t *opctl); - int (*Operator_Init)(PyObject *self, const addrxlat_op_ctl_t *opctl); - addrxlat_op_ctl_t *(*Operator_AsPointer)(PyObject *self); - -}; - -#ifdef __cplusplus -} -#endif - -#endif /* addrxlatmod.h */ diff --git a/python/disthelpers.py b/python/disthelpers.py deleted file mode 100644 index a4c63e4b..00000000 --- a/python/disthelpers.py +++ /dev/null @@ -1,17 +0,0 @@ -from distutils.core import Command - -class get_build_platlib(Command): - """This command shows the platform build directory. - """ - description = ("Show platform build directory") - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - cmd = self.get_finalized_command('build') - print(cmd.build_platlib) diff --git a/python/kdumpfile.c b/python/kdumpfile.c deleted file mode 100644 index c92fc34c..00000000 --- a/python/kdumpfile.c +++ /dev/null @@ -1,2197 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "addrxlatmod.h" - -#define MOD_NAME "_kdumpfile" -#define MOD_DOC "kdumpfile - interface to libkdumpfile" - -#if PY_MAJOR_VERSION >= 3 -#define PyString_FromString(x) PyUnicode_FromString((x)) -#define PyString_Check(x) PyUnicode_Check((x)) -#define PyString_FromFormat(format, ...) PyUnicode_FromFormat(format, __VA_ARGS__) -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_Concat PyUnicode_Concat -#endif - -typedef struct { - PyObject_HEAD - kdump_ctx_t *ctx; - int fd; - PyObject *attr; - PyObject *addrxlat_convert; -} kdumpfile_object; - -static PyObject *OSErrorException; -static PyObject *NotImplementedException; -static PyObject *NoDataException; -static PyObject *CorruptException; -static PyObject *InvalidException; -static PyObject *NoKeyException; -static PyObject *EOFException; -static PyObject *BusyException; -static PyObject *AddressTranslationException; - -static struct addrxlat_CAPI *addrxlat_API; - -static PyTypeObject attr_dir_object_type; -static PyTypeObject attr_iterkey_object_type; -static PyTypeObject attr_itervalue_object_type; -static PyTypeObject attr_iteritem_object_type; - -static PyTypeObject bmp_object_type; - -static PyTypeObject blob_object_type; - -static PyObject *attr_viewkeys_type; -static PyObject *attr_viewvalues_type; -static PyObject *attr_viewitems_type; -static PyObject *attr_viewdict_type; - -static PyObject *attr_dir_new(kdumpfile_object *kdumpfile, - const kdump_attr_ref_t *baseref); - -static PyObject *bmp_new(kdump_bmp_t *bitmap); - -static PyObject *blob_new(kdump_blob_t *blob); - -static PyObject * -exception_map(kdump_status status) -{ - switch (status) { - case KDUMP_ERR_SYSTEM: return OSErrorException; - case KDUMP_ERR_NOTIMPL: return NotImplementedException; - case KDUMP_ERR_NODATA: return NoDataException; - case KDUMP_ERR_CORRUPT: return CorruptException; - case KDUMP_ERR_INVALID: return InvalidException; - case KDUMP_ERR_NOKEY: return NoKeyException; - case KDUMP_ERR_EOF: return EOFException; - case KDUMP_ERR_BUSY: return BusyException; - case KDUMP_ERR_ADDRXLAT: return AddressTranslationException; - /* If we raise an exception with status == KDUMP_OK, it's a bug. */ - case KDUMP_OK: - default: return PyExc_RuntimeError; - }; -} - -static PyObject * -kdumpfile_new (PyTypeObject *type, PyObject *args, PyObject *kw) -{ - kdumpfile_object *self = NULL; - static char *keywords[] = {"file", NULL}; - kdump_attr_ref_t rootref; - kdump_status status; - const char *filepath; - - if (!PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &filepath)) - return NULL; - - - self = (kdumpfile_object*) type->tp_alloc (type, 0); - if (!self) - return NULL; - - self->ctx = kdump_new(); - if (!self->ctx) { - PyErr_SetString(PyExc_MemoryError, - "Couldn't allocate kdump context"); - goto fail; - } - - self->fd = open (filepath, O_RDONLY); - if (self->fd < 0) { - PyErr_Format(OSErrorException, "Couldn't open dump file"); - goto fail; - } - - status = kdump_open_fd(self->ctx, self->fd); - if (status != KDUMP_OK) { - PyErr_Format(exception_map(status), - "Cannot open dump: %s", kdump_get_err(self->ctx)); - goto fail; - } - - status = kdump_attr_ref(self->ctx, NULL, &rootref); - if (status != KDUMP_OK) { - PyErr_Format(exception_map(status), - "Cannot reference root attribute: %s", - kdump_get_err(self->ctx)); - goto fail; - } - - self->attr = attr_dir_new(self, &rootref); - if (!self->attr) { - kdump_attr_unref(self->ctx, &rootref); - goto fail; - } - - Py_INCREF(addrxlat_API->convert); - self->addrxlat_convert = addrxlat_API->convert; - - return (PyObject*)self; - -fail: - Py_XDECREF(self->attr); - Py_XDECREF(self); - close(self->fd); - return NULL; -} - -static void -kdumpfile_dealloc(PyObject *_self) -{ - kdumpfile_object *self = (kdumpfile_object*)_self; - - if (self->ctx) { - kdump_free(self->ctx); - self->ctx = NULL; - } - - if (self->fd) close(self->fd); - Py_XDECREF(self->addrxlat_convert); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -PyDoc_STRVAR(read__doc__, -"read (addrtype, address) -> buffer."); - -static PyObject *kdumpfile_read (PyObject *_self, PyObject *args, PyObject *kw) -{ - kdumpfile_object *self = (kdumpfile_object*)_self; - PyObject *obj; - kdump_paddr_t addr; - kdump_status status; - int addrspace; - unsigned long size; - static char *keywords[] = {"addrspace", "address", "size", NULL}; - size_t r; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "ikk:", - keywords, &addrspace, &addr, &size)) - return NULL; - - if (!size) { - PyErr_SetString(PyExc_ValueError, "Zero size buffer"); - return NULL; - } - - obj = PyByteArray_FromStringAndSize(0, size); - if (!obj) - return NULL; - - r = size; - status = kdump_read(self->ctx, addrspace, addr, - PyByteArray_AS_STRING(obj), &r); - if (status != KDUMP_OK) { - Py_XDECREF(obj); - PyErr_SetString(exception_map(status), - kdump_get_err(self->ctx)); - return NULL; - } - - return obj; -} - -static PyObject * -attr_new(kdumpfile_object *kdumpfile, kdump_attr_ref_t *ref, kdump_attr_t *attr) -{ - PyObject *obj = NULL; - - if (attr->type != KDUMP_DIRECTORY) - kdump_attr_unref(kdumpfile->ctx, ref); - - switch (attr->type) { - case KDUMP_NUMBER: - obj = PyLong_FromUnsignedLong(attr->val.number); - break; - case KDUMP_ADDRESS: - obj = PyLong_FromUnsignedLong(attr->val.address); - break; - case KDUMP_STRING: - obj = PyString_FromString(attr->val.string); - break; - case KDUMP_DIRECTORY: - obj= attr_dir_new(kdumpfile, ref); - break; - case KDUMP_BITMAP: - obj = bmp_new(attr->val.bitmap); - break; - case KDUMP_BLOB: - obj = blob_new(attr->val.blob); - break; - default: - PyErr_SetString(PyExc_RuntimeError, "Unhandled attr type"); - } - - kdump_attr_discard(kdumpfile->ctx, attr); - - return obj; -} - -PyDoc_STRVAR(get_addrxlat_ctx__doc__, -"K.get_addrxlat_ctx() -> addrxlat.Context"); - -static PyObject * -get_addrxlat_ctx(PyObject *_self, PyObject *args) -{ - kdumpfile_object *self = (kdumpfile_object*)_self; - addrxlat_ctx_t *ctx; - kdump_status status; - - status = kdump_get_addrxlat(self->ctx, &ctx, NULL); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_get_err(self->ctx)); - return NULL; - } - return addrxlat_API->Context_FromPointer(self->addrxlat_convert, ctx); -} - -PyDoc_STRVAR(get_addrxlat_sys__doc__, -"K.get_addrxlat_sys() -> addrxlat.System"); - -static PyObject * -get_addrxlat_sys(PyObject *_self, PyObject *args) -{ - kdumpfile_object *self = (kdumpfile_object*)_self; - addrxlat_sys_t *sys; - kdump_status status; - - status = kdump_get_addrxlat(self->ctx, NULL, &sys); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_get_err(self->ctx)); - return NULL; - } - return addrxlat_API->System_FromPointer(self->addrxlat_convert, sys); -} - -static PyMethodDef kdumpfile_object_methods[] = { - {"read", (PyCFunction) kdumpfile_read, METH_VARARGS | METH_KEYWORDS, - read__doc__}, - { "get_addrxlat_ctx", get_addrxlat_ctx, METH_NOARGS, - get_addrxlat_ctx__doc__ }, - { "get_addrxlat_sys", get_addrxlat_sys, METH_NOARGS, - get_addrxlat_sys__doc__ }, - {NULL} -}; - -static PyObject * -kdumpfile_getattr(PyObject *_self, void *_data) -{ - kdumpfile_object *self = (kdumpfile_object*)_self; - - if (!self->attr) - Py_RETURN_NONE; - - Py_INCREF(self->attr); - return self->attr; -} - -static void -cleanup_exceptions(void) -{ - Py_XDECREF(OSErrorException); - Py_XDECREF(NotImplementedException); - Py_XDECREF(NoDataException); - Py_XDECREF(CorruptException); - Py_XDECREF(InvalidException); - Py_XDECREF(NoKeyException); - Py_XDECREF(EOFException); - Py_XDECREF(BusyException); - Py_XDECREF(AddressTranslationException); -} - -static int lookup_exceptions (void) -{ - PyObject *mod = PyImport_ImportModule("kdumpfile.exceptions"); - if (!mod) - return -1; - -#define lookup_exception(name) \ -do { \ - name = PyObject_GetAttrString(mod, #name); \ - if (!name) \ - goto fail; \ -} while(0) - - lookup_exception(OSErrorException); - lookup_exception(NotImplementedException); - lookup_exception(NoDataException); - lookup_exception(CorruptException); - lookup_exception(InvalidException); - lookup_exception(NoKeyException); - lookup_exception(EOFException); - lookup_exception(BusyException); - lookup_exception(AddressTranslationException); -#undef lookup_exception - - Py_XDECREF(mod); - return 0; -fail: - cleanup_exceptions(); - Py_XDECREF(mod); - return -1; -} - -static void -cleanup_views(void) -{ - Py_XDECREF(attr_viewkeys_type); - Py_XDECREF(attr_viewvalues_type); - Py_XDECREF(attr_viewitems_type); - Py_XDECREF(attr_viewdict_type); -} - -static int -lookup_views(void) -{ - PyObject *mod = PyImport_ImportModule("kdumpfile.views"); - if (!mod) - return -1; - -#define lookup_view(name) \ - do { \ - name ## _type = PyObject_GetAttrString(mod, #name); \ - if (! name ## _type) \ - goto fail; \ - } while(0) - - lookup_view(attr_viewkeys); - lookup_view(attr_viewvalues); - lookup_view(attr_viewitems); - lookup_view(attr_viewdict); -#undef lookup_view - - Py_DECREF(mod); - return 0; - -fail: - cleanup_views(); - Py_DECREF(mod); - return -1; -} - -static PyGetSetDef kdumpfile_object_getset[] = { - { "attr", kdumpfile_getattr, NULL, - "Access to libkdumpfile attributes" }, - { NULL } -}; - -PyDoc_STRVAR(kdumpfile_addrxlat_convert__doc__, -"addrxlat C type converter"); - -static PyMemberDef kdumpfile_members[] = { - { "addrxlat_convert", T_OBJECT, - offsetof(kdumpfile_object, addrxlat_convert), 0, - kdumpfile_addrxlat_convert__doc__ }, - { NULL } -}; - -static PyTypeObject kdumpfile_object_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".kdumpfile", /* tp_name*/ - sizeof (kdumpfile_object), /* tp_basicsize*/ - 0, /* tp_itemsize*/ - kdumpfile_dealloc, /* tp_dealloc*/ - 0, /* tp_print*/ - 0, /* tp_getattr*/ - 0, /* tp_setattr*/ - 0, /* tp_compare*/ - 0, /* tp_repr*/ - 0, /* tp_as_number*/ - 0, /* tp_as_sequence*/ - 0, /* tp_as_mapping*/ - 0, /* tp_hash */ - 0, /* tp_call*/ - 0, /* tp_str*/ - 0, /* tp_getattro*/ - 0, /* tp_setattro*/ - 0, /* tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE, /* tp_flags*/ - "kdumpfile - native extension", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - kdumpfile_object_methods, /* tp_methods */ - kdumpfile_members, /* tp_members */ - kdumpfile_object_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - kdumpfile_new, /* tp_new */ -}; - -/* Attribute dictionary type */ - -typedef struct { - PyObject_HEAD - kdumpfile_object *kdumpfile; - kdump_attr_ref_t baseref; -} attr_dir_object; - -static PyObject *attr_iter_new(attr_dir_object *attr_dir, - PyTypeObject *itertype); - -static int -lookup_attribute(attr_dir_object *self, PyObject *key, kdump_attr_ref_t *ref) -{ - PyObject *stringkey; -#if PY_MAJOR_VERSION >= 3 - PyObject *bytes; -#endif - char *keystr = NULL; - int ret; - - if (!PyString_Check(key)) { - stringkey = PyObject_Str(key); - if (!stringkey) - return -1; - } else - stringkey = key; - - ret = -1; -#if PY_MAJOR_VERSION >= 3 - bytes = PyUnicode_AsASCIIString(stringkey); - if (bytes) { - keystr = PyBytes_AsString(bytes); - } -#else - keystr = PyString_AsString(stringkey); -#endif - if (keystr) { - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_status status; - - status = kdump_sub_attr_ref(ctx, &self->baseref, keystr, ref); - if (status == KDUMP_OK) - ret = 1; - else if (status == KDUMP_ERR_NOKEY) - ret = 0; - else - PyErr_SetString(exception_map(status), - kdump_get_err(ctx)); - } - - if (stringkey != key) - Py_DECREF(stringkey); - -#if PY_MAJOR_VERSION >= 3 - Py_DECREF(bytes); -#endif - - return ret; -} - -static int -get_attribute(attr_dir_object *self, PyObject *key, kdump_attr_ref_t *ref) -{ - int ret = lookup_attribute(self, key, ref); - if (ret == 0) - PyErr_SetObject(PyExc_KeyError, key); - return ret; -} - -static int -attr_dir_contains(PyObject *_self, PyObject *key) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_attr_ref_t ref; - int ret; - - ret = lookup_attribute(self, key, &ref); - if (ret > 0) { - ret = kdump_attr_ref_isset(&ref); - kdump_attr_unref(self->kdumpfile->ctx, &ref); - } - return ret; -} - -static PySequenceMethods attr_dir_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - attr_dir_contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static Py_ssize_t -attr_dir_length(PyObject *_self) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_attr_iter_t iter; - kdump_status status; - Py_ssize_t len = 0; - - status = kdump_attr_ref_iter_start(ctx, &self->baseref, &iter); - if (status != KDUMP_OK) - goto err; - - while (iter.key) { - ++len; - status = kdump_attr_iter_next(ctx, &iter); - if (status != KDUMP_OK) - break; - } - kdump_attr_iter_end(ctx, &iter); - if (status != KDUMP_OK) - goto err; - - return len; - - err: - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return -1; -} - -static PyObject * -attr_dir_subscript(PyObject *_self, PyObject *key) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_ctx_t *ctx; - kdump_attr_t attr; - kdump_attr_ref_t ref; - kdump_status status; - - if (get_attribute(self, key, &ref) <= 0) - return NULL; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_get(ctx, &ref, &attr); - if (status == KDUMP_OK) - return attr_new(self->kdumpfile, &ref, &attr); - - if (status == KDUMP_ERR_NODATA) - PyErr_SetObject(PyExc_KeyError, key); - else - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - - kdump_attr_unref(ctx, &ref); - return NULL; -} - -static PyObject * -object2attr(PyObject *value, kdump_attr_ref_t *ref, kdump_attr_t *attr) -{ - unsigned PY_LONG_LONG num; - PyObject *conv; -#if PY_MAJOR_VERSION >= 3 - PyObject *bytes; -#endif - - attr->type = value - ? kdump_attr_ref_type(ref) - : KDUMP_NIL; - - conv = value; - switch (attr->type) { - case KDUMP_NIL: /* used for deletions */ - break; - - case KDUMP_DIRECTORY: - /* TODO: We may want to enforce a specific type or even - * a specific value for directory instantiation. - */ - break; - - case KDUMP_NUMBER: - case KDUMP_ADDRESS: - if (PyLong_Check(value)) { - num = PyLong_AsUnsignedLongLong(value); - if (PyErr_Occurred()) - return NULL; -#if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(value)) { - num = PyInt_AsLong(value); - if (PyErr_Occurred()) - return NULL; -#endif - } else { - PyErr_Format(PyExc_TypeError, - "need an integer, not %.200s", - Py_TYPE(value)->tp_name); - return NULL; - } - - if (attr->type == KDUMP_NUMBER) - attr->val.number = num; - else - attr->val.address = num; - break; - - case KDUMP_STRING: - if (!PyString_Check(value)) { - conv = PyObject_Str(value); - if (!conv) - return NULL; - } - -#if PY_MAJOR_VERSION >= 3 - bytes = PyUnicode_AsASCIIString(conv); - if (!bytes) - return NULL; - - attr->val.string = PyBytes_AsString(bytes); - if (!attr->val.string) - return NULL; -#else - if (! (attr->val.string = PyString_AsString(conv)) ) - return NULL; -#endif - break; - - default: - PyErr_SetString(PyExc_TypeError, - "assignment to an unknown type"); - return NULL; - } - - return conv; -} - -static int -set_attribute(attr_dir_object *self, kdump_attr_ref_t *ref, PyObject *value) -{ - PyObject *conv; - kdump_ctx_t *ctx; - kdump_attr_t attr; - kdump_status status; - - conv = object2attr(value, ref, &attr); - if (value && !conv) - return -1; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_set(ctx, ref, &attr); - if (conv != value) - Py_XDECREF(conv); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return -1; - } - - return 0; -} - -static int -attr_dir_ass_subscript(PyObject *_self, PyObject *key, PyObject *value) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_attr_ref_t ref; - int ret = -1; - - if (get_attribute(self, key, &ref) <= 0) - return ret; - - ret = set_attribute(self, &ref, value); - kdump_attr_unref(self->kdumpfile->ctx, &ref); - return ret; -} - -static PyMappingMethods attr_dir_as_mapping = { - attr_dir_length, /* mp_length */ - attr_dir_subscript, /* mp_subscript */ - attr_dir_ass_subscript, /* mp_ass_subscript */ -}; - -static PyObject * -attr_dir_new(kdumpfile_object *kdumpfile, const kdump_attr_ref_t *baseref) -{ - attr_dir_object *self; - - self = PyObject_GC_New(attr_dir_object, &attr_dir_object_type); - if (self == NULL) - return NULL; - - Py_INCREF((PyObject*)kdumpfile); - self->kdumpfile = kdumpfile; - self->baseref = *baseref; - PyObject_GC_Track(self); - return (PyObject*)self; -} - -static void -attr_dir_dealloc(PyObject *_self) -{ - attr_dir_object *self = (attr_dir_object*)_self; - - PyObject_GC_UnTrack(self); - kdump_attr_unref(self->kdumpfile->ctx, &self->baseref); - Py_XDECREF((PyObject*)self->kdumpfile); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -attr_dir_traverse(PyObject *_self, visitproc visit, void *arg) -{ - attr_dir_object *self = (attr_dir_object*)_self; - - Py_VISIT((PyObject*)self->kdumpfile); - return 0; -} - -static PyObject * -attr_dir_getattro(PyObject *_self, PyObject *name) -{ - PyObject *ret; -#if PY_MAJOR_VERSION >= 3 - PyObject *temp; -#endif - - ret = PyObject_GenericGetAttr(_self, name); - if (ret || !PyErr_ExceptionMatches(PyExc_AttributeError)) - return ret; - - PyErr_Clear(); - ret = attr_dir_subscript(_self, name); - if (ret || !PyErr_ExceptionMatches(PyExc_KeyError)) - return ret; - -#if PY_MAJOR_VERSION >= 3 - temp = PyUnicode_AsASCIIString(name); - if (!temp) - return NULL; -#endif - - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%.400s'", - Py_TYPE(_self)->tp_name, -#if PY_MAJOR_VERSION >= 3 - PyString_AS_STRING(temp) -#else - PyString_AS_STRING(name) -#endif - ); - - -#if PY_MAJOR_VERSION >= 3 - Py_DECREF(temp); -#endif - return NULL; -} - -static int -attr_dir_setattro(PyObject *_self, PyObject *name, PyObject *value) -{ - int ret; -#if PY_MAJOR_VERSION >= 3 - PyObject *temp; -#endif - - ret = PyObject_GenericSetAttr(_self, name, value); - if (!ret || !PyErr_ExceptionMatches(PyExc_AttributeError)) - return ret; - - PyErr_Clear(); - ret = attr_dir_ass_subscript(_self, name, value); - if (!ret || !PyErr_ExceptionMatches(PyExc_KeyError)) - return ret; - -#if PY_MAJOR_VERSION >= 3 - temp = PyUnicode_AsASCIIString(name); -#endif - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%.400s'", - Py_TYPE(_self)->tp_name, -#if PY_MAJOR_VERSION >= 3 - PyString_AS_STRING(temp) -#else - PyString_AS_STRING(name) -#endif - ); -#if PY_MAJOR_VERSION >= 3 - Py_DECREF(temp); -#endif - return -1; -} - -PyDoc_STRVAR(get__doc__, -"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."); - -static PyObject * -attr_dir_get(PyObject *_self, PyObject *args) -{ - attr_dir_object *self = (attr_dir_object*)_self; - PyObject *key, *failobj; - kdump_ctx_t *ctx; - kdump_attr_ref_t ref; - kdump_attr_t attr; - kdump_status status; - int res; - - failobj = Py_None; - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) - return NULL; - - res = lookup_attribute(self, key, &ref); - if (res < 0) - return NULL; - else if (res == 0) - goto notfound; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_get(ctx, &ref, &attr); - if (status == KDUMP_OK) - return attr_new(self->kdumpfile, &ref, &attr); - - if (status != KDUMP_ERR_NODATA) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return NULL; - } - - notfound: - Py_INCREF(failobj); - return failobj; -} - -PyDoc_STRVAR(setdefault_doc__, -"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"); - -static PyObject * -dict_setdefault(PyObject *_self, PyObject *args) -{ - attr_dir_object *self = (attr_dir_object*)_self; - PyObject *key, *failobj; - PyObject *val = NULL; - kdump_ctx_t *ctx; - kdump_attr_ref_t ref; - kdump_attr_t attr; - kdump_status status; - - failobj = Py_None; - if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj)) - return NULL; - - if (get_attribute(self, key, &ref) <= 0) - return NULL; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_get(ctx, &ref, &attr); - if (status == KDUMP_OK) - val = attr_new(self->kdumpfile, &ref, &attr); - else if (status == KDUMP_ERR_NODATA) - val = (set_attribute(self, &ref, failobj) == 0) - ? failobj - : NULL; - else { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - val = NULL; - } - kdump_attr_unref(ctx, &ref); - - Py_XINCREF(val); - return val; -} - -static PyObject * -attr_dir_merge(PyObject *_self, PyObject *map) -{ - PyObject *keys, *iter; - PyObject *key, *value; - int status; - - keys = PyMapping_Keys(map); - if (!keys) - return NULL; - iter = PyObject_GetIter(keys); - Py_DECREF(keys); - if (!iter) - return NULL; - - for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { - value = PyObject_GetItem(map, key); - if (!value) - goto err; - - status = attr_dir_ass_subscript(_self, key, value); - Py_DECREF(value); - if (status < 0) - goto err; - Py_DECREF(key); - } - Py_DECREF(iter); - if (PyErr_Occurred()) - return NULL; - - return Py_None; - - err: - Py_DECREF(iter); - Py_DECREF(key); - return NULL; -} - -static PyObject * -attr_dir_merge_seq2(PyObject *_self, PyObject *seq2) -{ - PyObject *iter, *elem; - Py_ssize_t i; /* index into seq2 of current element */ - PyObject *fast; /* item as a 2-tuple or 2-list */ - - iter = PyObject_GetIter(seq2); - if (!iter) - return NULL; - - i = 0; - while ( (elem = PyIter_Next(iter)) ) { - PyObject *key, *value; - Py_ssize_t n; - int status; - - /* Convert item to sequence, and verify length 2. */ - fast = PySequence_Fast(elem, ""); - if (!fast) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "cannot convert attribute update" - " sequence element #%zd" - " to a sequence", i); - goto err; - } - n = PySequence_Fast_GET_SIZE(fast); - if (n != 2) { - PyErr_Format(PyExc_ValueError, - "attribute update sequence element #%zd " - "has length %zd; 2 is required", - i, n); - goto err; - } - - /* Update/merge with this (key, value) pair. */ - key = PySequence_Fast_GET_ITEM(fast, 0); - value = PySequence_Fast_GET_ITEM(fast, 1); - status = attr_dir_ass_subscript(_self, key, value); - if (status < 0) - goto err; - Py_DECREF(fast); - Py_DECREF(elem); - ++i; - } - Py_DECREF(iter); - - return PyErr_Occurred() - ? NULL - : Py_None; - - err: - Py_XDECREF(fast); - Py_DECREF(elem); - Py_DECREF(iter); - return NULL; -} - -PyDoc_STRVAR(update__doc__, -"D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n" -"If E present and has a .keys() method, does: for k in E: D[k] = E[k]\n" -"If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v\n" -"In either case, this is followed by: for k in F: D[k] = F[k]"); - -static PyObject * -attr_dir_update(PyObject *_self, PyObject *args, PyObject *kwds) -{ - PyObject *arg = NULL; - PyObject *result; - - if (!PyArg_UnpackTuple(args, "update", 0, 1, &arg)) - return NULL; - - result = (arg == NULL) - ? Py_None - : (PyObject_HasAttrString(arg, "keys") - ? attr_dir_merge(_self, arg) - : attr_dir_merge_seq2(_self, arg)); - - if (result && kwds != NULL) - result = attr_dir_merge(_self, kwds); - return result; -} - -PyDoc_STRVAR(clear__doc__, -"D.clear() -> None. Remove all items from D."); - -static PyObject * -attr_dir_clear(PyObject *_self, PyObject *args) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_attr_iter_t iter; - kdump_attr_t attr; - kdump_status status; - - status = kdump_attr_ref_iter_start(ctx, &self->baseref, &iter); - if (status != KDUMP_OK) - goto err_noiter; - - attr.type = KDUMP_NIL; - while (iter.key) { - status = kdump_attr_ref_set(ctx, &iter.pos, &attr); - if (status != KDUMP_OK) - goto err; - status = kdump_attr_iter_next(ctx, &iter); - if (status != KDUMP_OK) - goto err; - } - - kdump_attr_iter_end(ctx, &iter); - Py_RETURN_NONE; - - err: - kdump_attr_iter_end(ctx, &iter); - err_noiter: - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return NULL; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject * -attr_dir_repr(PyObject *_self) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_attr_iter_t iter; - kdump_status status; - PyObject *s, *temp, *temp2; - PyObject *colon = NULL, *pieces = NULL; - PyObject *result = NULL; - int res; - - status = kdump_attr_ref_iter_start(ctx, &self->baseref, &iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return NULL; - } - - if (!iter.key) { - result = PyString_FromFormat("%s({})", - Py_TYPE(_self)->tp_name); - goto out; - } - - colon = PyString_FromString(": "); - if (!colon) - goto out; - - pieces = PyList_New(0); - if (!pieces) - goto out; - - while (iter.key) { - s = PyString_FromString(iter.key); - if (!s) - goto out; - temp = attr_dir_subscript(_self, s); - if (!temp) { - Py_DECREF(s); - goto out; - } - PyString_Concat(&s, colon); - temp2 = PyObject_Repr(temp); - PyString_Concat(&s, temp2); - Py_DECREF(temp); - Py_DECREF(temp2); - if (!s) - goto out; - - res = PyList_Append(pieces, s); - Py_DECREF(s); - if (res <0) - goto out; - - status = kdump_attr_iter_next(ctx, &iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_get_err(ctx)); - goto out; - } - } - - s = PyString_FromFormat("%s({", Py_TYPE(_self)->tp_name); - if (!s) - goto out; - temp = PyList_GET_ITEM(pieces, 0); - PyString_Concat(&s, temp); - PyList_SET_ITEM(pieces, 0, s); - if (!s) - goto out; - - s = PyString_FromString("})"); - if (!s) - goto out; - temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_Concat(&temp, s); - PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); - if (!temp) - goto out; - - s = PyString_FromString(", "); - if (!s) - goto out; - result = _PyString_Join(s, pieces); - Py_DECREF(s); - - out: - kdump_attr_iter_end(ctx, &iter); - Py_XDECREF(pieces); - Py_XDECREF(colon); - return result; -} - -static int -attr_dir_print(PyObject *_self, FILE *fp, int flags) -{ - attr_dir_object *self = (attr_dir_object*)_self; - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_attr_iter_t iter; - kdump_status status; - PyObject *s, *temp; - int res; - - status = kdump_attr_ref_iter_start(ctx, &self->baseref, &iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return -1; - } - - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "%s({", Py_TYPE(_self)->tp_name); - Py_END_ALLOW_THREADS - - while (iter.key) { - s = PyString_FromString(iter.key); - if (!s) - goto err; - res = PyObject_Print(s, fp, 0); - if (res != 0) { - Py_DECREF(s); - goto err; - } - - Py_BEGIN_ALLOW_THREADS - fputs(": ", fp); - Py_END_ALLOW_THREADS - - temp = attr_dir_subscript(_self, s); - Py_DECREF(s); - if (!temp) - goto err; - res = PyObject_Print(temp, fp, 0); - Py_DECREF(temp); - if (res != 0) - goto err; - - status = kdump_attr_iter_next(ctx, &iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_get_err(ctx)); - goto err; - } - - if (iter.key) { - Py_BEGIN_ALLOW_THREADS - fputs(", ", fp); - Py_END_ALLOW_THREADS - } - } - - kdump_attr_iter_end(ctx, &iter); - - Py_BEGIN_ALLOW_THREADS - fputs("})", fp); - Py_END_ALLOW_THREADS - - return 0; - - err: - kdump_attr_iter_end(ctx, &iter); - return -1; -} -#endif - -static PyObject * -attr_iterkey_new(PyObject *_self) -{ - attr_dir_object *self = (attr_dir_object*)_self; - return attr_iter_new(self, &attr_iterkey_object_type); -} - -PyDoc_STRVAR(iterkeys__doc__, -"D.iterkeys() -> an iterator over the keys of D"); - -static PyObject * -attr_dir_iterkeys(PyObject *_self, PyObject *arg) -{ - attr_dir_object *self = (attr_dir_object*)_self; - return attr_iter_new(self, &attr_iterkey_object_type); -} - -PyDoc_STRVAR(itervalues__doc__, -"D.itervalues() -> an iterator over the values of D"); - -static PyObject * -attr_dir_itervalues(PyObject *_self, PyObject *arg) -{ - attr_dir_object *self = (attr_dir_object*)_self; - return attr_iter_new(self, &attr_itervalue_object_type); -} - -PyDoc_STRVAR(iteritems__doc__, -"D.iteritems() -> an iterator over the (key, value) items of D"); - -static PyObject * -attr_dir_iteritems(PyObject *_self, PyObject *arg) -{ - attr_dir_object *self = (attr_dir_object*)_self; - return attr_iter_new(self, &attr_iteritem_object_type); -} - -static PyObject * -attr_dir_make_list(PyObject *iter) -{ - PyObject *list, *object; - iternextfunc iternext; - - if (!iter) - return NULL; - - list = PyList_New(0); - if (!list) - goto err_iter; - - iternext = Py_TYPE(iter)->tp_iternext; - while ( (object = iternext(iter)) ) - if (PyList_Append(list, object)) - goto err_list; - - if (PyErr_Occurred()) - goto err_list; - - Py_DECREF(iter); - return list; - - err_list: - Py_DECREF(list); - err_iter: - Py_DECREF(iter); - return NULL; -} - -PyDoc_STRVAR(keys__doc__, -"D.keys() -> list of D's keys"); - -static PyObject * -attr_dir_keys(PyObject *_self, PyObject *arg) -{ - return attr_dir_make_list(attr_dir_iterkeys(_self, arg)); -} - -PyDoc_STRVAR(values__doc__, -"D.values() -> list of D's values"); - -static PyObject * -attr_dir_values(PyObject *_self, PyObject *arg) -{ - return attr_dir_make_list(attr_dir_itervalues(_self, arg)); -} - -PyDoc_STRVAR(items__doc__, -"D.items() -> list of D's (key, value) pairs, as 2-tuples"); - -static PyObject * -attr_dir_items(PyObject *_self, PyObject *arg) -{ - return attr_dir_make_list(attr_dir_iteritems(_self, arg)); -} - -static PyObject * -attr_dir_view(PyObject *_self, PyObject *viewtype) -{ - PyObject *args, *result; - - args = Py_BuildValue("(O)", _self); - if (!args) - return NULL; - result = PyObject_CallObject(viewtype, args); - Py_DECREF(args); - return result; -} - -PyDoc_STRVAR(viewkeys__doc__, -"D.viewkeys() -> a set-like object providing a view on D's keys"); - -static PyObject * -attr_dir_viewkeys(PyObject *_self, PyObject *args) -{ - return attr_dir_view(_self, attr_viewkeys_type); -} - -PyDoc_STRVAR(viewvalues__doc__, -"D.viewvalues() -> an object providing a view on D's values"); - -static PyObject * -attr_dir_viewvalues(PyObject *_self, PyObject *args) -{ - return attr_dir_view(_self, attr_viewvalues_type); -} - -PyDoc_STRVAR(viewitems__doc__, -"D.viewitems() -> a set-like object providing a view on D's items"); - -static PyObject * -attr_dir_viewitems(PyObject *_self, PyObject *args) -{ - return attr_dir_view(_self, attr_viewitems_type); -} - -PyDoc_STRVAR(viewdict__doc__, -"D.viewdict() -> a dict-like object providing a view on D"); - -static PyObject * -attr_dir_viewdict(PyObject *_self, PyObject *args) -{ - return attr_dir_view(_self, attr_viewdict_type); -} - -PyDoc_STRVAR(copy__doc__, -"D.copy() -> a shallow dict copy of D"); - -static PyObject * -attr_dir_copy(PyObject *_self, PyObject *args) -{ - PyObject *dict = PyDict_New(); - if (!dict) - return NULL; - if (PyDict_Merge(dict, _self, 1) != 0) { - Py_DECREF(dict); - return NULL; - } - return dict; -} - -PyDoc_STRVAR(dict__doc__, -"D.dict() -> a dict with a deep copy of D's attributes"); - -static PyObject * -attr_dir_dict(PyObject *_self, PyObject *args) -{ - PyObject *view; - PyObject *dict; - - view = attr_dir_viewdict(_self, NULL); - if (!view) - return NULL; - dict = PyDict_New(); - if (!dict) - goto err; - if (PyDict_Merge(dict, view, 1) != 0) - goto err_dict; - Py_DECREF(view); - return dict; - - err_dict: - Py_DECREF(dict); - err: - Py_DECREF(view); - return NULL; -} - -static PyMethodDef attr_dir_methods[] = { - {"get", attr_dir_get, METH_VARARGS, - get__doc__}, - {"setdefault", dict_setdefault, METH_VARARGS, - setdefault_doc__}, - {"update", (PyCFunction)attr_dir_update, METH_VARARGS | METH_KEYWORDS, - update__doc__}, - {"clear", attr_dir_clear, METH_NOARGS, - clear__doc__}, - {"iterkeys", attr_dir_iterkeys, METH_NOARGS, - iterkeys__doc__}, - {"itervalues", attr_dir_itervalues, METH_NOARGS, - itervalues__doc__}, - {"iteritems", attr_dir_iteritems, METH_NOARGS, - iteritems__doc__}, - {"keys", attr_dir_keys, METH_NOARGS, - keys__doc__}, - {"values", attr_dir_values, METH_NOARGS, - values__doc__}, - {"items", attr_dir_items, METH_NOARGS, - items__doc__}, - {"viewkeys", attr_dir_viewkeys, METH_NOARGS, - viewkeys__doc__}, - {"viewvalues", attr_dir_viewvalues, METH_NOARGS, - viewvalues__doc__}, - {"viewitems", attr_dir_viewitems, METH_NOARGS, - viewitems__doc__}, - {"viewdict", attr_dir_viewdict, METH_NOARGS, - viewdict__doc__}, - {"copy", attr_dir_copy, METH_NOARGS, - copy__doc__}, - {"dict", attr_dir_dict, METH_NOARGS, - dict__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject attr_dir_object_type = -{ - PyVarObject_HEAD_INIT (NULL, 0) - MOD_NAME ".attr_dir", - sizeof(attr_dir_object), /* tp_basicsize*/ - sizeof(char), /* tp_itemsize*/ - /* methods */ - attr_dir_dealloc, /* tp_dealloc*/ -#if PY_MAJOR_VERSION < 3 - attr_dir_print, /* tp_print*/ -#else - 0, -#endif - 0, /* tp_getattr*/ - 0, /* tp_setattr*/ - 0, /* tp_compare*/ -#if PY_MAJOR_VERSION < 3 - attr_dir_repr, /* tp_repr */ -#else - 0, -#endif - 0, /* tp_as_number*/ - &attr_dir_as_sequence, /* tp_as_sequence*/ - &attr_dir_as_mapping, /* tp_as_mapping*/ - 0, /* tp_hash */ - 0, /* tp_call*/ - 0, /* tp_str*/ - attr_dir_getattro, /* tp_getattro*/ - attr_dir_setattro, /* tp_setattro*/ - 0, /* tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags*/ - 0, /* tp_doc */ - attr_dir_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - attr_iterkey_new, /* tp_iter */ - 0, /* tp_iternext */ - attr_dir_methods, /* tp_methods */ -}; - -/* Attribute iterator type */ - -typedef struct { - PyObject_HEAD - kdumpfile_object *kdumpfile; - kdump_attr_iter_t iter; -} attr_iter_object; - -static PyObject * -attr_iter_new(attr_dir_object *attr_dir, PyTypeObject *itertype) -{ - attr_iter_object *self; - kdump_ctx_t *ctx = attr_dir->kdumpfile->ctx; - kdump_status status; - - self = PyObject_GC_New(attr_iter_object, itertype); - if (self == NULL) - return NULL; - - status = kdump_attr_ref_iter_start(ctx, &attr_dir->baseref, - &self->iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - Py_DECREF(self); - return NULL; - } - - Py_INCREF((PyObject*)attr_dir->kdumpfile); - self->kdumpfile = attr_dir->kdumpfile; - PyObject_GC_Track(self); - return (PyObject*)self; -} - -static void -attr_iter_dealloc(PyObject *_self) -{ - attr_iter_object *self = (attr_iter_object*)_self; - kdump_ctx_t *ctx = self->kdumpfile->ctx; - - kdump_attr_iter_end(ctx, &self->iter); - PyObject_GC_UnTrack(self); - Py_XDECREF((PyObject*)self->kdumpfile); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static int -attr_iter_traverse(PyObject *_self, visitproc visit, void *arg) -{ - attr_iter_object *self = (attr_iter_object*)_self; - - Py_VISIT((PyObject*)self->kdumpfile); - return 0; -} - -static PyObject * -attr_iter_advance(attr_iter_object *self, PyObject *ret) -{ - kdump_ctx_t *ctx = self->kdumpfile->ctx; - kdump_status status; - - status = kdump_attr_iter_next(ctx, &self->iter); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - Py_XDECREF(ret); - ret = NULL; - } - - return ret; -} - -static PyObject * -attr_iterkey_next(PyObject *_self) -{ - attr_iter_object *self = (attr_iter_object*)_self; - - if (!self->iter.key) - return NULL; - - return attr_iter_advance(self, PyString_FromString(self->iter.key)); -} - -static PyObject * -attr_itervalue_next(PyObject *_self) -{ - attr_iter_object *self = (attr_iter_object*)_self; - kdump_ctx_t *ctx; - kdump_attr_t attr; - kdump_status status; - PyObject *value; - - if (!self->iter.key) - return NULL; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_get(ctx, &self->iter.pos, &attr); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return NULL; - } - - value = attr_new(self->kdumpfile, &self->iter.pos, &attr); - return attr_iter_advance(self, value); -} - -static PyObject * -attr_iteritem_next(PyObject *_self) -{ - attr_iter_object *self = (attr_iter_object*)_self; - kdump_ctx_t *ctx; - kdump_attr_t attr; - kdump_status status; - PyObject *key, *value, *result; - - if (!self->iter.key) - return NULL; - - ctx = self->kdumpfile->ctx; - status = kdump_attr_ref_get(ctx, &self->iter.pos, &attr); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), kdump_get_err(ctx)); - return NULL; - } - - result = PyTuple_New(2); - if (result == NULL) - goto err_attr; - key = PyString_FromString(self->iter.key); - if (!key) - goto err_result; - value = attr_new(self->kdumpfile, &self->iter.pos, &attr); - if (!value) - goto err_key; - - kdump_attr_discard(self->kdumpfile->ctx, &attr); - PyTuple_SET_ITEM(result, 0, key); - PyTuple_SET_ITEM(result, 1, value); - return attr_iter_advance(self, result); - - err_key: - Py_DECREF(key); - err_result: - Py_DECREF(result); - err_attr: - kdump_attr_discard(self->kdumpfile->ctx, &attr); - return NULL; -} - -static PyTypeObject attr_iterkey_object_type = { - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".attr_dir-keyiterator", - sizeof(attr_iter_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - attr_iter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - attr_iter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - attr_iterkey_next, /* tp_iternext */ -}; - -static PyTypeObject attr_itervalue_object_type = { - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".attr_dir-valueiterator", - sizeof(attr_iter_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - attr_iter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - attr_iter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - attr_itervalue_next, /* tp_iternext */ -}; - -static PyTypeObject attr_iteritem_object_type = { - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".attr_dir-itemiterator", - sizeof(attr_iter_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - attr_iter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - attr_iter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - attr_iteritem_next, /* tp_iternext */ -}; - -typedef struct { - PyObject_HEAD - kdump_bmp_t *bmp; -} bmp_object; - -PyDoc_STRVAR(bmp__doc__, -"bmp() -> dump bitmap"); - -static PyObject * -bmp_new(kdump_bmp_t *bmp) -{ - bmp_object *self; - - self = PyObject_New(bmp_object, &bmp_object_type); - if (!self) - return NULL; - - kdump_bmp_incref(bmp); - self->bmp = bmp; - - return (PyObject*)self; -} - -static void -bmp_dealloc(PyObject *_self) -{ - bmp_object *self = (bmp_object*)_self; - - if (self->bmp) - kdump_bmp_decref(self->bmp); - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -PyDoc_STRVAR(bmp_get_bits__doc__, -"BMP.get_bits(first, last) -> byte array\n\ -\n\ -Get bitmap bits as a raw bitmap."); - -static PyObject * -bmp_get_bits(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"first", "last", NULL}; - bmp_object *self = (bmp_object*)_self; - unsigned long long first, last; - PyObject *buffer; - Py_ssize_t sz; - kdump_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "KK:get_bits", - keywords, &first, &last)) - return NULL; - - buffer = PyByteArray_FromStringAndSize(NULL, 0); - if (!buffer) - return NULL; - - sz = (((last - first) | 7) + 1) / 8; - if (PyByteArray_Resize(buffer, sz) < 0) { - Py_DECREF(buffer); - return NULL; - } - - - status = kdump_bmp_get_bits( - self->bmp, first, last, - (unsigned char*)PyByteArray_AS_STRING(buffer)); - if (status != KDUMP_OK) { - Py_DECREF(buffer); - PyErr_SetString(exception_map(status), - kdump_bmp_get_err(self->bmp)); - return NULL; - } - - return buffer; -} - -PyDoc_STRVAR(bmp_find_set__doc__, -"BMP.find_set(idx) -> index\n\ -\n\ -Find the closest set bit in a bitmapm, starting at idx."); - -static PyObject * -bmp_find_set(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"idx", NULL}; - bmp_object *self = (bmp_object*)_self; - unsigned long long argidx; - kdump_addr_t idx; - kdump_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:find_set", - keywords, &argidx)) - return NULL; - - idx = argidx; - status = kdump_bmp_find_set(self->bmp, &idx); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_bmp_get_err(self->bmp)); - return NULL; - } - - return PyLong_FromUnsignedLong(idx); -} - -PyDoc_STRVAR(bmp_find_clear__doc__, -"BMP.find_clear(idx) -> index\n\ -\n\ -Find the closest zero bit in a bitmapm, starting at idx."); - -static PyObject * -bmp_find_clear(PyObject *_self, PyObject *args, PyObject *kwargs) -{ - static char *keywords[] = {"idx", NULL}; - bmp_object *self = (bmp_object*)_self; - unsigned long long argidx; - kdump_addr_t idx; - kdump_status status; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "K:find_clear", - keywords, &argidx)) - return NULL; - - idx = argidx; - status = kdump_bmp_find_clear(self->bmp, &idx); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_bmp_get_err(self->bmp)); - return NULL; - } - - return PyLong_FromUnsignedLong(idx); -} - -static PyMethodDef bmp_methods[] = { - { "get_bits", (PyCFunction)bmp_get_bits, - METH_VARARGS | METH_KEYWORDS, - bmp_get_bits__doc__ }, - { "find_set", (PyCFunction)bmp_find_set, - METH_VARARGS | METH_KEYWORDS, - bmp_find_set__doc__ }, - { "find_clear", (PyCFunction)bmp_find_clear, - METH_VARARGS | METH_KEYWORDS, - bmp_find_clear__doc__ }, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject bmp_object_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".bmp", /* tp_name */ - sizeof (bmp_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - bmp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - bmp__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bmp_methods, /* tp_methods */ -}; - -typedef struct { - PyObject_HEAD - kdump_blob_t *blob; -} blob_object; - -PyDoc_STRVAR(blob__doc__, -"blob() -> dump blob"); - -static PyObject * -blob_new(kdump_blob_t *blob) -{ - blob_object *self; - - self = PyObject_New(blob_object, &blob_object_type); - if (!self) - return NULL; - - kdump_blob_incref(blob); - self->blob = blob; - - return (PyObject*)self; -} - -static void -blob_dealloc(PyObject *_self) -{ - blob_object *self = (blob_object*)_self; - - if (self->blob) - kdump_blob_decref(self->blob); - - Py_TYPE(self)->tp_free((PyObject*)self); -} - -PyDoc_STRVAR(blob_set__doc__, -"BLOB.set(buffer)\n\ -\n\ -Replace blob contents with a new value. The object given as\n\ -argument must implement the buffer protocol."); - -static PyObject * -blob_set(PyObject *_self, PyObject *args) -{ - blob_object *self = (blob_object*)_self; - kdump_status status; - Py_buffer view; - PyObject *arg; - void *buffer; - - if (!PyArg_ParseTuple(args, "O:set", &arg)) - return NULL; - - if (!PyObject_CheckBuffer(arg)) { - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't support the buffer API", - Py_TYPE(arg)->tp_name); - return NULL; - } - - if (PyObject_GetBuffer(arg, &view, PyBUF_FULL_RO) < 0) - return NULL; - buffer = malloc(view.len); - if (!buffer) - goto buf_fail; - if (PyBuffer_ToContiguous(buffer, &view, view.len, 'C') < 0) - goto buf_fail; - PyBuffer_Release(&view); - - status = kdump_blob_set(self->blob, buffer, view.len); - if (status != KDUMP_OK) { - PyErr_SetString(exception_map(status), - kdump_strerror(status)); - free(buffer); - return NULL; - } - return Py_None; - - buf_fail: - PyBuffer_Release(&view); - return NULL; -} - -static PyMethodDef blob_methods[] = { - { "set", blob_set, METH_VARARGS, - blob_set__doc__ }, - {NULL, NULL} /* sentinel */ -}; - -static int -blob_getbuffer(PyObject *_self, Py_buffer *view, int flags) -{ - blob_object *self = (blob_object*)_self; - void *buffer; - size_t size; - int ret; - - buffer = kdump_blob_pin(self->blob); - if (view == NULL) - return 0; - - size = kdump_blob_size(self->blob); - ret = PyBuffer_FillInfo(view, _self, buffer, size, 0, flags); - if (ret < 0) - kdump_blob_unpin(self->blob); - return ret; -} - -static void -blob_releasebuffer(PyObject *_self, Py_buffer *view) -{ - blob_object *self = (blob_object*)_self; - kdump_blob_unpin(self->blob); -} - -static PyBufferProcs blob_as_buffer = { -#if PY_MAJOR_VERSION < 3 - (readbufferproc)NULL, - (writebufferproc)NULL, - (segcountproc)NULL, - (charbufferproc)NULL, -#endif - blob_getbuffer, - blob_releasebuffer, -}; - -static PyTypeObject blob_object_type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - MOD_NAME ".blob", /* tp_name */ - sizeof (blob_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - blob_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &blob_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT -#if PY_MAJOR_VERSION < 3 - | Py_TPFLAGS_HAVE_NEWBUFFER -#endif - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - blob__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - blob_methods, /* tp_methods */ -}; - -struct constdef { - const char *name; - int value; -}; - -static const struct constdef kdumpfile_constants[] = { - { "KDUMP_KPHYSADDR", KDUMP_KPHYSADDR }, - { "KDUMP_MACHPHYSADDR", KDUMP_MACHPHYSADDR }, - { "KDUMP_KVADDR", KDUMP_KVADDR }, - { NULL, 0 } -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef kdumpfile_moddef = { - PyModuleDef_HEAD_INIT, - MOD_NAME, /* m_name */ - MOD_DOC, /* m_doc */ - -1, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -# define MOD_ERROR_VAL NULL -# define MOD_SUCCESS_VAL(val) val -#else -# define MOD_ERROR_VAL -# define MOD_SUCCESS_VAL(val) -#endif - -PyMODINIT_FUNC -#if PY_MAJOR_VERSION >= 3 -PyInit__kdumpfile (void) -#else -init_kdumpfile (void) -#endif -{ - PyObject *mod; - const struct constdef *cdef; - int ret; - - if (PyType_Ready(&kdumpfile_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&attr_dir_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&attr_iterkey_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&attr_itervalue_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&attr_iteritem_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&bmp_object_type) < 0) - return MOD_ERROR_VAL; - if (PyType_Ready(&blob_object_type) < 0) - return MOD_ERROR_VAL; - -#if PY_MAJOR_VERSION >= 3 - mod = PyModule_Create(&kdumpfile_moddef); -#else - mod = Py_InitModule3(MOD_NAME, NULL, MOD_DOC); -#endif - if (!mod) - goto fail; - - Py_INCREF((PyObject *)&kdumpfile_object_type); - ret = PyModule_AddObject(mod, "kdumpfile", - (PyObject*)&kdumpfile_object_type); - if (ret) - goto fail; - - Py_INCREF((PyObject *)&attr_dir_object_type); - ret = PyModule_AddObject(mod, "attr_dir", - (PyObject*)&attr_dir_object_type); - if (ret) - goto fail; - - Py_INCREF((PyObject *)&bmp_object_type); - ret = PyModule_AddObject(mod, "bmp", - (PyObject*)&bmp_object_type); - if (ret) - goto fail; - - Py_INCREF((PyObject *)&blob_object_type); - ret = PyModule_AddObject(mod, "blob", - (PyObject*)&blob_object_type); - if (ret) - goto fail; - - for (cdef = kdumpfile_constants; cdef->name; ++cdef) - if (PyModule_AddIntConstant(mod, cdef->name, cdef->value)) - goto fail; - - ret = lookup_exceptions(); - if (ret) - goto fail; - - ret = lookup_views(); - if (ret) - goto fail; - - addrxlat_API = (struct addrxlat_CAPI*) - PyCapsule_Import(addrxlat_CAPSULE_NAME, 0); - if (!addrxlat_API) - goto fail; - if (addrxlat_API->ver < addrxlat_CAPI_VER) { - PyErr_Format(PyExc_RuntimeError, - "addrxlat CAPI ver >= %lu needed, %lu found", - addrxlat_CAPI_VER, addrxlat_API->ver); - goto fail; - } - - return MOD_SUCCESS_VAL(mod); - -fail: - cleanup_exceptions(); - cleanup_views(); - Py_XDECREF(mod); - return MOD_ERROR_VAL; -} diff --git a/python/kdumpfile.sym b/python/kdumpfile.sym deleted file mode 100644 index 189baec7..00000000 --- a/python/kdumpfile.sym +++ /dev/null @@ -1,2 +0,0 @@ -init_kdumpfile -PyInit__kdumpfile diff --git a/python/kdumpfile/__init__.py b/python/kdumpfile/__init__.py deleted file mode 100644 index 6501ace5..00000000 --- a/python/kdumpfile/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -from _kdumpfile import * -from addrxlat import convert as _convert -import sys - -class kdumpfile(kdumpfile): - def __init__(self, *args, **kwargs): - self.addrxlat_convert = _convert - -import inspect as _inspect -_values = globals().values() -if sys.version_info.major >= 3: - _values = list(_values) -for _cls in _values: - if not _inspect.isclass(_cls): - continue - for _name, _method in _inspect.getmembers(_cls, - lambda x: - (_inspect.ismethod(x), - _inspect.isfunction(x)) - [sys.version_info.major >= 3]): - if _method.__doc__: - continue - for _parent in _inspect.getmro(_cls)[1:]: - if hasattr(_parent, _name): - if _inspect.ismethod(_method): - _method.__func__.__doc__ = getattr(_parent, _name).__doc__ - else: - _method.__doc__ = getattr(_parent, _name).__doc__ - break - -# Free up temporary variables -del _values, _cls, _name, _method, _parent, _inspect diff --git a/python/kdumpfile/exceptions.py b/python/kdumpfile/exceptions.py deleted file mode 100644 index 62543232..00000000 --- a/python/kdumpfile/exceptions.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -KDUMP_OK = 0 -KDUMP_ERR_SYSTEM = 1 -KDUMP_ERR_NOTIMPL = 2 -KDUMP_ERR_NODATA = 3 -KDUMP_ERR_CORRUPT = 4 -KDUMP_ERR_INVALID = 5 -KDUMP_ERR_EOF = 6 -KDUMP_ERR_NOKEY = 7 -KDUMP_ERR_BUSY = 8 -KDUMP_ERR_ADDRXLAT = 9 - -class KDumpBaseException(Exception): - error = None - -class OSErrorException(KDumpBaseException): - error = KDUMP_ERR_SYSTEM - -class NotImplementedException(KDumpBaseException): - error = KDUMP_ERR_NOTIMPL - -class NoDataException(KDumpBaseException): - error = KDUMP_ERR_NODATA - -class CorruptException(KDumpBaseException): - error = KDUMP_ERR_CORRUPT - -class InvalidException(KDumpBaseException): - error = KDUMP_ERR_INVALID - -class NoKeyException(KDumpBaseException): - error = KDUMP_ERR_NOKEY - -class EOFException(KDumpBaseException): - error = KDUMP_ERR_EOF - -class BusyException(KDumpBaseException): - error = KDUMP_ERR_BUSY - -class AddressTranslationException(KDumpBaseException): - error = KDUMP_ERR_ADDRXLAT diff --git a/python/kdumpfile/views.py b/python/kdumpfile/views.py deleted file mode 100644 index abfa67d2..00000000 --- a/python/kdumpfile/views.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - - -def issub(sub, other): - for x in sub: - if x not in other: - return False - return True - -class attr_view(object): - def __init__(self, dir): - self.dir = dir - - def __repr__(self): - return "%s(%s)" % (type(self).__name__, list(self).__repr__()) - - def __len__(self): - return len(self.dir) - -class attr_setview(attr_view): - def __eq__(self, other): - return len(self) == len(other) and issub(other, self) - - def __ne__(self, other): - return not __eq__(self, other) - - def __lt__(self, other): - return len(self) < len(other) and issub(self, other) - - def __le__(self, other): - return len(self) <= len(other) and issub(self, other) - - def __gt__(self, other): - return len(self) > len(other) and issub(other, self) - - def __ge__(self, other): - return len(self) >= len(other) and issub(other, self) - - def __or__(self, other): - return set(self) | other - - def __and__(self, other): - return set(self) & other - - def __sub__(self, other): - return set(self) - other - - def __xor__(self, other): - return set(self) ^ other - -class attr_viewkeys(attr_setview): - def __contains__(self, other): - return other in self.dir - - def __iter__(self): - return self.dir.iterkeys() - -class attr_viewvalues(attr_view): - def __iter__(self): - return self.dir.itervalues() - -class attr_viewitems(attr_setview): - def __contains__(self, other): - (key, val) = other - return key in self.dir and self.dir[key] == val - - def __iter__(self): - return self.dir.iteritems() - -class attr_viewdict(attr_viewkeys): - """ -Provide a dict-like view on an attribute directory. Nested attribute -directories are shown as dictionaries, so the view provides a deep copy -the attribute (sub-)hierarchy. - """ - def __repr__(self): - return "%s(%s)" % (type(self).__name__, dict(self).__repr__()) - - def keys(self): - return list(self) - - def __getitem__(self, key): - #this import here is needed due to circular dependency - #with _kdumpfile - from _kdumpfile import attr_dir - val = self.dir[key] - if isinstance(val, attr_dir): - return val.copy() - else: - return val diff --git a/python/libtoolize.py b/python/libtoolize.py deleted file mode 100644 index da1f76d1..00000000 --- a/python/libtoolize.py +++ /dev/null @@ -1,132 +0,0 @@ -"""libtool - -Build and install extensions using libtool. -""" - -import os -from distutils import log -from distutils.util import split_quoted -from distutils.dir_util import mkpath -from distutils.file_util import copy_file -from distutils.spawn import spawn -from distutils.errors import DistutilsFileError - -from distutils.command.build_ext import build_ext as _build_ext -class build_ext(_build_ext): - def initialize_options(self): - _build_ext.initialize_options(self) - self.libtool = None - self.pyexecdir = None - - def finalize_options(self): - _build_ext.finalize_options(self) - - if self.libtool is None: - self.libtool = 'libtool' - if self.pyexecdir is None: - import sysconfig - self.pyexecdir = sysconfig.get_path('platlib') - self.cmd_libtool = split_quoted(self.libtool) - - def libtoolize(self, key, mode, *args): - val = getattr(self.compiler, key) - val = val[:1] + list(args) + val[1:] - setattr(self.compiler, key, - self.cmd_libtool + [ '--mode='+mode ] + val) - - def build_extensions(self): - self.compiler.obj_extension = '.lo' - self.libtoolize('compiler', 'compile') - self.libtoolize('compiler_so', 'compile') - self.libtoolize('linker_exe', 'link') - self.libtoolize('linker_so', 'link', - '-module', '-avoid-version', - '-export-symbols-regex', 'init.*|PyInit_.*', - '-rpath', self.pyexecdir) - _build_ext.build_extensions(self) - -from distutils.command.install_lib import install_lib as _install_lib -class install_lib(_install_lib): - def initialize_options(self): - _install_lib.initialize_options(self) - self.libtool_install = None - - def finalize_options(self): - _install_lib.finalize_options(self) - - if self.libtool_install is None: - self.libtool_install = 'libtool --mode=install install' - self.cmd_libtool_install = split_quoted(self.libtool_install) - - def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, - preserve_symlinks=0, level=1): - """Copy the build directory tree, respecting dry-run and force flags. - Special treatment of libtool files. - """ - if not self.dry_run and not os.path.isdir(infile): - raise DistutilsFileError( - "cannot copy tree '%s': not a directory" % infile) - try: - names = os.listdir(infile) - except OSError as e: - if self.dry_run: - names = [] - else: - raise DistutilsFileError( - "error listing files in '%s': %s" % (infile, e.strerror)) - - if not self.dry_run: - mkpath(outfile) - - outputs = [] - - for n in names: - src_name = os.path.join(infile, n) - dst_name = os.path.join(outfile, n) - - if n.startswith('.nfs'): - # skip NFS rename files - continue - if n in ('.libs', '_libs'): - # skip libtool directories - continue - - if preserve_symlinks and os.path.islink(src_name): - link_dest = os.readlink(src_name) - log.info("linking %s -> %s", dst_name, link_dest) - if not self.dry_run: - os.symlink(link_dest, dst_name) - outputs.append(dst_name) - - elif os.path.isdir(src_name): - outputs.extend( - self.copy_tree(src_name, dst_name, preserve_mode, - preserve_times, preserve_symlinks)) - - elif n.endswith('.la'): - spawn(self.cmd_libtool_install + [ src_name, dst_name ], - dry_run=self.dry_run) - - else: - copy_file(src_name, dst_name, preserve_mode, - preserve_times, not self.force, - dry_run=self.dry_run) - outputs.append(dst_name) - - return outputs - -def sysconfig_replace_ext(varname, newext): - """Replace the extension in a system config variable. - """ - from distutils.sysconfig import _config_vars - val = _config_vars.get(varname, '') - suffpos = val.rfind('.') - if suffpos >= 0: - val = val[:suffpos] - _config_vars[varname] = val + newext - -# change default shared object suffix to .la -from distutils.sysconfig import get_config_vars -get_config_vars() -sysconfig_replace_ext('EXT_SUFFIX', '.la') -sysconfig_replace_ext('SO', '.la') diff --git a/python/setup.py b/python/setup.py deleted file mode 100644 index 0b74dfcb..00000000 --- a/python/setup.py +++ /dev/null @@ -1,51 +0,0 @@ -from distutils.core import setup, Extension -import libtoolize -import disthelpers -import os - -try: - from configparser import ConfigParser -except ImportError: - from ConfigParser import ConfigParser - -cfg = ConfigParser() -cfg.read('setup.cfg') -srcdir = cfg.get('kdumpfile', 'srcdir') -top_builddir = cfg.get('kdumpfile', 'top_builddir') -include_dir=os.path.join(top_builddir, 'include') -addrxlat_la = os.path.join( - top_builddir, 'src', 'addrxlat', 'libaddrxlat.la') -kdumpfile_la = os.path.join( - top_builddir, 'src', 'kdumpfile', 'libkdumpfile.la') - -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+) ", - "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) ", - "Programming Language :: Python", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Software Development :: Debuggers "] - -setup(name='libkdumpfile', - version=cfg.get('kdumpfile', 'version'), - description='Python bindings for libkdumpfile', - author='Petr Tesarik', - author_email='petr@tesarici.cz', - url='https://github.com/ptesarik/libkdumpfile', - packages=['addrxlat', 'kdumpfile'], - package_dir={'': srcdir}, - ext_modules=[ - Extension('_addrxlat', [os.path.join(srcdir, 'addrxlat.c')], - include_dirs=[include_dir], - extra_objects=[addrxlat_la]), - Extension('_kdumpfile', [os.path.join(srcdir, 'kdumpfile.c')], - include_dirs=[include_dir], - extra_objects=[kdumpfile_la]), - ], - cmdclass={ - 'build_ext': libtoolize.build_ext, - 'install_lib': libtoolize.install_lib, - 'get_build_platlib': disthelpers.get_build_platlib, - }, -) diff --git a/python/showxlat.py b/python/showxlat.py deleted file mode 100644 index fd1840f6..00000000 --- a/python/showxlat.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -# A version of examples/showxlat.c translated to Python. -# The script is not meant to be particularly useful, but it should -# demonstrate use of the libaddrxlat Python API. -# -# This file is in public domain. - -from __future__ import print_function - -import sys -import kdumpfile -import addrxlat - -def addrspace_str(addrspace): - if addrspace == addrxlat.KPHYSADDR: - return 'KPHYSADDR' - elif addrspace == addrxlat.MACHPHYSADDR: - return 'MACHPHYSADDR' - elif addrspace == addrxlat.KVADDR: - return 'KVADDR' - elif addrspace == addrxlat.NOADDR: - return 'NOADDR' - else: - return ''.format(addrspace) - -def fulladdr_str(addr): - result = addrspace_str(addr.addrspace) - if addr.addrspace != addrxlat.NOADDR: - result += ':0x{:x}'.format(addr.addr) - return result - -def print_target_as(meth): - print(' target_as={}'.format(addrspace_str(meth.target_as))) - -def print_linear(meth): - print('LINEAR') - print_target_as(meth) - print(' off=0x{:x}'.format(meth.off)) - -pte_formats = { - addrxlat.PTE_NONE: 'none', - addrxlat.PTE_PFN32: 'pfn32', - addrxlat.PTE_PFN64: 'pfn64', - addrxlat.PTE_AARCH64: 'aarch64', - addrxlat.PTE_AARCH64_LPA: 'aarch64_lpa', - addrxlat.PTE_AARCH64_LPA2: 'aarch64_lpa2', - addrxlat.PTE_ARM: 'arm', - addrxlat.PTE_IA32: 'ia32', - addrxlat.PTE_IA32_PAE: 'ia32_pae', - addrxlat.PTE_X86_64: 'x86_64', - addrxlat.PTE_RISCV32: 'riscv32', - addrxlat.PTE_RISCV64: 'riscv64', - addrxlat.PTE_S390X: 's390x', - addrxlat.PTE_PPC64_LINUX_RPN30: 'ppc64_linux_rpn30', -} - -def print_pgt(meth): - print('PGT') - print_target_as(meth) - print(' root={}'.format(fulladdr_str(meth.root))) - fmt = pte_formats.get(meth.pte_format, meth.pte_format) - print(' pte_format={}'.format(fmt)) - print(' fields={}'.format(','.join(str(i) for i in meth.fields))) - -def print_lookup(meth): - print('LOOKUP') - print_target_as(meth) - print(' endoff=0x{:x}'.format(meth.endoff)) - for elem in meth.tbl: - print(' {:x} -> {:x}'.format(elem[0], elem[1])) - -def print_memarr(meth): - print('MEMARR') - print_target_as(meth) - print(' base={}'.format(fulladdr_str(meth.base))) - print(' shift={}'.format(meth.shift)) - print(' elemsz={}'.format(meth.elemsz)) - print(' valsz={}'.format(meth.valsz)) - -def print_meth(system, name): - meth = system.get_meth(addrxlat.__dict__['SYS_METH_{}'.format(name)]) - if meth.kind == addrxlat.NOMETH: - return - - print('METH_{}: '.format(name), end='') - - if meth.kind == addrxlat.CUSTOM: - print('CUSTOM') - elif meth.kind == addrxlat.LINEAR: - print_linear(meth) - elif meth.kind == addrxlat.PGT: - print_pgt(meth) - elif meth.kind == addrxlat.LOOKUP: - print_lookup(meth) - elif meth.kind == addrxlat.MEMARR: - print_memarr(meth) - else: - print(''.format(meth.kind)) - - print() - -def print_map(system, name): - print('MAP_{}:'.format(name)) - - map = system.get_map(addrxlat.__dict__['SYS_MAP_{}'.format(name)]) - if map is None: - return - - addr = 0 - for range in map: - if range.meth in meth_names: - name = meth_names[range.meth] - else: - name = '{:d}'.format(range.meth) - print('{:x}-{:x}: {}'.format(addr, addr + range.endoff, name)) - addr += range.endoff + 1 - -def dump_addrxlat(ctx): - system = k.get_addrxlat_sys() - - print_meth(system, 'PGT') - print_meth(system, 'UPGT') - print_meth(system, 'DIRECT') - print_meth(system, 'KTEXT') - print_meth(system, 'VMEMMAP') - print_meth(system, 'RDIRECT') - print_meth(system, 'MACHPHYS_KPHYS') - print_meth(system, 'KPHYS_MACHPHYS') - - print_map(system, 'HW') - print() - print_map(system, 'KV_PHYS') - print() - print_map(system, 'KPHYS_DIRECT') - print() - print_map(system, 'MACHPHYS_KPHYS') - print() - print_map(system, 'KPHYS_MACHPHYS') - -if __name__ == '__main__': - if len(sys.argv) < 2 or len(sys.argv) > 3: - print('Usage: {} []'.format(sys.argv[0]), - file=sys.stderr) - exit(1) - - k = kdumpfile.kdumpfile(sys.argv[1]) - - meth_names = {} - for name, val in addrxlat.__dict__.items(): - if name.startswith('SYS_METH_') and name != 'SYS_METH_NUM': - meth_names[val] = name[9:] - - if len(sys.argv) > 2: - k.attr['addrxlat.ostype'] = sys.argv[2] - - dump_addrxlat(k) diff --git a/python/test_addrxlat.c b/python/test_addrxlat.c deleted file mode 100644 index ee8883a4..00000000 --- a/python/test_addrxlat.c +++ /dev/null @@ -1,159 +0,0 @@ -/** @internal @file python/test_addrxlat.c - * @brief Python module for testing libaddrxlat bindings. - */ -/* Copyright (C) 2017 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. - - libkdumpfile 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 . -*/ - -#include -#include "addrxlatmod.h" - -#define MOD_NAME "_test_addrxlat" -#define MOD_DOC "helper for unit testing" - -static struct addrxlat_CAPI *addrxlat_API; - -#define CUSTOM_MAGIC_ADDR 0x4d795f4d61676963 /* My_Magic */ -#define CUSTOM_MAGIC_ADDR2 0x4d61676963546f6f /* MagicToo */ - -static char custom_magic_str[] = "_test_addrxlat_custom"; - -static addrxlat_status -magic_first_step(addrxlat_step_t *step, addrxlat_addr_t addr) -{ - const addrxlat_meth_t *meth = step->meth; - - if (meth->param.custom.data != custom_magic_str) - return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_INVALID, - "Wrong magic"); - - step->base.as = ADDRXLAT_NOADDR; - step->base.addr = CUSTOM_MAGIC_ADDR; - step->idx[0] = addr & 0xff; - step->idx[1] = addr >> 8; - step->remain = 2; - - return ADDRXLAT_OK; -} - -static addrxlat_status -magic_next_step(addrxlat_step_t *step) -{ - const addrxlat_meth_t *meth = step->meth; - - if (meth->param.custom.data != custom_magic_str) - return addrxlat_ctx_err(step->ctx, ADDRXLAT_ERR_INVALID, - "Wrong magic"); - - step->base.addr = CUSTOM_MAGIC_ADDR2 + step->idx[1]; - step->elemsz = 0x100; - - return ADDRXLAT_OK; -} - -PyDoc_STRVAR(get_custmeth__doc__, -"getCustomMethod(conv) -> CustomMethod\n\ -\n\ -Get a custom method that translates to a magic value."); - -static PyObject * -get_custmeth(PyObject *self, PyObject *args) -{ - PyObject *conv; - addrxlat_meth_t meth; - - if (!PyArg_ParseTuple(args, "O", &conv)) - return NULL; - - meth.kind = ADDRXLAT_CUSTOM; - meth.target_as = ADDRXLAT_NOADDR; - meth.param.custom.first_step = magic_first_step; - meth.param.custom.next_step = magic_next_step; - meth.param.custom.data = custom_magic_str; - return addrxlat_API->Method_FromPointer(conv, &meth); -} - -static PyMethodDef test_methods[] = { - { "getCustomMethod", (PyCFunction)get_custmeth, METH_VARARGS, - get_custmeth__doc__ }, - { NULL } -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef addrxlat_moddef = { - PyModuleDef_HEAD_INIT, - MOD_NAME, /* m_name */ - MOD_DOC, /* m_doc */ - -1, /* m_size */ - test_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -# define MOD_ERROR_VAL NULL -# define MOD_SUCCESS_VAL(val) val -#else -# define MOD_ERROR_VAL -# define MOD_SUCCESS_VAL(val) -#endif - -PyMODINIT_FUNC -#if PY_MAJOR_VERSION >= 3 -PyInit__test_addrxlat (void) -#else -init_test_addrxlat (void) -#endif -{ - PyObject *mod; - - addrxlat_API = (struct addrxlat_CAPI*) - PyCapsule_Import(addrxlat_CAPSULE_NAME, 0); - if (!addrxlat_API) - goto err; - if (addrxlat_API->ver < addrxlat_CAPI_VER) { - PyErr_Format(PyExc_RuntimeError, - "addrxlat CAPI ver >= %lu needed, %lu found", - addrxlat_CAPI_VER, addrxlat_API->ver); - goto err; - } - -#if PY_MAJOR_VERSION >= 3 - mod = PyModule_Create(&addrxlat_moddef); -#else - mod = Py_InitModule3(MOD_NAME, test_methods, MOD_DOC); -#endif - if (!mod) - goto err; - - return MOD_SUCCESS_VAL(mod); - - err: - return MOD_ERROR_VAL; -} diff --git a/python/test_addrxlat.py b/python/test_addrxlat.py deleted file mode 100644 index d65430de..00000000 --- a/python/test_addrxlat.py +++ /dev/null @@ -1,926 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -import 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 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, addrxlat.ADDR_MAX - 0x1234) - - 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, None) - 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, None) - 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, None) - 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, None) - 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 a sequence'): - meth.fields = None - with self.assertRaisesRegex(ValueError, - 'more than [0-9]+ address fields'): - 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, 'not a sequence'): - meth.tbl = None - with self.assertRaisesRegex(TypeError, 'not a sequence'): - meth.tbl = (None,) - with self.assertRaisesRegex(TypeError, 'not a sequence'): - meth.tbl = 1 - with self.assertRaisesRegex(TypeError, 'not a sequence'): - meth.tbl = (1,) - with self.assertRaisesRegex(ValueError, 'must be integer pairs'): - meth.tbl = ((),) - with self.assertRaisesRegex(ValueError, 'must be integer pairs'): - meth.tbl = ((1,),) - with self.assertRaisesRegex(ValueError, 'must be integer pairs'): - meth.tbl = ((1, 2, 3),) - with self.assertRaisesRegex(TypeError, 'must be.* a .*number'): - meth.tbl = ((None, None),) - with self.assertRaisesRegex(TypeError, 'must be.* a .*number'): - meth.tbl = ((1, None),) - with self.assertRaisesRegex(TypeError, 'must be.* a .*number'): - 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, None) - 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, None) - 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, None) - 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, None) - 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, None) - 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.assertIs(step.base, None) - 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.assertIs(step.base, None) - 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.assertIs(step.base, None) - 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.assertIs(step.base, None) - 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.assertIs(step.base, None) - 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.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.assertIs(step.base, None) - 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.assertIs(step.base, None) - self.assertIs(step.raw, None) - idx = idx + (0,) * (addrxlat.FIELDS_MAX + 1 - len(idx)) - self.assertEqual(step.idx, idx) - - with self.assertRaisesRegex(TypeError, 'not a sequence'): - step.idx = None - with self.assertRaisesRegex(ValueError, 'more than [0-9]+ indices'): - step.idx = (0,) * (addrxlat.FIELDS_MAX + 2) - with self.assertRaisesRegex(TypeError, 'must be.* a .*number'): - 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(addr): - # Page table level 2 @ 0 - if addr.addr == 0x10000: - return (bytearray((0x00, 0x00, 0x01, 0x01)), - addrxlat.BIG_ENDIAN) - # Page table level 1 @ 0x65 - if addr.addr == 0x10100 + 0x65 * 4: - return (bytearray((0x00, 0x00, 0x01, 0xc0)), - addrxlat.BIG_ENDIAN) - # Page table level 1 @ 0x41 - if addr.addr == 0x10100 + 0x41 * 4: - return (bytearray((0x00, 0x00, 0x01, 0xa9)), - addrxlat.BIG_ENDIAN) - # Memory array at 0x40 - if addr.addr == 0x11000 + 0x40 * 4: - return (bytearray((0x00, 0x00, 0x00, 0xaa)), - addrxlat.BIG_ENDIAN) - - def read_caps(): - return addrxlat.CAPS(addrxlat.MACHPHYSADDR) - - self.ctx = addrxlat.Context() - self.ctx.cb_read_caps = read_caps - 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.assertRaisesRegex(addrxlat.NoMethodError, 'Callback returned None'): - 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) - def cb_read_caps(self): - return addrxlat.CAPS(addrxlat.MACHPHYSADDR) - def cb_get_page(self, addr): - # Memory array at 0x40 - if addr.addr == 0x11000 + 0x40 * 4: - return (bytearray((0x00, 0x00, 0x00, 0x12)), - addrxlat.BIG_ENDIAN) - - ctx = mycontext() - addr = addrxlat.FullAddress(addrxlat.KVADDR, 0x4034) - addr.conv(addrxlat.KPHYSADDR, ctx, self.sys) - self.assertEqual(addr, addrxlat.FullAddress(addrxlat.KPHYSADDR, 0x1234)) - -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 - - import _test_addrxlat - self.meth_ext = _test_addrxlat.getCustomMethod(addrxlat.convert) - 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 = _test_addrxlat.getCustomMethod(addrxlat.convert) - 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.assertIs(step.base, None) - 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.assertIs(step.base, None) - self.meth_ext.cb_first_step(step, 0x1234) - self.assertEqual(step.base.addrspace, addrxlat.NOADDR) - self.assertEqual(step.base.addr, 0x4d795f4d61676963) - 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, 0x4d61676963546f6f + 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, 0x4d61676963546f6f + 0x4523) - - def test_customdesc_extmod_cb(self): - step = addrxlat.Step(ctx=self.ctx, meth=self.meth_extmod) - self.assertIs(step.base, None) - self.meth_extmod.cb_first_step(step, 0x1234) - self.assertEqual(step.base.addrspace, addrxlat.NOADDR) - self.assertEqual(step.base.addr, 0x4d795f4d61676963) - 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() diff --git a/python/test_addrxlat.sym b/python/test_addrxlat.sym deleted file mode 100644 index 3e6feb2a..00000000 --- a/python/test_addrxlat.sym +++ /dev/null @@ -1,2 +0,0 @@ -init_test_addrxlat -PyInit__test_addrxlat diff --git a/python/vtop.py b/python/vtop.py deleted file mode 100644 index fe8de98a..00000000 --- a/python/vtop.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# vim:sw=4 ts=4 et - -from __future__ import print_function -import kdumpfile -import addrxlat -from sys import argv - -tbl_names = ( 'PAGE', 'PTE', 'PMD', 'PUD', 'PGD' ) - -class kphysnote(object): - def __init__(self, ctx, sys): - self.ctx = ctx - self.sys = sys - - map = sys.get_map(addrxlat.SYS_MAP_MACHPHYS_KPHYS) - self.ident = True - for range in map: - if range.meth == addrxlat.SYS_METH_NONE: - continue - meth = sys.get_meth(range.meth) - if meth.kind != addrxlat.LINEAR or meth.off != 0: - self.ident = False - break - - def note(self, fulladdr, fmt='{}'): - if self.ident or fulladdr.addrspace == addrxlat.KPHYSADDR: - return '' - tmp = fulladdr.copy() - try: - tmp.conv(addrxlat.KPHYSADDR, self.ctx, self.sys) - return fmt.format('{:x}'.format(tmp.addr)) - except (addrxlat.NotPresentError, addrxlat.NoDataError): - return fmt.format('N/A') - -def vtop(addr, ctx, sys): - fulladdr = addrxlat.FullAddress(addrxlat.KVADDR, addr) - print('{:16} {:16}'.format('VIRTUAL', 'PHYSICAL')) - try: - fulladdr.conv(addrxlat.KPHYSADDR, ctx, sys) - print('{:<16x} {:<16x}\n'.format(addr, fulladdr.addr)) - except addrxlat.BaseException: - print('{:<16x} {:<16}\n'.format(addr, '---')) - - step = addrxlat.Step(ctx, sys) - meth = sys.get_map(addrxlat.SYS_MAP_HW).search(addr) - if meth == addrxlat.SYS_METH_NONE: - meth = sys.get_map(addrxlat.SYS_MAP_KV_PHYS).search(addr) - if meth == addrxlat.SYS_METH_NONE: - print('NO METHOD') - return - - step.meth = sys.get_meth(meth) - step.launch(addr) - - note = kphysnote(ctx, sys) - while step.remain: - tbl = tbl_names[step.remain - 1] - if step.remain > 1: - addr = step.base.copy() - addr.addr += step.idx[step.remain - 1] * step.elemsz - else: - addr = step.base - remark = note.note(addr, ' ({})') - print('{:>4}: {:16x}{}'.format(tbl, addr.addr, remark), end='') - - try: - step.step() - if step.remain and step.raw is not None: - print(' => {:x}'.format(step.raw)) - except addrxlat.NotPresentError: - print(' => {:x} NOT PRESENT'.format(step.raw)) - return - print() - -if len(argv) != 3: - print('Usage: {} '.format(argv[0])) - exit(1) - -kdf = kdumpfile.kdumpfile(argv[1]) -kdf.addrxlat_convert = addrxlat.convert -kdf.attr['addrxlat.ostype'] = 'linux' -sys = kdf.get_addrxlat_sys() -ctx = kdf.get_addrxlat_ctx() - -addr = int(argv[2], base=0) -try: - vtop(addr, ctx, sys) -except addrxlat.BaseException as e: - print('Translation failed: {}'.format(e.message)) diff --git a/src/addrxlat/Makefile.am b/src/addrxlat/Makefile.am index 2aa7ec19..69678d8e 100644 --- a/src/addrxlat/Makefile.am +++ b/src/addrxlat/Makefile.am @@ -36,7 +36,7 @@ libaddrxlat_la_SOURCES = \ s390x.c \ x86_64.c -libaddrxlat_la_LDFLAGS = -version-info 4:3:1 +libaddrxlat_la_LDFLAGS = -version-info 4:4:1 if HAVE_LD_VERSION_SCRIPT libaddrxlat_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libaddrxlat.map diff --git a/src/addrxlat/aarch64.c b/src/addrxlat/aarch64.c index cf7499be..687976c6 100644 --- a/src/addrxlat/aarch64.c +++ b/src/addrxlat/aarch64.c @@ -28,10 +28,11 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include -#include "addrxlat-priv.h" #include /** Maximum virtual address bits (architectural limit). */ diff --git a/src/addrxlat/arm.c b/src/addrxlat/arm.c index 66d3b8e2..9aa8d5ec 100644 --- a/src/addrxlat/arm.c +++ b/src/addrxlat/arm.c @@ -28,10 +28,10 @@ not, see . */ -#include - #include "addrxlat-priv.h" +#include + /* Maximum physical address bits (architectural limit) */ #define PHYSADDR_BITS_MAX 40 #define PHYSADDR_MASK ADDR_MASK(PHYSADDR_BITS_MAX) diff --git a/src/addrxlat/ctx.c b/src/addrxlat/ctx.c index d2bef0d4..ea152e8d 100644 --- a/src/addrxlat/ctx.c +++ b/src/addrxlat/ctx.c @@ -28,12 +28,12 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include #include -#include "addrxlat-priv.h" - /** Maximum length of the static error message. */ #define ERRBUF 64 diff --git a/src/addrxlat/ia32.c b/src/addrxlat/ia32.c index 37e774d6..2603a908 100644 --- a/src/addrxlat/ia32.c +++ b/src/addrxlat/ia32.c @@ -28,12 +28,12 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include #include -#include "addrxlat-priv.h" - #define PGD_PSE_HIGH_SHIFT 13 #define PGD_PSE_HIGH_BITS 8 #define PGD_PSE_HIGH_MASK ADDR_MASK(PGD_PSE_HIGH_BITS) diff --git a/src/addrxlat/map.c b/src/addrxlat/map.c index b17f1e83..75bb6169 100644 --- a/src/addrxlat/map.c +++ b/src/addrxlat/map.c @@ -28,11 +28,11 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include -#include "addrxlat-priv.h" - DEFINE_ALIAS(map_new); addrxlat_map_t * diff --git a/src/addrxlat/riscv64.c b/src/addrxlat/riscv64.c index 3a3334fb..885f7bb7 100644 --- a/src/addrxlat/riscv64.c +++ b/src/addrxlat/riscv64.c @@ -28,10 +28,11 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include -#include "addrxlat-priv.h" #include /** Maximum physical address bits (architectural limit) */ diff --git a/src/addrxlat/step.c b/src/addrxlat/step.c index 976a9c14..ab070867 100644 --- a/src/addrxlat/step.c +++ b/src/addrxlat/step.c @@ -28,10 +28,10 @@ not, see . */ -#include - #include "addrxlat-priv.h" +#include + int addrxlat_pteval_shift(addrxlat_pte_format_t fmt) { diff --git a/src/addrxlat/sys.c b/src/addrxlat/sys.c index fa0f8295..23d1a7af 100644 --- a/src/addrxlat/sys.c +++ b/src/addrxlat/sys.c @@ -28,11 +28,11 @@ not, see . */ +#include "addrxlat-priv.h" + #include #include -#include "addrxlat-priv.h" - addrxlat_sys_t * addrxlat_sys_new(void) { diff --git a/src/addrxlat/x86_64.c b/src/addrxlat/x86_64.c index 5624b829..7a9aac27 100644 --- a/src/addrxlat/x86_64.c +++ b/src/addrxlat/x86_64.c @@ -28,10 +28,10 @@ not, see . */ -#include - #include "addrxlat-priv.h" +#include + /* Maximum physical address bits (architectural limit) */ #define PHYSADDR_BITS_MAX 52 #define PHYSADDR_MASK ADDR_MASK(PHYSADDR_BITS_MAX) diff --git a/src/errmsg.h b/src/errmsg.h index 2c4b83b8..ac50352b 100644 --- a/src/errmsg.h +++ b/src/errmsg.h @@ -31,6 +31,8 @@ #ifndef _ERRMSG_H #define _ERRMSG_H 1 +#include "config.h" + #include #include #include diff --git a/src/list.h b/src/list.h index 92654ab7..3f196899 100644 --- a/src/list.h +++ b/src/list.h @@ -31,6 +31,8 @@ #ifndef _LIST_H #define _LIST_H 1 +#include "config.h" + #include /** Cast a structure field out to the containing structure. diff --git a/src/threads.h b/src/threads.h index ff3faafa..d8e6af27 100644 --- a/src/threads.h +++ b/src/threads.h @@ -31,6 +31,8 @@ #ifndef _THREADS_H #define _THREADS_H 1 +#include "config.h" + /* Multi-threading */ #if USE_PTHREAD diff --git a/tests/addrmap.c b/tests/addrmap.c index 0ee99e8b..4eed716e 100644 --- a/tests/addrmap.c +++ b/tests/addrmap.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - static void printmap(const addrxlat_map_t *map) { diff --git a/tests/addrxlat.c b/tests/addrxlat.c index 8b83d104..cca98c2d 100644 --- a/tests/addrxlat.c +++ b/tests/addrxlat.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -33,8 +35,6 @@ #include #include -#include "testutil.h" - #define ALLOC_INC 32 static size_t nentries; diff --git a/tests/attriter.c b/tests/attriter.c index 32291b2b..197ee825 100644 --- a/tests/attriter.c +++ b/tests/attriter.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - struct attrdef { const char *name; const char *value; diff --git a/tests/checkattr.c b/tests/checkattr.c index 70283f5b..537d6aef 100644 --- a/tests/checkattr.c +++ b/tests/checkattr.c @@ -28,6 +28,8 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include #include @@ -37,8 +39,6 @@ #include #include -#include "testutil.h" - static int check_noattr(kdump_ctx_t *ctx, char *key) { diff --git a/tests/clearattr.c b/tests/clearattr.c index 23ad94d3..8a8179bf 100644 --- a/tests/clearattr.c +++ b/tests/clearattr.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - #define ATTRPATH "linux.uts.sysname" #define ATTRVALUE "Linux" diff --git a/tests/custom-meth.c b/tests/custom-meth.c index e65a1ff0..198555b0 100644 --- a/tests/custom-meth.c +++ b/tests/custom-meth.c @@ -28,12 +28,12 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include -#include "testutil.h" - #define STEPS 2 #define XOR_VALUE 0xabcd #define OFFSET 0x1111 diff --git a/tests/data.c b/tests/data.c index a5805e3a..1c62e7a8 100644 --- a/tests/data.c +++ b/tests/data.c @@ -26,13 +26,13 @@ not, see . */ +#include "testutil.h" + #include #include #include #include -#include "testutil.h" - #define ALLOC_INC 4096 static int diff --git a/tests/diskdump.h b/tests/diskdump.h index f5bd07d5..cd139070 100644 --- a/tests/diskdump.h +++ b/tests/diskdump.h @@ -29,6 +29,8 @@ #ifndef _DISKDUMP_H #define _DISKDUMP_H 1 +#include "config.h" + #include #define MDF_SIGNATURE "makedumpfile" diff --git a/tests/dumpdata.c b/tests/dumpdata.c index 129a8a41..f19a15de 100644 --- a/tests/dumpdata.c +++ b/tests/dumpdata.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -34,8 +36,6 @@ #include #include -#include "testutil.h" - #define CHUNKSZ 256 #define BYTES_PER_LINE 16 diff --git a/tests/elf-prstatus-mod-x86_64.c b/tests/elf-prstatus-mod-x86_64.c index 137d4779..809da62c 100644 --- a/tests/elf-prstatus-mod-x86_64.c +++ b/tests/elf-prstatus-mod-x86_64.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -35,8 +37,6 @@ #include #include -#include "testutil.h" - struct timeval_64 { int64_t tv_sec; int64_t tv_usec; diff --git a/tests/err-addrxlat.c b/tests/err-addrxlat.c index 3673f543..372e71f7 100644 --- a/tests/err-addrxlat.c +++ b/tests/err-addrxlat.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -35,8 +37,6 @@ #include -#include "testutil.h" - /* To test all corner cases, this string should be bigger than * the internal fallback buffer (ERRBUF in addrxlat-priv.h) */ diff --git a/tests/fdset.c b/tests/fdset.c index d3ef061e..ea63a71c 100644 --- a/tests/fdset.c +++ b/tests/fdset.c @@ -26,13 +26,13 @@ not, see . */ +#include "testutil.h" + #include #include #include #include -#include "testutil.h" - #define FILENAME_0 "fileA" #define FILENAME_1 "fileB" diff --git a/tests/lkcd.h b/tests/lkcd.h index c4febe82..3aff5e07 100644 --- a/tests/lkcd.h +++ b/tests/lkcd.h @@ -29,6 +29,8 @@ #ifndef _LKCD_H #define _LKCD_H 1 +#include "config.h" + #include #define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL diff --git a/tests/mkbinary.c b/tests/mkbinary.c index 7319da95..cf39808f 100644 --- a/tests/mkbinary.c +++ b/tests/mkbinary.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -33,8 +35,6 @@ #include #include -#include "testutil.h" - static int parseheader(struct page_data *pg, char *p) { diff --git a/tests/mkdiskdump.c b/tests/mkdiskdump.c index de023d33..f32109fc 100644 --- a/tests/mkdiskdump.c +++ b/tests/mkdiskdump.c @@ -26,6 +26,9 @@ not, see . */ +#include "config.h" +#include "testutil.h" + #include #include #include @@ -34,8 +37,6 @@ #include #include -#include "config.h" -#include "testutil.h" #include "diskdump.h" #if USE_ZLIB diff --git a/tests/mkelf.c b/tests/mkelf.c index 71bfad0b..0e58d938 100644 --- a/tests/mkelf.c +++ b/tests/mkelf.c @@ -26,6 +26,9 @@ not, see . */ +#include "config.h" +#include "testutil.h" + #include #include #include @@ -36,8 +39,6 @@ #include #include -#include "config.h" -#include "testutil.h" #include "diskdump.h" typedef int write_fn(FILE *); diff --git a/tests/mklkcd.c b/tests/mklkcd.c index 49b57a0a..57ea977a 100644 --- a/tests/mklkcd.c +++ b/tests/mklkcd.c @@ -26,6 +26,9 @@ not, see . */ +#include "config.h" +#include "testutil.h" + #include #include #include @@ -33,8 +36,6 @@ #include #include -#include "config.h" -#include "testutil.h" #include "lkcd.h" #if USE_ZLIB diff --git a/tests/mksadump.c b/tests/mksadump.c index a29500fe..aa8e5f8f 100644 --- a/tests/mksadump.c +++ b/tests/mksadump.c @@ -26,6 +26,9 @@ not, see . */ +#include "config.h" +#include "testutil.h" + #include #include #include @@ -33,8 +36,6 @@ #include #include -#include "config.h" -#include "testutil.h" #include "sadump.h" #define WS_CHARS " \f\n\r\t\v" diff --git a/tests/multiread.c b/tests/multiread.c index 055155ca..218ffc98 100644 --- a/tests/multiread.c +++ b/tests/multiread.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -36,8 +38,6 @@ #include #include -#include "testutil.h" - #define DEFITER 1000 #define DEFTHREADS 1 diff --git a/tests/multixlat.c b/tests/multixlat.c index 2ce6165e..86fb3b26 100755 --- a/tests/multixlat.c +++ b/tests/multixlat.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -35,8 +37,6 @@ #include #include -#include "testutil.h" - #define CHUNKSZ 256 #define BYTES_PER_LINE 16 diff --git a/tests/nometh.c b/tests/nometh.c index 12eeb784..d37eabac 100644 --- a/tests/nometh.c +++ b/tests/nometh.c @@ -28,12 +28,12 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include -#include "testutil.h" - static int setup_pgt(addrxlat_ctx_t *ctx, addrxlat_sys_t *sys) { diff --git a/tests/param.c b/tests/param.c index 1fb0d8cb..439ef40b 100644 --- a/tests/param.c +++ b/tests/param.c @@ -26,13 +26,13 @@ not, see . */ +#include "testutil.h" + #include #include #include #include -#include "testutil.h" - #define ARRAY_SEPARATORS " \t" static char diff --git a/tests/sadump.h b/tests/sadump.h index bad0d37a..4b18442c 100644 --- a/tests/sadump.h +++ b/tests/sadump.h @@ -29,6 +29,8 @@ #ifndef _SADUMP_H #define _SADUMP_H 1 +#include "config.h" + #include /** Standard EFI time specification. */ diff --git a/tests/slurp.c b/tests/slurp.c index 6d027bc6..e13f7db4 100644 --- a/tests/slurp.c +++ b/tests/slurp.c @@ -26,13 +26,13 @@ not, see . */ +#include "testutil.h" + #include #include #include #include -#include "testutil.h" - #define WATERMARK_LOW 256 #define WATERMARK_HIGH 1024 diff --git a/tests/subattr.c b/tests/subattr.c index ef4fc9e1..7c16623f 100644 --- a/tests/subattr.c +++ b/tests/subattr.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - #define ATTRDIR "linux.uts" #define ATTRNAME "sysname" #define ATTRPATH ATTRDIR "." ATTRNAME diff --git a/tests/sys-xlat.c b/tests/sys-xlat.c index 7043eecc..e11070a9 100644 --- a/tests/sys-xlat.c +++ b/tests/sys-xlat.c @@ -28,6 +28,8 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include #include @@ -36,8 +38,6 @@ #include #include -#include "testutil.h" - static char *data_file; static char *cfg_file; diff --git a/tests/testutil.h b/tests/testutil.h index ee53f3f6..ae4db464 100644 --- a/tests/testutil.h +++ b/tests/testutil.h @@ -29,6 +29,8 @@ #ifndef _TESTUTIL_H #define _TESTUTIL_H 1 +#include "config.h" + #include #include #include diff --git a/tests/thread-errstr.c b/tests/thread-errstr.c index c5a69f9e..0cfa3f75 100644 --- a/tests/thread-errstr.c +++ b/tests/thread-errstr.c @@ -26,6 +26,8 @@ not, see . */ +#include "testutil.h" + #include #include #include @@ -35,8 +37,6 @@ #include #include -#include "testutil.h" - static pthread_mutex_t attr_mutex = PTHREAD_MUTEX_INITIALIZER; static enum { diff --git a/tests/typed-attr.c b/tests/typed-attr.c index a0c68ea4..c5234f93 100644 --- a/tests/typed-attr.c +++ b/tests/typed-attr.c @@ -26,10 +26,10 @@ not, see . */ -#include - #include "testutil.h" +#include + #define ATTR_CACHE_SIZE "cache.size" #define ATTR_SYSNAME "linux.uts.sysname" #define ATTR_PHYS_BASE "linux.phys_base" diff --git a/tests/vmci-cleanup.c b/tests/vmci-cleanup.c index af197ce5..4b0e3fea 100644 --- a/tests/vmci-cleanup.c +++ b/tests/vmci-cleanup.c @@ -26,13 +26,13 @@ not, see . */ +#include "testutil.h" + #include #include #include #include -#include "testutil.h" - static const char vmcore1[] = "DIR.SUB.VAL=test1\n"; diff --git a/tests/vmci-lines-post.c b/tests/vmci-lines-post.c index d77d8529..2e1876f5 100644 --- a/tests/vmci-lines-post.c +++ b/tests/vmci-lines-post.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - #define xstr(s) #s #define str(s) xstr(s) diff --git a/tests/vmci-post.c b/tests/vmci-post.c index cae8d659..ede5fa29 100644 --- a/tests/vmci-post.c +++ b/tests/vmci-post.c @@ -26,12 +26,12 @@ not, see . */ +#include "testutil.h" + #include #include #include -#include "testutil.h" - #define xstr(s) #s #define str(s) xstr(s) diff --git a/tests/xlat-linux-x86_64-6.11-pti-user-ver b/tests/xlat-linux-x86_64-6.11-pti-user-ver index 43d500d1..427985bc 100755 --- a/tests/xlat-linux-x86_64-6.11-pti-user-ver +++ b/tests/xlat-linux-x86_64-6.11-pti-user-ver @@ -14,5 +14,5 @@ opts=( osver=0x060b00 ) -name=xlat-linux-x86_64-6.11-pti-user +srcname=xlat-linux-x86_64-6.11-pti-user . "$srcdir"/xlat-os-common diff --git a/tests/xlat-os-common b/tests/xlat-os-common index a308a743..7dcdee91 100644 --- a/tests/xlat-os-common +++ b/tests/xlat-os-common @@ -4,13 +4,14 @@ mkdir -p out || exit 99 -if [ -z "$name" ]; then - name=$( basename "$0" ) +name=$( basename "$0" ) +if [ -z "$srcname" ]; then + srcname="$name" fi resultfile="out/${name}.result" -expectfile="$srcdir/$name.expect" -symfile="$srcdir/$name.sym" -datafile="$srcdir/$name.data" +expectfile="$srcdir/$srcname.expect" +symfile="$srcdir/$srcname.sym" +datafile="$srcdir/$srcname.data" cfgfile="out/${name}.cfg" optspec= diff --git a/tests/xlat-os.c b/tests/xlat-os.c index 25072a41..8d6be8f5 100644 --- a/tests/xlat-os.c +++ b/tests/xlat-os.c @@ -28,6 +28,8 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include #include @@ -37,8 +39,6 @@ #include -#include "testutil.h" - struct cbdata { addrxlat_ctx_t *ctx; addrxlat_sys_t *sys; diff --git a/tests/xlatmap.c b/tests/xlatmap.c index b6f7b73c..53e07f00 100644 --- a/tests/xlatmap.c +++ b/tests/xlatmap.c @@ -28,14 +28,14 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include #include #include #include -#include "testutil.h" - #define NMAPS 15 static addrxlat_map_t *map[NMAPS]; diff --git a/tests/xlatop.c b/tests/xlatop.c index 03d18431..ac56fd03 100644 --- a/tests/xlatop.c +++ b/tests/xlatop.c @@ -28,12 +28,12 @@ #define _GNU_SOURCE +#include "testutil.h" + #include #include -#include "testutil.h" - struct test { addrxlat_fulladdr_t addr; addrxlat_fulladdr_t expect; diff --git a/python/addrxlat/Makefile.am b/tools/Makefile.am similarity index 84% rename from python/addrxlat/Makefile.am rename to tools/Makefile.am index b4db1ac6..0425a79e 100644 --- a/python/addrxlat/Makefile.am +++ b/tools/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to create Makefile.in ## Configure input file for libkdumpfile. ## -## Copyright (C) 2017 Ales Novak +## Copyright (C) 2024 Petr Tesarik ## ## This file is part of libkdumpfile. ## @@ -19,8 +19,8 @@ ## along with this program. If not, see . ## -pyaddrxlatdir = $(pythondir)/addrxlat +SUBDIRS = -pyaddrxlat_PYTHON = \ - __init__.py \ - exceptions.py +if BUILD_KDUMPID +SUBDIRS += kdumpid +endif diff --git a/tools/kdumpid/.gitignore b/tools/kdumpid/.gitignore new file mode 100644 index 00000000..3295c678 --- /dev/null +++ b/tools/kdumpid/.gitignore @@ -0,0 +1,2 @@ +# Resulting binaries +kdumpid diff --git a/python/kdumpfile/Makefile.am b/tools/kdumpid/Makefile.am similarity index 60% rename from python/kdumpfile/Makefile.am rename to tools/kdumpid/Makefile.am index ba5459d0..54debc8a 100644 --- a/python/kdumpfile/Makefile.am +++ b/tools/kdumpid/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to create Makefile.in ## Configure input file for libkdumpfile. ## -## Copyright (C) 2015 Ales Novak +## Copyright (C) 2024 Petr Tesarik ## ## This file is part of libkdumpfile. ## @@ -19,9 +19,31 @@ ## along with this program. If not, see . ## -pykdumpfiledir = $(pythondir)/kdumpfile +AM_CPPFLAGS = -I$(top_builddir)/include \ + -DVER_MAJOR=$(KDUMPID_VER_MAJOR) \ + -DVER_MINOR=$(KDUMPID_VER_MINOR) -pykdumpfile_PYTHON = \ - __init__.py \ - exceptions.py \ - views.py +AM_CFLAGS = \ + $(ZLIB_CFLAGS) + +LIBS = \ + $(top_builddir)/src/kdumpfile/libkdumpfile.la \ + $(top_builddir)/src/addrxlat/libaddrxlat.la \ + $(ZLIB_LIBS) \ + $(DIS_ASM_LIBS) + +kdumpid_SOURCES = \ + main.c \ + util.c \ + search.c \ + ppc.c \ + ppc64.c \ + s390.c \ + x86.c + +noinst_HEADERS = \ + kdumpid.h + +bin_PROGRAMS = kdumpid + +dist_man_MANS = kdumpid.1 diff --git a/tools/kdumpid/kdumpid.1 b/tools/kdumpid/kdumpid.1 new file mode 100644 index 00000000..11a6f81c --- /dev/null +++ b/tools/kdumpid/kdumpid.1 @@ -0,0 +1,55 @@ +.TH KDUMPID 1 "4 Nov 2011" +.SH NAME +KdumpID \- A tool to identify kernel memory dumps +.SH SYNOPSIS +.B kdumpid +.I [-v] +.SH "DESCRIPTION" +.B kdumpid +provides a fast and reliable method to find out the most +important information about an unknown kernel crash dump, +such as the architecture and kernel release. Think of it +as a kind of "file" utility for kernel dumps. +.LP +At present, +.B kdumpid +can read: +.LP +\- LKCD files +.br +\- DISKDUMP/KDUMP files +.br +\- ELF dumps (including support for both Xen Dom0 and DomU). +.LP +The following architectures are fully supported: +.LP +\- x86 +.br +\- x86-64 +.br +\- ppc +.br +\- ppc64 +.br +\- s390 +.br +\- s390x. +.LP +Other architectures may produce some output if the information +can be found in the file header. +.SH "OPERATION" +By default, +.B kdumpid +will print the kernel dump's format, architecture and version. +.SH "OPTIONS" +.TP +\fB\-v\fR +Try to extract and print additional information from +the memory dump, such as: the machine type, the full +kernel banner string and the kernel configuration flavor. +.SH "SEE ALSO" +.BR crash (8), +.BR makedumpfile (8), +.BR kdump (7). +.SH AUTHOR +KdumpID was written by Petr Tesarik. diff --git a/tools/kdumpid/kdumpid.h b/tools/kdumpid/kdumpid.h new file mode 100644 index 00000000..d358fa72 --- /dev/null +++ b/tools/kdumpid/kdumpid.h @@ -0,0 +1,119 @@ +#ifndef __KDUMPID_H +#define __KDUMPID_H + +#include "config.h" + +#include +#include +#include +#include + +/* Older glibc didn't have the byteorder macros */ +#ifndef be16toh + +#include + +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define htobe16(x) bswap_16(x) +# define htole16(x) (x) +# define be16toh(x) bswap_16(x) +# define le16toh(x) (x) + +# define htobe32(x) bswap_32(x) +# define htole32(x) (x) +# define be32toh(x) bswap_32(x) +# define le32toh(x) (x) + +# define htobe64(x) bswap_64(x) +# define htole64(x) (x) +# define be64toh(x) bswap_64(x) +# define le64toh(x) (x) +# else +# define htobe16(x) (x) +# define htole16(x) bswap_16(x) +# define be16toh(x) (x) +# define le16toh(x) bswap_16(x) + +# define htobe32(x) (x) +# define htole32(x) bswap_32(x) +# define be32toh(x) (x) +# define le32toh(x) bswap_32(x) + +# define htobe64(x) (x) +# define htole64(x) bswap_64(x) +# define be64toh(x) (x) +# define le64toh(x) bswap_64(x) +# endif + +#endif + +#define INVALID_ADDR ((uint64_t)-1ULL) + +struct dump_desc; + +struct dump_desc { + const char *name; /* file name */ + long flags; /* see DIF_XXX below */ + int fd; /* dump file descriptor */ + kdump_ctx_t *ctx; /* kdumpfile context */ + + void *page; /* page data buffer */ + kdump_num_t page_size; /* target page size */ + kdump_num_t max_pfn; /* max PFN for read_page */ + + const char *format; /* format name */ + + const char *arch; /* architecture (if known) */ + kdump_num_t endian; /* target byte order */ + uint64_t start_addr; /* kernel start address */ + + char machine[66]; /* arch name (utsname machine) */ + char ver[66]; /* version (utsname release) */ + char banner[256]; /* Linux banner */ + + char *cfg; /* kernel configuration */ + size_t cfglen; + + kdump_num_t xen_type; /* Xen dump type (or kdump_xen_none) */ + uint64_t xen_start_info; /* address of Xen start info */ + + void *priv; +}; + +/* Kdumpid flags */ +#define DIF_VERBOSE 1 +#define DIF_FORCE 2 +#define DIF_START_FOUND 8 + +/* Arch-specific helpers */ +int looks_like_kcode_ppc(struct dump_desc *dd, uint64_t addr); +int looks_like_kcode_ppc64(struct dump_desc *dd, uint64_t addr); +int looks_like_kcode_s390(struct dump_desc *dd, uint64_t addr); +int looks_like_kcode_x86(struct dump_desc *dd, uint64_t addr); + +/* provide our own definition of new_utsname */ +struct new_utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +/* utils */ + +int get_version_from_banner(struct dump_desc *dd); +int need_explore(struct dump_desc *dd); + +int read_page(struct dump_desc *dd, unsigned long pfn); +size_t dump_cpin(struct dump_desc *dd, void *buf, uint64_t paddr, size_t len); + +int uncompress_config(struct dump_desc *dd, void *zcfg, size_t zsize); +uint64_t dump_search_range(struct dump_desc *dd, + uint64_t start, uint64_t end, + const unsigned char *needle, size_t len); + +int explore_raw_data(struct dump_desc *dd); + +#endif /* __KDUMPID_H */ diff --git a/tools/kdumpid/main.c b/tools/kdumpid/main.c new file mode 100644 index 00000000..53e755af --- /dev/null +++ b/tools/kdumpid/main.c @@ -0,0 +1,270 @@ +/* + * main.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. + */ + +#define _GNU_SOURCE + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdumpid.h" + +static void +print_xen_info(kdump_ctx_t *ctx) +{ + kdump_attr_t attr; + kdump_status status; + + fputs("Xen: ", stdout); + status = kdump_get_attr(ctx, "xen.version.major", &attr); + if (status == KDUMP_OK) + printf("%" KDUMP_PRIuNUM ".", attr.val.number); + else + fputs("?.", stdout); + + status = kdump_get_attr(ctx, "xen.version.minor", &attr); + if (status == KDUMP_OK) + printf("%" KDUMP_PRIuNUM, attr.val.number); + else + fputs("?", stdout); + + status = kdump_get_attr(ctx, "xen.version.extra", &attr); + if (status == KDUMP_OK) + puts(attr.val.string); + else + putchar('\n'); +} + +static void +version(FILE *out, const char *progname) +{ + fprintf(out, "%s version %d.%d\n", + basename(progname), VER_MAJOR, VER_MINOR); +} + +static void +help(FILE *out, const char *progname) +{ + fprintf(out, "Usage: %s [-f] [-v] \n", + basename(progname)); +} + +#define SHORTOPTS "fhv" + +static void +print_verbose(struct dump_desc *dd) +{ + if (dd->machine[0]) + printf("Machine: %s\n", dd->machine); + if (*dd->banner) + printf("Banner: %s\n", dd->banner); + + if (dd->cfg) { + char *local = strstr(dd->cfg, "CONFIG_LOCALVERSION="); + if (local) { + char c, *end = strchr(local, '\n'); + if (end) { + c = *end; + *end = 0; + } + printf("Cfg release: %s\n", local + 20); + if (end) + *end = c; + } + } +} + +int +main(int argc, char **argv) +{ + static const struct option opts[] = { + { "force", no_argument, NULL, 'f' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 256 }, + {0, 0, 0, 0} + }; + struct dump_desc dd; + const char *str; + kdump_status status; + int c, opt; + + /* Initialize dd */ + memset(&dd, 0, sizeof dd); + + while ( (c = getopt_long(argc, argv, SHORTOPTS, opts, &opt)) != -1 ) + switch(c) { + case 'f': + dd.flags |= DIF_FORCE; + break; + case 'h': + help(stdout, argv[0]); + return 0; + case 'v': + dd.flags |= DIF_VERBOSE; + break; + case 256: + version(stdout, argv[0]); + return 0; + } + + if (argc - optind != 1) { + help(stderr, argv[0]); + return 1; + } + dd.name = argv[optind]; + + if ((dd.fd = open(dd.name, O_RDONLY)) < 0) { + perror(dd.name); + return 2; + } + + dd.ctx = kdump_new(); + if (!dd.ctx) { + perror("Cannot allocate dump file context"); + close(dd.fd); + return 2; + } + + status = kdump_set_number_attr(dd.ctx, KDUMP_ATTR_ZERO_EXCLUDED, 1); + if (status != KDUMP_OK) + fprintf(stderr, "WARNING: Excluded pages are not zeroed: %s\n", + kdump_get_err(dd.ctx)); + + status = kdump_set_number_attr(dd.ctx, KDUMP_ATTR_FILE_FD, dd.fd); + if (status != KDUMP_OK) { + fprintf(stderr, "File initialization failed: %s\n", + kdump_get_err(dd.ctx)); + close(dd.fd); + return 2; + } + + if (dd.flags & DIF_FORCE) { + status = kdump_get_number_attr(dd.ctx, "max_pfn", + &dd.max_pfn); + if (status != KDUMP_OK) { + fprintf(stderr, "Cannot get max PFN: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + } + + kdump_set_string_attr(dd.ctx, KDUMP_ATTR_OSTYPE, "linux"); + + status = kdump_get_number_attr(dd.ctx, KDUMP_ATTR_PAGE_SIZE, + &dd.page_size); + if (status != KDUMP_OK) { + fprintf(stderr, "Cannot get page size: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_string_attr(dd.ctx, "linux.uts.release", &str); + if (status == KDUMP_OK) + strcpy(dd.ver, str); + else if (status == KDUMP_ERR_NODATA) + dd.ver[0] = '\0'; + else { + fprintf(stderr, "Cannot get UTS release: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_string_attr(dd.ctx, "linux.uts.machine", &str); + if (status == KDUMP_OK) + strcpy(dd.machine, str); + else if (status == KDUMP_ERR_NODATA) + dd.machine[0] = '\0'; + else { + fprintf(stderr, "Cannot get UTS machine: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_string_attr(dd.ctx, KDUMP_ATTR_ARCH_NAME, &dd.arch); + if (status == KDUMP_ERR_NODATA) + dd.arch = NULL; + else if (status != KDUMP_OK) { + fprintf(stderr, "Cannot get architecture name: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_number_attr(dd.ctx, "arch.byte_order", &dd.endian); + if (status == KDUMP_ERR_NODATA) + dd.endian = (kdump_num_t)-1; + else if (status != KDUMP_OK) { + fprintf(stderr, "Cannot get architecture byte order: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_string_attr(dd.ctx, KDUMP_ATTR_FILE_FORMAT, + &dd.format); + if (status == KDUMP_ERR_NODATA) + dd.format = NULL; + else if (status != KDUMP_OK) { + fprintf(stderr, "Cannot get architecture name: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + status = kdump_get_number_attr(dd.ctx, KDUMP_ATTR_XEN_TYPE, + &dd.xen_type); + if (status == KDUMP_ERR_NODATA) + dd.xen_type = KDUMP_XEN_NONE; + else if (status != KDUMP_OK) { + fprintf(stderr, "Cannot determine Xen type: %s\n", + kdump_get_err(dd.ctx)); + kdump_free(dd.ctx); + return 2; + } + + if (need_explore(&dd)) + explore_raw_data(&dd); + + if (!*dd.ver) + get_version_from_banner(&dd); + + printf("Format: %s%s\n", dd.format ?: "", + dd.xen_type != KDUMP_XEN_NONE ? ", Xen" : ""); + printf("Arch: %s\n", dd.arch); + printf("Version: %s\n", dd.ver); + if (dd.xen_type != KDUMP_XEN_NONE) + print_xen_info(dd.ctx); + + if (dd.flags & DIF_VERBOSE) + print_verbose(&dd); + + /* Intentionally ignore errors on close */ + kdump_free(dd.ctx); + close(dd.fd); + + return 0; +} diff --git a/tools/kdumpid/ppc.c b/tools/kdumpid/ppc.c new file mode 100644 index 00000000..dd97e839 --- /dev/null +++ b/tools/kdumpid/ppc.c @@ -0,0 +1,163 @@ +/* + * ppc.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. + */ + +#include "config.h" + +#include +#include + +#include + +#include "kdumpid.h" + +#define MAX_INSN_LEN 100 + +struct disas_state { + unsigned long flags; +}; + +#define SRR0_SET 1 +#define SRR1_SET 2 + +struct disas_priv { + char *iptr; + struct disas_state state; + + char insn[MAX_INSN_LEN]; +}; + +static const char sep[] = ", \t\r\n"; +#define wsep (sep+1) + +static disassembler_ftype print_insn; + +static void +append_insn(void *data, const char *fmt, va_list va) +{ + struct disas_priv *priv = data; + size_t remain; + int len; + + remain = priv->insn + sizeof(priv->insn) - priv->iptr; + len = vsnprintf(priv->iptr, remain, fmt, va); + if (len > 0) + priv->iptr += len; + +} + +static int +disas_fn(void *data, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#ifdef DIS_ASM_STYLED_PRINTF + +static int +disas_styled_fn(void *data, enum disassembler_style style, + const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#endif /* DIS_ASM_STYLED_PRINTF */ + +static void error_func(int status, bfd_vma memaddr, + struct disassemble_info *dinfo) +{ + /* intentionally empty */ +} + +static int +disas_at(struct dump_desc *dd, struct disassemble_info *info, unsigned pc) +{ + struct disas_priv *priv = info->stream; + char *toksave; + char *insn; + int count; + + do { + priv->iptr = priv->insn; + count = print_insn(info->buffer_vma + pc, info); + if (count < 0) + break; + pc += count; + + insn = strtok_r(priv->insn, wsep, &toksave); + + /* for historical reasons, ppc starts with 3 NOPs */ + if (pc <= 3 * 4 && strcmp(insn, "nop")) + break; + + /* MMU is switched on with an rfi */ + if (priv->state.flags & SRR0_SET && + priv->state.flags & SRR1_SET && + !strcmp(insn, "rfi")) + return 1; + + if (!strcmp(insn, "mtsrr0")) + priv->state.flags |= SRR0_SET; + if (!strcmp(insn, "mtsrr1")) + priv->state.flags |= SRR1_SET; + + /* invalid instruction? */ + if (!strcmp(insn, ".long")) + break; + } while (count > 0); + + return 0; +} + +int +looks_like_kcode_ppc(struct dump_desc *dd, uint64_t addr) +{ + struct disassemble_info info; + struct disas_priv priv; + + /* check ppc startup code */ + if (read_page(dd, addr / dd->page_size)) + return -1; + + memset(&priv, 0, sizeof priv); +#ifdef DIS_ASM_STYLED_PRINTF + init_disassemble_info(&info, &priv, disas_fn, disas_styled_fn); +#else + init_disassemble_info(&info, &priv, disas_fn); +#endif + info.memory_error_func = error_func; + info.buffer = dd->page; + info.buffer_vma = addr; + info.buffer_length = dd->page_size; + info.arch = bfd_arch_powerpc; + info.mach = bfd_mach_ppc; + disassemble_init_for_target(&info); + print_insn = disassembler(bfd_arch_powerpc, + dd->endian != KDUMP_LITTLE_ENDIAN, + bfd_mach_ppc, NULL); + if (!print_insn) + return 0; + return disas_at(dd, &info, 0); +} diff --git a/tools/kdumpid/ppc64.c b/tools/kdumpid/ppc64.c new file mode 100644 index 00000000..0cce8021 --- /dev/null +++ b/tools/kdumpid/ppc64.c @@ -0,0 +1,179 @@ +/* + * ppc64.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. + */ + +#include "config.h" + +#include +#include + +#include + +#include "kdumpid.h" + +#define MAX_INSN_LEN 100 + +struct disas_state { + unsigned long flags; +}; + +#define SRR0_SET 1 +#define SRR1_SET 2 + +struct disas_priv { + char *iptr; + struct disas_state state; + + char insn[MAX_INSN_LEN]; +}; + +static const char sep[] = ", \t\r\n"; +#define wsep (sep+1) + +static disassembler_ftype print_insn; + +static void +append_insn(void *data, const char *fmt, va_list va) +{ + struct disas_priv *priv = data; + size_t remain; + int len; + + remain = priv->insn + sizeof(priv->insn) - priv->iptr; + len = vsnprintf(priv->iptr, remain, fmt, va); + if (len > 0) + priv->iptr += len; +} + +static int +disas_fn(void *data, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#ifdef DIS_ASM_STYLED_PRINTF + +static int +disas_styled_fn(void *data, enum disassembler_style style, + const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#endif /* DIS_ASM_STYLED_PRINTF */ + +static void +print_address(bfd_vma addr, struct disassemble_info *info) +{ + struct disas_priv *priv = info->stream; + size_t remain = priv->insn + sizeof(priv->insn) - priv->iptr; + int len = snprintf(priv->iptr, remain, + "0x%llx", (unsigned long long) addr); + if (len > 0) + priv->iptr += len; +} + +static void error_func(int status, bfd_vma memaddr, + struct disassemble_info *dinfo) +{ + /* intentionally empty */ +} + +static int +disas_at(struct dump_desc *dd, struct disassemble_info *info, unsigned pc) +{ + struct disas_priv *priv = info->stream; + char *toksave; + char *insn; + int count; + + do { + priv->iptr = priv->insn; + count = print_insn(info->buffer_vma + pc, info); + if (count < 0) + break; + pc += count; + + insn = strtok_r(priv->insn, wsep, &toksave); + + /* ppc64 starts with a jump instruction, but it + * may be NOPped out at runtime */ + if (pc == 4 && strcmp(insn, "b") && strcmp(insn, "nop")) + return 0; + + /* The next instruction should be a trap */ + if (pc == 8 && strcmp(insn, "trap")) + return 0; + + /* MSR can be modiied only in supervisor mode */ + if (!strcmp(insn, "mtmsrd")) + return 1; + + /* Alternatively, a good rfid will also serve */ + if (priv->state.flags & SRR0_SET && + priv->state.flags & SRR1_SET && + !strcmp(insn, "rfid")) + return 1; + + if (!strcmp(insn, "mtsrr0")) + priv->state.flags |= SRR0_SET; + if (!strcmp(insn, "mtsrr1")) + priv->state.flags |= SRR1_SET; + } while (count > 0); + + return 0; +} + +int +looks_like_kcode_ppc64(struct dump_desc *dd, uint64_t addr) +{ + struct disassemble_info info; + struct disas_priv priv; + + /* check ppc64 startup code */ + if (read_page(dd, addr / dd->page_size)) + return -1; + + memset(&priv, 0, sizeof priv); +#ifdef DIS_ASM_STYLED_PRINTF + init_disassemble_info(&info, &priv, disas_fn, disas_styled_fn); +#else + init_disassemble_info(&info, &priv, disas_fn); +#endif + info.print_address_func = print_address; + info.memory_error_func = error_func; + info.buffer = dd->page; + info.buffer_vma = addr; + info.buffer_length = dd->page_size; + info.arch = bfd_arch_powerpc; + info.mach = bfd_mach_ppc64; + disassemble_init_for_target(&info); + print_insn = disassembler(bfd_arch_powerpc, + dd->endian != KDUMP_LITTLE_ENDIAN, + bfd_mach_ppc64, NULL); + if (!print_insn) + return 0; + return disas_at(dd, &info, 0); +} diff --git a/tools/kdumpid/s390.c b/tools/kdumpid/s390.c new file mode 100644 index 00000000..4be51146 --- /dev/null +++ b/tools/kdumpid/s390.c @@ -0,0 +1,172 @@ +/* + * s390.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. + */ + +#include "config.h" + +#include +#include + +#include + +#include "kdumpid.h" + +#define DEFAULT_ZIPL_OFFSET 0x08000 +#define DEFAULT_LOAD_ADDR 0x10000 + +/* Minimum length of correctly decoded instructions */ +#define MIN_STARTUP_SIZE 0x40 + +#define MAX_INSN_LEN 100 + +struct disas_state { + unsigned long flags; +}; + +#define SAM64_SEEN 1 + +struct disas_priv { + char *iptr; + struct disas_state state; + + char insn[MAX_INSN_LEN]; +}; + +static const char sep[] = ", \t\r\n"; +#define wsep (sep+1) + +static disassembler_ftype print_insn; + +static void +append_insn(void *data, const char *fmt, va_list va) +{ + struct disas_priv *priv = data; + size_t remain; + int len; + + remain = priv->insn + sizeof(priv->insn) - priv->iptr; + len = vsnprintf(priv->iptr, remain, fmt, va); + if (len > 0) + priv->iptr += len; +} + +static int +disas_fn(void *data, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#ifdef DIS_ASM_STYLED_PRINTF + +static int +disas_styled_fn(void *data, enum disassembler_style style, + const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#endif /* DIS_ASM_STYLED_PRINTF */ + +static void error_func(int status, bfd_vma memaddr, + struct disassemble_info *dinfo) +{ + /* intentionally empty */ +} + +static int +disas_at(struct dump_desc *dd, struct disassemble_info *info, unsigned pc) +{ + struct disas_priv *priv = info->stream; + char *toksave; + char *insn; + int count; + + do { + priv->iptr = priv->insn; + count = print_insn(info->buffer_vma + pc, info); + if (count < 0) + break; + pc += count; + + insn = strtok_r(priv->insn, wsep, &toksave); + + /* s390 setup code always starts with a basr instruction */ + if (pc == 0 && strcmp(insn, "basr")) + break; + + /* Recognize z/Architecture from ESA/390 */ + if (!strcmp(insn, "sam64")) + priv->state.flags |= SAM64_SEEN; + + /* invalid instruction? */ + if (!strcmp(insn, ".long")) + break; + } while (count > 0); + + return (pc >= MIN_STARTUP_SIZE); +} + +int +looks_like_kcode_s390(struct dump_desc *dd, uint64_t addr) +{ + struct disassemble_info info; + struct disas_priv priv; + int ret = 0; + + /* check zIPL signature */ + if (read_page(dd, (addr + DEFAULT_ZIPL_OFFSET) / dd->page_size)) + return -1; + + if (!memcmp(dd->page, "zIPL", 4)) + ret |= 1; + + /* check s390 startup code */ + if (read_page(dd, (addr + DEFAULT_LOAD_ADDR) / dd->page_size)) + return -1; + + memset(&priv, 0, sizeof priv); +#ifdef DIS_ASM_STYLED_PRINTF + init_disassemble_info(&info, &priv, disas_fn, disas_styled_fn); +#else + init_disassemble_info(&info, &priv, disas_fn); +#endif + info.memory_error_func = error_func; + info.buffer = dd->page; + info.buffer_vma = addr + DEFAULT_LOAD_ADDR; + info.buffer_length = dd->page_size; + info.arch = bfd_arch_s390; + info.mach = bfd_mach_s390_64; + disassemble_init_for_target(&info); + print_insn = disassembler(bfd_arch_s390, TRUE, + bfd_mach_s390_64, NULL); + if (!print_insn) + return 0; + ret |= disas_at(dd, &info, 0); + + if (ret > 0 && priv.state.flags & SAM64_SEEN) + dd->arch = "s390x"; + + return ret; +} diff --git a/tools/kdumpid/search.c b/tools/kdumpid/search.c new file mode 100644 index 00000000..99721846 --- /dev/null +++ b/tools/kdumpid/search.c @@ -0,0 +1,183 @@ +/* + * search.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. + */ + +#include "config.h" + +#include +#include + +#include "kdumpid.h" + +static void +compute_badchar(ssize_t *badchar, const unsigned char *s, ssize_t len) +{ + size_t i = 1; + while (i < len) + badchar[*s++] = i++; +} + +static void +compute_sfx(ssize_t *sfx, const unsigned char *s, ssize_t len) +{ + ssize_t f, g, i; + + sfx[len - 1] = len; + f = 0; /* bogus assignment to silence a warning */ + g = len - 1; + for (i = len - 2; i >= 0; --i) { + if (i > g && sfx[i + len - 1 - f] < i - g) + sfx[i] = sfx[i + len - 1 - f]; + else { + if (i < g) + g = i; + f = i; + while (g >= 0 && s[g] == s[g + len - 1 - f]) + --g; + sfx[i] = f - g; + } + } +} + +static void +compute_goodsfx(ssize_t *goodsfx, const unsigned char *s, ssize_t len) +{ + ssize_t i, j, *sfx = goodsfx + len; + + compute_sfx(sfx, s, len); + + for (i = 0; i < len; ++i) + goodsfx[i] = len; + j = 0; + for (i = len - 1; i >= 0; --i) + if (sfx[i] == i + 1) + for (; j < len - 1 - i; ++j) + if (goodsfx[j] == len) + goodsfx[j] = len - 1 - i; + for (i = 0; i <= len - 2; ++i) + goodsfx[len - 1 - sfx[i]] = len - 1 - i; +} + +/* A helper function for doing cpin forwards or backwards inside the + * find_bytestr() inner loop + */ +static inline void* +search_cpin(struct dump_desc *dd, void *buf, uint64_t addr, size_t len) +{ + if (!dump_cpin(dd, buf, addr, len)) + return buf; + else if (dd->flags & DIF_FORCE) { + memset(buf, 0, len); + return buf; + } else + return NULL; +} + +/* Search for a constant byte string using the Boyer-Moore algorithm. + */ +static inline unsigned char* +search_buf(unsigned char *buf, size_t buflen, + const unsigned char *needle, size_t maxidx, + ssize_t *badchar, ssize_t *goodsfx) +{ + if (!maxidx) + return memchr(buf, *needle, buflen); + + while (buflen > maxidx) { + unsigned char *p; + ssize_t shift, i; + + for (p = buf + maxidx, i = maxidx; i >= 0; --p, --i) + if (needle[i] != *p) + break; + + if (i < 0) + return buf; + + shift = i + 1 - badchar[*p]; + if (shift < goodsfx[i]) + shift = goodsfx[i]; + + buf += shift; + buflen -= shift; + } + return NULL; +} + +/* Search for a constant byte string using the Boyer-Moore algorithm. */ +uint64_t +dump_search_range(struct dump_desc *dd, + uint64_t start, uint64_t end, + const unsigned char *needle, size_t len) +{ + void *dynalloc; + ssize_t *badchar, *goodsfx; + unsigned char *readbuf; + + if (len > 1) { + dynalloc = calloc(sizeof(ssize_t) * (256 + 2*len) + + 2*(len-1), 1); + if (!dynalloc) + return INVALID_ADDR; + badchar = dynalloc; + goodsfx = badchar + 256; + readbuf = dynalloc + sizeof(ssize_t) * (256 + 2*len); + + compute_badchar(badchar, needle, len); + compute_goodsfx(goodsfx, needle, len); + } else { + dynalloc = NULL; + badchar = goodsfx = NULL; + readbuf = NULL; + } + + --len; /* simplify offset computing */ + + while (start < end) { + off_t remain; + unsigned char *p, *q; + + remain = dd->page_size - (start & (dd->page_size - 1)); + if (remain > end - start) + remain = end - start; + + if (remain > len) { + if (read_page(dd, start / dd->page_size)) { + if (! (dd->flags & DIF_FORCE)) + break; + memset(dd->page, 0, dd->page_size); + } + p = dd->page + (start & (dd->page_size - 1)); + } else { + remain += len; + p = search_cpin(dd, readbuf, start, remain); + if (!p) + break; + } + start += remain; + + q = search_buf(p, remain, needle, len, + badchar, goodsfx); + if (q) { + if (dynalloc) + free(dynalloc); + return start + q - p - remain; + } + + start -= len; + } + + if (dynalloc) + free(dynalloc); + return INVALID_ADDR; +} diff --git a/tools/kdumpid/util.c b/tools/kdumpid/util.c new file mode 100644 index 00000000..2d5a0783 --- /dev/null +++ b/tools/kdumpid/util.c @@ -0,0 +1,520 @@ +/* + * util.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. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "kdumpid.h" + +#define MAX_KERNEL_SIZE 16*1024*1024 + +#define ALLOC_INC 1024 + +static void +chomp(char *banner) +{ + char *p = banner; + while (*p && *p != '\n') + ++p; + *p = 0; +} + +static const char* +get_machine_arch(const char *machine) +{ + if (!strcmp(machine, "i386") || + !strcmp(machine, "i586") || + !strcmp(machine, "i686")) + return "ia32"; + else if (!strcmp(machine, "arm64")) + return "aarch64"; + else if (!strncmp(machine, "arm", 3)) + return "arm"; + + return machine; +} + +static const char* +cfg2arch(const char *cfg) +{ + if (strstr(cfg, "CONFIG_X86_64=y")) + return "x86_64"; + if (strstr(cfg, "CONFIG_X86_32=y")) + return "ia32"; + if (strstr(cfg, "CONFIG_PPC64=y")) + return "ppc64"; + if (strstr(cfg, "CONFIG_PPC32=y")) + return "ppc"; + if (strstr(cfg, "CONFIG_IA64=y")) + return "ia64"; + if (strstr(cfg, "CONFIG_S390=y")) + return strstr(cfg, "CONFIG_64BIT=y") + ? "s390x" + : "s390"; + if (strstr(cfg, "CONFIG_ALPHA=y")) + return "alpha"; + if (strstr(cfg, "CONFIG_ARM=y")) + return "arm"; + return NULL; +} + +static int +arch_in_array(const char *arch, const char *const *arr) +{ + const char *const *p = arr; + if (arch == NULL) + return 1; + while (*p) { + if (!strcmp(arch, *p)) + return 1; + ++p; + } + return 0; +} + +int +get_version_from_banner(struct dump_desc *dd) +{ + const char *p; + char *q; + + if (!*dd->banner) + return -1; + + p = dd->banner + sizeof("Linux version ") - 1; + q = dd->ver; + while (*p && *p != ' ') + *q++ = *p++; + *q = 0; + return 0; +} + +int +need_explore(struct dump_desc *dd) +{ + if (!dd->arch && dd->machine[0]) + dd->arch = get_machine_arch(dd->machine); + + if (!(dd->flags & DIF_VERBOSE) && dd->arch != NULL && dd->ver[0]) + return 0; + return 1; +} + +/* utsname strings are 65 characters long. + * Final NUL may be missing (i.e. corrupted dump data) + */ +static void +copy_uts_string(char *dest, const char *src) +{ + if (!*dest) { + memcpy(dest, src, 65); + dest[65] = 0; + } +} + +static int +uts_looks_sane(struct new_utsname *uts) +{ + return uts->sysname[0] && uts->nodename[0] && uts->release[0] && + uts->version[0] && uts->machine[0]; +} + +int read_page(struct dump_desc *dd, unsigned long pfn) +{ + size_t rd = dd->page_size; + return kdump_read(dd->ctx, KDUMP_KPHYSADDR, pfn * dd->page_size, + dd->page, &rd); +} + +size_t +dump_cpin(struct dump_desc *dd, void *buf, uint64_t paddr, size_t len) +{ + size_t rd = len; + kdump_read(dd->ctx, KDUMP_KPHYSADDR, paddr, buf, &rd); + return len - rd; +} + +int +uncompress_config(struct dump_desc *dd, void *zcfg, size_t zsize) +{ + z_stream stream; + void *cfg; + int ret; + + stream.next_in = zcfg; + stream.avail_in = zsize; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + if (inflateInit2(&stream, 16+MAX_WBITS) != Z_OK) + return -1; + + cfg = NULL; + stream.avail_out = -1; + stream.total_out = 0; + do { + void *newbuf = realloc(cfg, stream.total_out + 1024); + if (!newbuf) { + ret = Z_MEM_ERROR; + break; + } + + cfg = newbuf; + stream.next_out = cfg + stream.total_out; + stream.avail_out += ALLOC_INC; + } while( (ret = inflate(&stream, Z_NO_FLUSH)) == Z_OK); + + inflateEnd(&stream); + + if (ret != Z_STREAM_END) { + free(cfg); + return -1; + } + + *stream.next_out = 0; /* terminating NUL */ + dd->cfg = cfg; + dd->cfglen = stream.total_out; + + return 0; +} + +typedef int (*explore_fn)(struct dump_desc *, uint64_t, uint64_t, + const char *const *); + +static int +explore_ktext(struct dump_desc *dd, explore_fn fn, + const char *const *expected_archs) +{ + const addrxlat_range_t *range; + const addrxlat_meth_t *meth; + addrxlat_sys_t *xlatsys; + addrxlat_addr_t addr; + addrxlat_map_t *map; + size_t n; + int ret; + + if (kdump_get_addrxlat(dd->ctx, NULL, &xlatsys) != KDUMP_OK) + return -1; + + ret = -1; + meth = addrxlat_sys_get_meth(xlatsys, ADDRXLAT_SYS_METH_KTEXT); + if (meth->kind != ADDRXLAT_LINEAR) + goto out; + addr = meth->param.linear.off; + + map = addrxlat_sys_get_map(xlatsys, ADDRXLAT_SYS_MAP_KV_PHYS); + range = addrxlat_map_ranges(map); + n = addrxlat_map_len(map); + while (n) { + if (range->meth == ADDRXLAT_SYS_METH_KTEXT && + !fn(dd, addr, addr + range->endoff + 1, expected_archs)) { + ret = 0; + goto out; + } + addr += range->endoff + 1; + ++range; + --n; + } + + out: + addrxlat_sys_decref(xlatsys); + return ret; +} + +static int +explore_kernel(struct dump_desc *dd, explore_fn fn) +{ + static const char *const all_archs[] = { + "alpha", "arm", "ia64", + "ppc", "ppc64", + "s390", "s390x", + "ia32", "x86_64", + NULL + }; + static const char *const x86_biarch[] = { + "ia32", "x86_64", NULL + }; + static const char *const zarch[] = { + "s390", "s390x", NULL + }; + static const char *const ppc[] = { "ppc", NULL }; + static const char *const ppc64[] = { "ppc64", NULL }; + + uint64_t addr; + + if (dd->flags & DIF_FORCE) + return fn(dd, 0, dd->max_pfn * dd->page_size, all_archs); + + if (dd->flags & DIF_START_FOUND) + return fn(dd, dd->start_addr, + dd->start_addr + MAX_KERNEL_SIZE, all_archs); + + if (!explore_ktext(dd, fn, all_archs)) + return 0; + + if (arch_in_array(dd->arch, x86_biarch)) { + /* Xen pv kernels are loaded low */ + addr = 0x2000; + if (dd->xen_type != KDUMP_XEN_NONE && + looks_like_kcode_x86(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, x86_biarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + + /* x86 kernels were traditionally loaded at 1M */ + addr = 1024*1024; + if (looks_like_kcode_x86(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, x86_biarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + + /* other x86 kernels are loaded at 16M */ + addr = 16*1024*1024; + if (looks_like_kcode_x86(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, x86_biarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + + /* some x86 kernels are loaded at 2M (due to align) */ + addr = 2*1024*1024; + if (looks_like_kcode_x86(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, x86_biarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + } + + if (arch_in_array(dd->arch, ppc64)) { + /* PPC64 loads at 0 */ + addr = 0; + if (looks_like_kcode_ppc64(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, zarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + } + + if (arch_in_array(dd->arch, ppc)) { + /* POWER also loads at 0 */ + addr = 0; + if (looks_like_kcode_ppc(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, zarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + } + + if (arch_in_array(dd->arch, zarch)) { + /* Linux/390 loads at 0 */ + addr = 0; + if (looks_like_kcode_s390(dd, addr) > 0 && + !fn(dd, addr, addr + MAX_KERNEL_SIZE, zarch)) { + dd->start_addr = addr; + dd->flags |= DIF_START_FOUND; + return 0; + } + } + + return -1; +} + +static int +explore_banner(struct dump_desc *dd, uint64_t addr, uint64_t endaddr, + const char *const *expected_archs) +{ + static const unsigned char banhdr[] = "Linux version "; + + while ((addr = dump_search_range(dd, addr, endaddr, + banhdr, sizeof(banhdr) - 1)) != INVALID_ADDR) { + char banner[256]; + size_t len; + + len = dump_cpin(dd, banner, addr, sizeof banner); + addr += sizeof(banhdr) - 1; + if (len == sizeof banner) + continue; + dd->banner[sizeof(dd->banner)-1] = 0; + strncpy(dd->banner, banner, sizeof(dd->banner) - 1); + chomp(dd->banner); + return 0; + } + + return -1; +} + +static int +explore_utsname(struct dump_desc *dd, uint64_t addr, uint64_t endaddr, + const char *const *expected_archs) +{ + static const unsigned char sysname[65] = "Linux"; + + while ((addr = dump_search_range(dd, addr, endaddr, + sysname, sizeof sysname)) != INVALID_ADDR) { + struct new_utsname uts; + size_t len; + const char *arch; + + len = dump_cpin(dd, &uts, addr, sizeof uts); + addr += sizeof sysname; + if (len) + continue; + + if (!uts_looks_sane(&uts)) + continue; + + arch = get_machine_arch(uts.machine); + if (arch && arch_in_array(arch, expected_archs)) { + copy_uts_string(dd->machine, uts.machine); + copy_uts_string(dd->ver, uts.release); + dd->arch = (arch == uts.machine + ? dd->machine + : arch); + return 0; + } + } + + return -1; +} + +static uint64_t +search_ikcfg(struct dump_desc *dd, uint64_t startaddr, uint64_t endaddr) +{ + const unsigned char magic_start[8] = "IKCFG_ST"; + const unsigned char magic_end[8] = "IKCFG_ED"; + size_t cfgsize; + char *cfg; + + startaddr = dump_search_range(dd, startaddr, endaddr, + magic_start, sizeof magic_start); + if (startaddr == INVALID_ADDR) + goto fail; + startaddr += sizeof(magic_start); + + endaddr = dump_search_range(dd, startaddr, endaddr, + magic_end, sizeof magic_end); + if (endaddr == INVALID_ADDR) + goto fail; + + cfgsize = endaddr - startaddr; + if (! (cfg = malloc(cfgsize)) ) { + perror("Cannot allocate kernel config"); + goto fail; + } + if (dump_cpin(dd, cfg, startaddr, cfgsize)) + goto fail_free; + + if (uncompress_config(dd, cfg, cfgsize)) + goto fail_free; + + free(cfg); + return endaddr; + + fail_free: + free(cfg); + fail: + return INVALID_ADDR; +} + +static int +explore_ikcfg(struct dump_desc *dd, uint64_t addr, uint64_t endaddr, + const char *const *expected_archs) +{ + while ((addr = search_ikcfg(dd, addr, endaddr)) != INVALID_ADDR) { + const char *arch = cfg2arch(dd->cfg); + if (arch && arch_in_array(arch, expected_archs)) { + dd->arch = arch; + return 0; + } + } + + return -1; +} + +int +explore_raw_data(struct dump_desc *dd) +{ + addrxlat_sys_t *sys; + addrxlat_map_t *map; + kdump_status kstatus; + int ret; + + if ( (dd->page = malloc(dd->page_size)) == NULL) { + perror("Cannot allocate page data"); + return -1; + } + + ret = -1; + + kstatus = kdump_get_addrxlat(dd->ctx, NULL, &sys); + if (kstatus != KDUMP_OK) { + fprintf(stderr, "Cannot get address translation: %s\n", + kdump_get_err(dd->ctx)); + goto err_free; + } + + map = addrxlat_sys_get_map(sys, ADDRXLAT_SYS_MAP_KPHYS_MACHPHYS); + if (!map) { + addrxlat_range_t range; + addrxlat_meth_t meth; + addrxlat_status status; + + meth.kind = ADDRXLAT_LINEAR; + meth.target_as = ADDRXLAT_MACHPHYSADDR; + meth.param.linear.off = 0; + addrxlat_sys_set_meth(sys, ADDRXLAT_SYS_METH_KPHYS_MACHPHYS, + &meth); + + map = addrxlat_map_new(); + if (!map) { + perror("Cannot allocate identity map"); + goto err_xlat; + } + + range.endoff = ADDRXLAT_ADDR_MAX; + range.meth = ADDRXLAT_SYS_METH_KPHYS_MACHPHYS; + status = addrxlat_map_set(map, 0, &range); + if (status != ADDRXLAT_OK) { + fprintf(stderr, "Cannot set identity range: %s\n", + addrxlat_strerror(status)); + goto err_xlat; + } + addrxlat_sys_set_map(sys, ADDRXLAT_SYS_MAP_KPHYS_MACHPHYS, map); + } + + ret &= explore_kernel(dd, explore_utsname); + explore_kernel(dd, explore_ikcfg); + ret &= explore_kernel(dd, explore_banner); + + err_xlat: + addrxlat_sys_decref(sys); + err_free: + free(dd->page); + + return ret; +} diff --git a/tools/kdumpid/x86.c b/tools/kdumpid/x86.c new file mode 100644 index 00000000..8cabc4cf --- /dev/null +++ b/tools/kdumpid/x86.c @@ -0,0 +1,315 @@ +#include "config.h" + +#include +#include +#include + +#include + +#include "kdumpid.h" + +#define MAX_INSN_LEN 100 + +struct disas_state { + unsigned long flags; + uint64_t sp_value; + uint32_t ecx_value; + int depth; +}; + +#define SI_STORED 1 +#define SI_MODIFIED 2 +#define SP_MODIFIED 4 + +struct disas_priv { + char *iptr; + struct disas_state initstate; + + char insn[MAX_INSN_LEN]; + unsigned char pagemap[]; +}; + +static const unsigned char xen_cpuid[] = + { 0x0f, 0x0b, 0x78, 0x65, 0x6e, 0x0f, 0xa2 }; + +#define MSR_GS_BASE 0xc0000101 + +static const char sep[] = ", \t\r\n"; +#define wsep (sep+1) + +static disassembler_ftype print_insn; + +static void +append_insn(void *data, const char *fmt, va_list va) +{ + struct disas_priv *priv = data; + size_t remain; + int len; + + remain = priv->insn + sizeof(priv->insn) - priv->iptr; + len = vsnprintf(priv->iptr, remain, fmt, va); + if (len > 0) + priv->iptr += len; +} + +static int +disas_fn(void *data, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#ifdef DIS_ASM_STYLED_PRINTF + +static int +disas_styled_fn(void *data, enum disassembler_style style, + const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + append_insn(data, fmt, va); + va_end(va); + + return 0; +} + +#endif /* DIS_ASM_STYLED_PRINTF */ + +static void error_func(int status, bfd_vma memaddr, + struct disassemble_info *dinfo) +{ + /* intentionally empty */ +} + +static size_t +skip_zeroes(unsigned char *buf, size_t len) +{ + size_t num = 0; + while (len-- && !*buf++) + ++num; + return (num > 2) ? num : 0; +} + +static int +check_xen_early_idt_msg(struct dump_desc *dd) +{ + static const unsigned char msg[] = + "PANIC: early exception rip %lx error %lx cr2 %lx\n"; + void *p = dd->page; + + while (p < dd->page + 0x100) + if (!memcmp(p, msg, sizeof msg - 1)) + return 1; + return 0; +} + +static void +set_pagemap(unsigned char *pagemap, unsigned pc, int count) +{ + while (count > 0) { + pagemap[pc >> 3] |= 1 << (pc & 7); + ++pc, --count; + } +} + +static int +is_lgdt(const char *insn) +{ + return insn && (!strcmp(insn, "lgdt") || !strcmp(insn, "lgdtl")); +} + +static int +is_reg(const char *loc, const char *reg) +{ + if (!loc || *loc++ != '%') + return 0; + if (*loc == 'r' || *loc == 'e') + ++loc; + return !strcmp(loc, reg); +} + +static int +looks_like_kvaddr(struct disassemble_info *info, uint64_t addr) +{ + if (info->mach == bfd_mach_i386_i386) { + if (addr > 0xffffffff) + return 0; + + /* TODO: handle other Memory split options + * than the default VMSPLIT_3G + */ + if (addr >= 0xc0000000) + return 1; + } else if (info->mach == bfd_mach_x86_64) { + if (addr >= 0xffffffff80000000) + return 1; + } + + return 0; +} + +static int +disas_at(struct dump_desc *dd, struct disassemble_info *info, unsigned pc) +{ + struct disas_priv *priv = info->stream; + struct disas_state state = priv->initstate; + char *toksave; + char *insn, *arg1, *arg2; + unsigned long long a; + int count; + + do { + count = skip_zeroes(dd->page + pc, dd->page_size - pc); + set_pagemap(priv->pagemap, pc, count); + pc += count; + + if (dd->page_size - pc == 0) + break; + + if (dd->page_size - pc >= sizeof(xen_cpuid) && + !memcmp(dd->page + pc, xen_cpuid, sizeof xen_cpuid)) + return 1; + + if ( (priv->pagemap[pc >> 3] & (1 << (pc & 7))) ) + break; + + priv->iptr = priv->insn; + count = print_insn(info->buffer_vma + pc, info); + set_pagemap(priv->pagemap, pc, count); + if (count < 0) + break; + pc += count; + + insn = strtok_r(priv->insn, wsep, &toksave); + arg1 = strtok_r(NULL, sep, &toksave); + arg2 = strtok_r(NULL, sep, &toksave); + + /* a jump instruction? */ + if ( (*insn == 'j' || + !strncmp(insn, "call", 4)) && + sscanf(arg1, "0x%llx", &a) == 1) { + int cont = strncmp(insn, "jmp", 3); + + a -= info->buffer_vma; + if (a < dd->page_size) { + priv->initstate = state; + ++priv->initstate.depth; + if (disas_at(dd, info, a) > 0) + return 1; + --priv->initstate.depth; + } + + if (cont) + continue; + + if (!state.depth && dd->xen_type != KDUMP_XEN_NONE + && state.flags & SI_STORED) { + if (state.flags & SP_MODIFIED && + looks_like_kvaddr(info, state.sp_value)) + return 1; + return check_xen_early_idt_msg(dd); + } + + break; + } + if (!strncmp(insn, "ret", 3)) + break; + + if (!strcmp(insn, "(bad)")) + return -1; + + if (is_lgdt(insn)) + return 1; + + if (!strcmp(insn, "wrmsr") && state.ecx_value == MSR_GS_BASE) + return 1; + + if (!strncmp(insn, "mov", 3)) { + if (is_reg(arg2, "cx") && + sscanf(arg1, "$0x%llx", &a) == 1) + state.ecx_value = a; + else if (is_reg(arg2, "sp") && + sscanf(arg1, "$0x%llx", &a) == 1) { + state.sp_value = a; + state.flags |= SP_MODIFIED; + } + else if (!strcmp(arg2, "%cr3") || + !strcmp(arg2, "%cr4")) + return 1; + if (is_reg(arg1, "si")) { + state.flags |= SI_STORED; + if (dd->xen_type != KDUMP_XEN_NONE && + !(state.flags & SI_MODIFIED) && + sscanf(arg2, "0x%llx", &a) == 1) + dd->xen_start_info = a; + } + } + + if (is_reg(arg2, "si")) + state.flags |= SI_MODIFIED; + } while (count > 0); + + return 0; +} + +/* Decode the first page at addr and check whether it looks like + * x86 kernel code start. + */ +int +looks_like_kcode_x86(struct dump_desc *dd, uint64_t addr) +{ + struct disassemble_info info; + struct disas_priv *priv; + + if (read_page(dd, addr / dd->page_size)) + return -1; + + priv = calloc(1, sizeof(struct disas_priv) + dd->page_size / 8); + if (!priv) + return -1; + +#ifdef DIS_ASM_STYLED_PRINTF + init_disassemble_info(&info, priv, disas_fn, disas_styled_fn); +#else + init_disassemble_info(&info, priv, disas_fn); +#endif + info.memory_error_func = error_func; + info.buffer = dd->page; + info.buffer_vma = addr; + info.buffer_length = dd->page_size; + info.arch = bfd_arch_i386; + + /* Try i386 code first */ + info.mach = bfd_mach_i386_i386; + disassemble_init_for_target(&info); + print_insn = disassembler(bfd_arch_i386, FALSE, + bfd_mach_i386_i386, NULL); + if ((!dd->arch || strcmp(dd->arch, "x86_64")) && + print_insn && + disas_at(dd, &info, 0) > 0) { + free(priv); + return 1; + } + + /* Try x86_64 if that failed */ + memset(priv, 0, sizeof(struct disas_priv) + dd->page_size / 8); + info.mach = bfd_mach_x86_64; + disassemble_init_for_target(&info); + print_insn = disassembler(bfd_arch_i386, FALSE, + bfd_mach_x86_64, NULL); + if ((!dd->arch || strcmp(dd->arch, "i386")) && + print_insn && + disas_at(dd, &info, 0) > 0) { + free(priv); + return 1; + } + + free(priv); + return 0; +}