| #!/usr/bin/perl |
| ########################################################################### |
| # ABI Compliance Checker (ABICC) 1.99.26 |
| # A tool for checking backward compatibility of a C/C++ library API |
| # |
| # Copyright (C) 2009-2011 Institute for System Programming, RAS |
| # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) |
| # Copyright (C) 2011-2012 ROSA Laboratory |
| # Copyright (C) 2012-2016 Andrey Ponomarenko's ABI Laboratory |
| # |
| # Written by Andrey Ponomarenko |
| # |
| # PLATFORMS |
| # ========= |
| # Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian |
| # |
| # REQUIREMENTS |
| # ============ |
| # Linux |
| # - G++ (3.0-4.7, 4.8.3, 4.9 or newer) |
| # - GNU Binutils (readelf, c++filt, objdump) |
| # - Perl 5 |
| # - Ctags |
| # - ABI Dumper >= 0.99.15 |
| # |
| # Mac OS X |
| # - Xcode (g++, c++filt, otool, nm) |
| # - Ctags |
| # |
| # MS Windows |
| # - MinGW (3.0-4.7, 4.8.3, 4.9 or newer) |
| # - MS Visual C++ (dumpbin, undname, cl) |
| # - Active Perl 5 (5.8 or newer) |
| # - Sigcheck v2.52 or newer |
| # - GnuWin Zip and UnZip |
| # - Ctags (Exuberant or Universal) |
| # - Add tool locations to the PATH environment variable |
| # - Run vcvars64.bat (C:\Microsoft Visual Studio 9.0\VC\bin\) |
| # |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License or the GNU Lesser |
| # General Public License as published by the Free Software Foundation. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # and the GNU Lesser General Public License along with this program. |
| # If not, see <http://www.gnu.org/licenses/>. |
| ########################################################################### |
| use Getopt::Long; |
| Getopt::Long::Configure ("posix_default", "no_ignore_case"); |
| use File::Path qw(mkpath rmtree); |
| use File::Temp qw(tempdir); |
| use File::Copy qw(copy move); |
| use Cwd qw(abs_path cwd realpath); |
| use Storable qw(dclone); |
| use Data::Dumper; |
| use Config; |
| |
| my $TOOL_VERSION = "1.99.26"; |
| my $ABI_DUMP_VERSION = "3.3"; |
| my $XML_REPORT_VERSION = "1.2"; |
| my $XML_ABI_DUMP_VERSION = "1.2"; |
| my $OSgroup = get_OSgroup(); |
| my $ORIG_DIR = cwd(); |
| my $TMP_DIR = tempdir(CLEANUP=>1); |
| my $LOCALE = "C.UTF-8"; |
| |
| # Internal modules |
| my $MODULES_DIR = get_Modules(); |
| push(@INC, get_dirname($MODULES_DIR)); |
| # Rules DB |
| my %RULES_PATH = ( |
| "Binary" => $MODULES_DIR."/RulesBin.xml", |
| "Source" => $MODULES_DIR."/RulesSrc.xml"); |
| |
| my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, |
| $TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps, |
| $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath, |
| %RelativeDirectory, $TargetTitle, $TestDump, $LoggingPath, |
| %TargetVersion, $InfoMsg, $CrossGcc, %OutputLogPath, |
| $OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem, |
| $CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc, |
| $TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet, |
| $SkipHeadersPath, $CxxCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, |
| $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, |
| $SourceReportPath, $UseXML, $SortDump, $DumpFormat, |
| $ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, |
| $CheckInfo, $Quick, $AffectLimit, $AllAffected, $CxxIncompat, |
| $SkipInternalSymbols, $SkipInternalTypes, $TargetArch, $GccOptions, |
| $TypesListPath, $SkipTypesListPath, $CheckPrivateABI, $CountSymbols, $OldStyle, |
| $DisableQuickEmptyReport, $SkipTypedefUncover, $MinGWCompat, $SkipUnidentified, |
| $DisableConstantsCheck, $SkipAddedConstants, $SkipRemovedConstants, $TestABIDumper); |
| |
| my $CmdName = get_filename($0); |
| my %OS_LibExt = ( |
| "dynamic" => { |
| "linux"=>"so", |
| "macos"=>"dylib", |
| "windows"=>"dll", |
| "symbian"=>"dso", |
| "default"=>"so" |
| }, |
| "static" => { |
| "linux"=>"a", |
| "windows"=>"lib", |
| "symbian"=>"lib", |
| "default"=>"a" |
| } |
| ); |
| |
| my %OS_Archive = ( |
| "windows"=>"zip", |
| "default"=>"tar.gz" |
| ); |
| |
| my %ERROR_CODE = ( |
| # Compatible verdict |
| "Compatible"=>0, |
| "Success"=>0, |
| # Incompatible verdict |
| "Incompatible"=>1, |
| # Undifferentiated error code |
| "Error"=>2, |
| # System command is not found |
| "Not_Found"=>3, |
| # Cannot access input files |
| "Access_Error"=>4, |
| # Cannot compile header files |
| "Cannot_Compile"=>5, |
| # Header compiled with errors |
| "Compile_Error"=>6, |
| # Invalid input ABI dump |
| "Invalid_Dump"=>7, |
| # Incompatible version of ABI dump |
| "Dump_Version"=>8, |
| # Cannot find a module |
| "Module_Error"=>9, |
| # Empty intersection between |
| # headers and shared objects |
| "Empty_Intersection"=>10, |
| # Empty set of symbols in headers |
| "Empty_Set"=>11 |
| ); |
| |
| my %HomePage = ( |
| "Dev"=>"https://github.com/lvc/abi-compliance-checker", |
| "Wiki"=>"https://lvc.github.io/abi-compliance-checker/" |
| ); |
| |
| my $ShortUsage = "ABI Compliance Checker (ABICC) $TOOL_VERSION |
| A tool for checking backward compatibility of a C/C++ library API |
| Copyright (C) 2016 Andrey Ponomarenko's ABI Laboratory |
| License: GNU LGPL or GNU GPL |
| |
| Usage: $CmdName [options] |
| Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml |
| |
| OLD.xml and NEW.xml are XML-descriptors: |
| |
| <version> |
| 1.0 |
| </version> |
| |
| <headers> |
| /path/to/headers/ |
| </headers> |
| |
| <libs> |
| /path/to/libraries/ |
| </libs> |
| |
| More info: $CmdName --help\n"; |
| |
| if($#ARGV==-1) |
| { |
| printMsg("INFO", $ShortUsage); |
| exit(0); |
| } |
| |
| GetOptions("h|help!" => \$Help, |
| "i|info!" => \$InfoMsg, |
| "v|version!" => \$ShowVersion, |
| "dumpversion!" => \$DumpVersion, |
| # general options |
| "l|lib|library=s" => \$TargetLibraryName, |
| "d1|old|o=s" => \$Descriptor{1}{"Path"}, |
| "d2|new|n=s" => \$Descriptor{2}{"Path"}, |
| "dump|dump-abi|dump_abi=s" => \$DumpAPI, |
| # extra options |
| "app|application=s" => \$AppPath, |
| "static|static-libs!" => \$UseStaticLibs, |
| "gcc-path|cross-gcc=s" => \$CrossGcc, |
| "gcc-prefix|cross-prefix=s" => \$CrossPrefix, |
| "gcc-options=s" => \$GccOptions, |
| "sysroot=s" => \$SystemRoot_Opt, |
| "v1|vnum1|version1|vnum=s" => \$TargetVersion{1}, |
| "v2|vnum2|version2=s" => \$TargetVersion{2}, |
| "s|strict!" => \$StrictCompat, |
| "symbols-list=s" => \$SymbolsListPath, |
| "types-list=s" => \$TypesListPath, |
| "skip-symbols=s" => \$SkipSymbolsListPath, |
| "skip-types=s" => \$SkipTypesListPath, |
| "disable-constants-check!" => \$DisableConstantsCheck, |
| "skip-added-constants!" => \$SkipAddedConstants, |
| "skip-removed-constants!" => \$SkipRemovedConstants, |
| "headers-list=s" => \$TargetHeadersPath, |
| "skip-headers=s" => \$SkipHeadersPath, |
| "header=s" => \$TargetHeader, |
| "headers-only|headers_only!" => \$CheckHeadersOnly_Opt, |
| "show-retval!" => \$ShowRetVal, |
| "use-dumps!" => \$UseDumps, |
| "nostdinc!" => \$NoStdInc, |
| "dump-system=s" => \$DumpSystem, |
| "sysinfo=s" => \$TargetSysInfo, |
| "cmp-systems!" => \$CmpSystems, |
| "libs-list=s" => \$TargetLibsPath, |
| "ext|extended!" => \$ExtendedCheck, |
| "q|quiet!" => \$Quiet, |
| "stdout!" => \$StdOut, |
| "report-format=s" => \$ReportFormat, |
| "dump-format=s" => \$DumpFormat, |
| "xml!" => \$UseXML, |
| "lang=s" => \$UserLang, |
| "arch=s" => \$TargetArch, |
| "binary|bin|abi!" => \$BinaryOnly, |
| "source|src|api!" => \$SourceOnly, |
| "limit-affected|affected-limit=s" => \$AffectLimit, |
| "count-symbols=s" => \$CountSymbols, |
| "old-style!" => \$OldStyle, |
| # other options |
| "test!" => \$TestTool, |
| "test-dump!" => \$TestDump, |
| "test-abi-dumper!" => \$TestABIDumper, |
| "debug!" => \$Debug, |
| "cpp-compatible!" => \$CxxCompat, |
| "cxx-incompatible|cpp-incompatible!" => \$CxxIncompat, |
| "mingw-compatible!" => \$MinGWCompat, |
| "p|params=s" => \$ParamNamesPath, |
| "relpath1|relpath=s" => \$RelativeDirectory{1}, |
| "relpath2=s" => \$RelativeDirectory{2}, |
| "dump-path=s" => \$OutputDumpPath, |
| "sort!" => \$SortDump, |
| "report-path=s" => \$OutputReportPath, |
| "bin-report-path=s" => \$BinaryReportPath, |
| "src-report-path=s" => \$SourceReportPath, |
| "log-path=s" => \$LoggingPath, |
| "log1-path=s" => \$OutputLogPath{1}, |
| "log2-path=s" => \$OutputLogPath{2}, |
| "logging-mode=s" => \$LogMode, |
| "list-affected!" => \$ListAffected, |
| "title|l-full|lib-full=s" => \$TargetTitle, |
| "component=s" => \$TargetComponent_Opt, |
| "extra-info=s" => \$ExtraInfo, |
| "extra-dump!" => \$ExtraDump, |
| "force!" => \$Force, |
| "tolerance=s" => \$Tolerance, |
| "tolerant!" => \$Tolerant, |
| "skip-unidentified!" => \$SkipUnidentified, |
| "check!" => \$CheckInfo, |
| "quick!" => \$Quick, |
| "disable-quick-empty-report!" => \$DisableQuickEmptyReport, |
| "all-affected!" => \$AllAffected, |
| "skip-internal-symbols|skip-internal=s" => \$SkipInternalSymbols, |
| "skip-internal-types=s" => \$SkipInternalTypes, |
| "skip-typedef-uncover!" => \$SkipTypedefUncover, |
| "check-private-abi!" => \$CheckPrivateABI |
| ) or ERR_MESSAGE(); |
| |
| sub ERR_MESSAGE() |
| { |
| printMsg("INFO", "\n".$ShortUsage); |
| exit($ERROR_CODE{"Error"}); |
| } |
| |
| my $LIB_TYPE = $UseStaticLibs?"static":"dynamic"; |
| my $SLIB_TYPE = $LIB_TYPE; |
| if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic") |
| { # show as "shared" library |
| $SLIB_TYPE = "shared"; |
| } |
| my $LIB_EXT = getLIB_EXT($OSgroup); |
| my $AR_EXT = getAR_EXT($OSgroup); |
| my $BYTE_SIZE = 8; |
| my $COMMON_LOG_PATH = "logs/run.log"; |
| |
| my $HelpMessage=" |
| NAME: |
| ABI Compliance Checker ($CmdName) |
| Check backward compatibility of a C/C++ library API |
| |
| DESCRIPTION: |
| ABI Compliance Checker (ABICC) is a tool for checking backward binary and |
| source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks |
| header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and |
| analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary |
| and/or source-level compatibility: changes in calling stack, v-table changes, |
| removed symbols, renamed fields, etc. Binary incompatibility may result in |
| crashing or incorrect behavior of applications built with an old version of |
| a library if they run on a new one. Source incompatibility may result in |
| recompilation errors with a new library version. |
| |
| The tool is intended for developers of software libraries and maintainers |
| of operating systems who are interested in ensuring backward compatibility, |
| i.e. allow old applications to run or to be recompiled with newer library |
| versions. |
| |
| Also the tool can be used by ISVs for checking applications portability to |
| new library versions. Found issues can be taken into account when adapting |
| the application to a new library version. |
| |
| This tool is free software: you can redistribute it and/or modify it |
| under the terms of the GNU LGPL or GNU GPL. |
| |
| USAGE: |
| $CmdName [options] |
| |
| EXAMPLE: |
| $CmdName -lib NAME -old OLD.xml -new NEW.xml |
| |
| OLD.xml and NEW.xml are XML-descriptors: |
| |
| <version> |
| 1.0 |
| </version> |
| |
| <headers> |
| /path1/to/header(s)/ |
| /path2/to/header(s)/ |
| ... |
| </headers> |
| |
| <libs> |
| /path1/to/library(ies)/ |
| /path2/to/library(ies)/ |
| ... |
| </libs> |
| |
| INFORMATION OPTIONS: |
| -h|-help |
| Print this help. |
| |
| -i|-info |
| Print complete info. |
| |
| -v|-version |
| Print version information. |
| |
| -dumpversion |
| Print the tool version ($TOOL_VERSION) and don't do anything else. |
| |
| GENERAL OPTIONS: |
| -l|-lib|-library NAME |
| Library name (without version). |
| |
| -d1|-old|-o PATH |
| Descriptor of 1st (old) library version. |
| It may be one of the following: |
| |
| 1. XML-descriptor (VERSION.xml file): |
| |
| <version> |
| 1.0 |
| </version> |
| |
| <headers> |
| /path1/to/header(s)/ |
| /path2/to/header(s)/ |
| ... |
| </headers> |
| |
| <libs> |
| /path1/to/library(ies)/ |
| /path2/to/library(ies)/ |
| ... |
| </libs> |
| |
| ... |
| |
| 2. ABI dump generated by -dump option |
| 3. Directory with headers and/or $SLIB_TYPE libraries |
| 4. Single header file |
| |
| If you are using an 2-4 descriptor types then you should |
| specify version numbers with -v1 and -v2 options too. |
| |
| For more information, please see: |
| http://ispras.linuxbase.org/index.php/Library_Descriptor |
| |
| -d2|-new|-n PATH |
| Descriptor of 2nd (new) library version. |
| |
| -dump|-dump-abi PATH |
| Create library ABI dump for the input XML descriptor. You can |
| transfer it anywhere and pass instead of the descriptor. Also |
| it can be used for debugging the tool. |
| |
| Supported versions of ABI dump: 2.0<=V<=$ABI_DUMP_VERSION\n"; |
| |
| sub HELP_MESSAGE() { |
| printMsg("INFO", $HelpMessage." |
| MORE INFO: |
| $CmdName --info\n"); |
| } |
| |
| sub INFO_MESSAGE() |
| { |
| printMsg("INFO", "$HelpMessage |
| EXTRA OPTIONS: |
| -app|-application PATH |
| This option allows to specify the application that should be checked |
| for portability to the new library version. |
| |
| -static |
| Check static libraries instead of the shared ones. The <libs> section |
| of the XML-descriptor should point to static libraries location. |
| |
| -gcc-path PATH |
| Path to the cross GCC compiler to use instead of the usual (host) GCC. |
| |
| -gcc-prefix PREFIX |
| GCC toolchain prefix. |
| |
| -gcc-options OPTS |
| Additional compiler options. |
| |
| -sysroot DIR |
| Specify the alternative root directory. The tool will search for include |
| paths in the DIR/usr/include and DIR/usr/lib directories. |
| |
| -v1|-version1 NUM |
| Specify 1st library version outside the descriptor. This option is needed |
| if you have preferred an alternative descriptor type (see -d1 option). |
| |
| In general case you should specify it in the XML-descriptor: |
| <version> |
| VERSION |
| </version> |
| |
| -v2|-version2 NUM |
| Specify 2nd library version outside the descriptor. |
| |
| -vnum NUM |
| Specify the library version in the generated ABI dump. The <version> section |
| of the input XML descriptor will be overwritten in this case. |
| |
| -s|-strict |
| Treat all compatibility warnings as problems. Add a number of \"Low\" |
| severity problems to the return value of the tool. |
| |
| -headers-only |
| Check header files without $SLIB_TYPE libraries. It is easy to run, but may |
| provide a low quality compatibility report with false positives and |
| without detecting of added/removed symbols. |
| |
| Alternatively you can write \"none\" word to the <libs> section |
| in the XML-descriptor: |
| <libs> |
| none |
| </libs> |
| |
| -show-retval |
| Show the symbol's return type in the report. |
| |
| -symbols-list PATH |
| This option allows to specify a file with a list of symbols (mangled |
| names in C++) that should be checked. Other symbols will not be checked. |
| |
| -types-list PATH |
| This option allows to specify a file with a list of types that should |
| be checked. Other types will not be checked. |
| |
| -skip-symbols PATH |
| The list of symbols that should not be checked. |
| |
| -skip-types PATH |
| The list of types that should not be checked. |
| |
| -disable-constants-check |
| Do not check for changes in constants. |
| |
| -skip-added-constants |
| Do not detect added constants. |
| |
| -skip-removed-constants |
| Do not detect removed constants. |
| |
| -headers-list PATH |
| The file with a list of headers, that should be checked/dumped. |
| |
| -skip-headers PATH |
| The file with the list of header files, that should not be checked. |
| |
| -header NAME |
| Check/Dump ABI of this header only. |
| |
| -use-dumps |
| Make dumps for two versions of a library and compare dumps. This should |
| increase the performance of the tool and decrease the system memory usage. |
| |
| -nostdinc |
| Do not search in GCC standard system directories for header files. |
| |
| -dump-system NAME -sysroot DIR |
| Find all the shared libraries and header files in DIR directory, |
| create XML descriptors and make ABI dumps for each library. The result |
| set of ABI dumps can be compared (--cmp-systems) with the other one |
| created for other version of operating system in order to check them for |
| compatibility. Do not forget to specify -cross-gcc option if your target |
| system requires some specific version of GCC compiler (different from |
| the host GCC). The system ABI dump will be generated to: |
| sys_dumps/NAME/ARCH |
| |
| -dump-system DESCRIPTOR.xml |
| The same as the previous option but takes an XML descriptor of the target |
| system as input, where you should describe it: |
| |
| /* Primary sections */ |
| |
| <name> |
| /* Name of the system */ |
| </name> |
| |
| <headers> |
| /* The list of paths to header files and/or |
| directories with header files, one per line */ |
| </headers> |
| |
| <libs> |
| /* The list of paths to shared libraries and/or |
| directories with shared libraries, one per line */ |
| </libs> |
| |
| /* Optional sections */ |
| |
| <search_headers> |
| /* List of directories to be searched |
| for header files to automatically |
| generate include paths, one per line */ |
| </search_headers> |
| |
| <search_libs> |
| /* List of directories to be searched |
| for shared libraries to resolve |
| dependencies, one per line */ |
| </search_libs> |
| |
| <tools> |
| /* List of directories with tools used |
| for analysis (GCC toolchain), one per line */ |
| </tools> |
| |
| <cross_prefix> |
| /* GCC toolchain prefix. |
| Examples: |
| arm-linux-gnueabi |
| arm-none-symbianelf */ |
| </cross_prefix> |
| |
| <gcc_options> |
| /* Additional GCC options, one per line */ |
| </gcc_options> |
| |
| -sysinfo DIR |
| This option should be used with -dump-system option to dump |
| ABI of operating systems and configure the dumping process. |
| |
| -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH |
| Compare two ABI dumps of a system. Create compatibility reports for |
| each system library and the common HTML report including the summary |
| of test results for all checked libraries. |
| |
| Summary report will be generated to: |
| sys_compat_reports/NAME1_to_NAME2/ARCH |
| |
| -libs-list PATH |
| The file with a list of libraries, that should be dumped by |
| the -dump-system option or should be checked by the -cmp-systems option. |
| |
| -ext|-extended |
| If your library A is supposed to be used by other library B and you |
| want to control the ABI of B, then you should enable this option. The |
| tool will check for changes in all data types, even if they are not |
| used by any function in the library A. Such data types are not part |
| of the A library ABI, but may be a part of the ABI of the B library. |
| |
| The short scheme is: |
| app C (broken) -> lib B (broken ABI) -> lib A (stable ABI) |
| |
| -q|-quiet |
| Print all messages to the file instead of stdout and stderr. |
| Default path (can be changed by -log-path option): |
| $COMMON_LOG_PATH |
| |
| -stdout |
| Print analysis results (compatibility reports and ABI dumps) to stdout |
| instead of creating a file. This would allow piping data to other programs. |
| |
| -report-format FMT |
| Change format of compatibility report. |
| Formats: |
| htm - HTML format (default) |
| xml - XML format |
| |
| -dump-format FMT |
| Change format of ABI dump. |
| Formats: |
| perl - Data::Dumper format (default) |
| xml - XML format |
| |
| -xml |
| Alias for: --report-format=xml or --dump-format=xml |
| |
| -lang LANG |
| Set library language (C or C++). You can use this option if the tool |
| cannot auto-detect a language. This option may be useful for checking |
| C-library headers (--lang=C) in --headers-only or --extended modes. |
| |
| -arch ARCH |
| Set library architecture (x86, x86_64, ia64, arm, ppc32, ppc64, s390, |
| ect.). The option is useful if the tool cannot detect correct architecture |
| of the input objects. |
| |
| -binary|-bin|-abi |
| Show \"Binary\" compatibility problems only. |
| Generate report to: |
| compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html |
| |
| -source|-src|-api |
| Show \"Source\" compatibility problems only. |
| Generate report to: |
| compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html |
| |
| -limit-affected LIMIT |
| The maximum number of affected symbols listed under the description |
| of the changed type in the report. |
| |
| -count-symbols PATH |
| Count total public symbols in the ABI dump. |
| |
| -old-style |
| Generate old-style report. |
| |
| OTHER OPTIONS: |
| -test |
| Run internal tests. Create two binary incompatible versions of a sample |
| library and run the tool to check them for compatibility. This option |
| allows to check if the tool works correctly in the current environment. |
| |
| -test-dump |
| Test ability to create, read and compare ABI dumps. |
| |
| -test-abi-dumper |
| Compare ABI dumps created by the ABI Dumper tool. |
| |
| -debug |
| Debugging mode. Print debug info on the screen. Save intermediate |
| analysis stages in the debug directory: |
| debug/LIB_NAME/VERSION/ |
| |
| Also consider using -dump option for debugging the tool. |
| |
| -cpp-compatible |
| Do nothing. |
| |
| -cxx-incompatible |
| Set this option if input C header files use C++ keywords. The tool |
| will try to replace such keywords at preprocessor stage and replace |
| them back in the final TU dump. |
| |
| -mingw-compatible |
| If input header files are compatible with the MinGW GCC compiler, |
| then you can tell the tool about this and speedup the analysis. |
| |
| -p|-params PATH |
| Path to file with the function parameter names. It can be used |
| for improving report view if the library header files have no |
| parameter names. File format: |
| |
| func1;param1;param2;param3 ... |
| func2;param1;param2;param3 ... |
| ... |
| |
| -relpath PATH |
| Replace {RELPATH} macros to PATH in the XML-descriptor used |
| for dumping the library ABI (see -dump option). |
| |
| -relpath1 PATH |
| Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1). |
| |
| -relpath2 PATH |
| Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2). |
| |
| -dump-path PATH |
| Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump. |
| Default: |
| abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT |
| |
| -sort |
| Enable sorting of data in ABI dumps. |
| |
| -report-path PATH |
| Path to compatibility report. |
| Default: |
| compat_reports/LIB_NAME/V1_to_V2/compat_report.html |
| |
| -bin-report-path PATH |
| Path to \"Binary\" compatibility report. |
| Default: |
| compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html |
| |
| -src-report-path PATH |
| Path to \"Source\" compatibility report. |
| Default: |
| compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html |
| |
| -log-path PATH |
| Log path for all messages. |
| Default: |
| logs/LIB_NAME/VERSION/log.txt |
| |
| -log1-path PATH |
| Log path for 1st version of a library. |
| Default: |
| logs/LIB_NAME/V1/log.txt |
| |
| -log2-path PATH |
| Log path for 2nd version of a library. |
| Default: |
| logs/LIB_NAME/V2/log.txt |
| |
| -logging-mode MODE |
| Change logging mode. |
| Modes: |
| w - overwrite old logs (default) |
| a - append old logs |
| n - do not write any logs |
| |
| -list-affected |
| Generate file with the list of incompatible |
| symbols beside the HTML compatibility report. |
| Use 'c++filt \@file' command from GNU binutils |
| to unmangle C++ symbols in the generated file. |
| Default names: |
| abi_affected.txt |
| src_affected.txt |
| |
| -component NAME |
| The component name in the title and summary of the HTML report. |
| Default: |
| library |
| |
| -title NAME |
| Change library name in the report title to NAME. By default |
| will be displayed a name specified by -l option. |
| |
| -extra-info DIR |
| Dump extra info to DIR. |
| |
| -extra-dump |
| Create extended ABI dump containing all symbols |
| from the translation unit. |
| |
| -force |
| Try to enable this option if the tool checked not all |
| types and symbols in header files. |
| |
| -tolerance LEVEL |
| Apply a set of heuristics to successfully compile input |
| header files. You can enable several tolerance levels by |
| joining them into one string (e.g. 13, 124, etc.). |
| Levels: |
| 1 - skip non-Linux headers (e.g. win32_*.h, etc.) |
| 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.) |
| 3 - skip headers that include non-Linux headers |
| 4 - skip headers included by others |
| |
| -tolerant |
| Enable highest tolerance level [1234]. |
| |
| -skip-unidentified |
| Skip header files in 'headers' and 'include_preamble' sections |
| of the XML descriptor that cannot be found. This is useful if |
| you are trying to use the same descriptor for different targets. |
| |
| -check |
| Check completeness of the ABI dump. |
| |
| -quick |
| Quick analysis. Disable check of some template instances. |
| |
| -disable-quick-empty-report |
| Do not generate quick empty report if input ABI dumps are equal. |
| |
| -skip-internal-symbols PATTERN |
| Do not check symbols matched by the pattern. |
| |
| -skip-internal-types PATTERN |
| Do not check types matched by the pattern. |
| |
| -skip-typedef-uncover |
| Do not report a problem if type is covered or |
| uncovered by typedef (useful for broken debug info). |
| |
| -check-private-abi |
| Check data types from the private part of the ABI when |
| comparing ABI dumps created by the ABI Dumper tool with |
| use of the -public-headers option. |
| |
| Requires ABI Dumper >= 0.99.14 |
| |
| REPORT: |
| Compatibility report will be generated to: |
| compat_reports/LIB_NAME/V1_to_V2/compat_report.html |
| |
| Log will be generated to: |
| logs/LIB_NAME/V1/log.txt |
| logs/LIB_NAME/V2/log.txt |
| |
| EXIT CODES: |
| 0 - Compatible. The tool has run without any errors. |
| non-zero - Incompatible or the tool has run with errors. |
| |
| MORE INFORMATION: |
| ".$HomePage{"Wiki"}." |
| ".$HomePage{"Dev"}."\n\n"); |
| } |
| |
| my %Operator_Indication = ( |
| "not" => "~", |
| "assign" => "=", |
| "andassign" => "&=", |
| "orassign" => "|=", |
| "xorassign" => "^=", |
| "or" => "|", |
| "xor" => "^", |
| "addr" => "&", |
| "and" => "&", |
| "lnot" => "!", |
| "eq" => "==", |
| "ne" => "!=", |
| "lt" => "<", |
| "lshift" => "<<", |
| "lshiftassign" => "<<=", |
| "rshiftassign" => ">>=", |
| "call" => "()", |
| "mod" => "%", |
| "modassign" => "%=", |
| "subs" => "[]", |
| "land" => "&&", |
| "lor" => "||", |
| "rshift" => ">>", |
| "ref" => "->", |
| "le" => "<=", |
| "deref" => "*", |
| "mult" => "*", |
| "preinc" => "++", |
| "delete" => " delete", |
| "vecnew" => " new[]", |
| "vecdelete" => " delete[]", |
| "predec" => "--", |
| "postinc" => "++", |
| "postdec" => "--", |
| "plusassign" => "+=", |
| "plus" => "+", |
| "minus" => "-", |
| "minusassign" => "-=", |
| "gt" => ">", |
| "ge" => ">=", |
| "new" => " new", |
| "multassign" => "*=", |
| "divassign" => "/=", |
| "div" => "/", |
| "neg" => "-", |
| "pos" => "+", |
| "memref" => "->*", |
| "compound" => "," ); |
| |
| my %UnknownOperator; |
| |
| my %NodeType= ( |
| "array_type" => "Array", |
| "binfo" => "Other", |
| "boolean_type" => "Intrinsic", |
| "complex_type" => "Intrinsic", |
| "const_decl" => "Other", |
| "enumeral_type" => "Enum", |
| "field_decl" => "Other", |
| "function_decl" => "Other", |
| "function_type" => "FunctionType", |
| "identifier_node" => "Other", |
| "integer_cst" => "Other", |
| "integer_type" => "Intrinsic", |
| "vector_type" => "Vector", |
| "method_type" => "MethodType", |
| "namespace_decl" => "Other", |
| "parm_decl" => "Other", |
| "pointer_type" => "Pointer", |
| "real_cst" => "Other", |
| "real_type" => "Intrinsic", |
| "record_type" => "Struct", |
| "reference_type" => "Ref", |
| "string_cst" => "Other", |
| "template_decl" => "Other", |
| "template_type_parm" => "TemplateParam", |
| "typename_type" => "TypeName", |
| "sizeof_expr" => "SizeOf", |
| "tree_list" => "Other", |
| "tree_vec" => "Other", |
| "type_decl" => "Other", |
| "union_type" => "Union", |
| "var_decl" => "Other", |
| "void_type" => "Intrinsic", |
| "nop_expr" => "Other", # |
| "addr_expr" => "Other", # |
| "offset_type" => "Other" ); |
| |
| my %CppKeywords_C = map {$_=>1} ( |
| # C++ 2003 keywords |
| "public", |
| "protected", |
| "private", |
| "default", |
| "template", |
| "new", |
| #"asm", |
| "dynamic_cast", |
| "auto", |
| "try", |
| "namespace", |
| "typename", |
| "using", |
| "reinterpret_cast", |
| "friend", |
| "class", |
| "virtual", |
| "const_cast", |
| "mutable", |
| "static_cast", |
| "export", |
| # C++0x keywords |
| "noexcept", |
| "nullptr", |
| "constexpr", |
| "static_assert", |
| "explicit", |
| # cannot be used as a macro name |
| # as it is an operator in C++ |
| "and", |
| #"and_eq", |
| "not", |
| #"not_eq", |
| "or" |
| #"or_eq", |
| #"bitand", |
| #"bitor", |
| #"xor", |
| #"xor_eq", |
| #"compl" |
| ); |
| |
| my %CppKeywords_F = map {$_=>1} ( |
| "delete", |
| "catch", |
| "alignof", |
| "thread_local", |
| "decltype", |
| "typeid" |
| ); |
| |
| my %CppKeywords_O = map {$_=>1} ( |
| "bool", |
| "register", |
| "inline", |
| "operator" |
| ); |
| |
| my %CppKeywords_A = map {$_=>1} ( |
| "this", |
| "throw", |
| "template" |
| ); |
| |
| foreach (keys(%CppKeywords_C), |
| keys(%CppKeywords_F), |
| keys(%CppKeywords_O)) { |
| $CppKeywords_A{$_}=1; |
| } |
| |
| # Header file extensions as described by gcc |
| my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+"; |
| |
| my %IntrinsicMangling = ( |
| "void" => "v", |
| "bool" => "b", |
| "wchar_t" => "w", |
| "char" => "c", |
| "signed char" => "a", |
| "unsigned char" => "h", |
| "short" => "s", |
| "unsigned short" => "t", |
| "int" => "i", |
| "unsigned int" => "j", |
| "long" => "l", |
| "unsigned long" => "m", |
| "long long" => "x", |
| "__int64" => "x", |
| "unsigned long long" => "y", |
| "__int128" => "n", |
| "unsigned __int128" => "o", |
| "float" => "f", |
| "double" => "d", |
| "long double" => "e", |
| "__float80" => "e", |
| "__float128" => "g", |
| "..." => "z" |
| ); |
| |
| my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); |
| |
| my %StdcxxMangling = ( |
| "3std"=>"St", |
| "3std9allocator"=>"Sa", |
| "3std12basic_string"=>"Sb", |
| "3std12basic_stringIcE"=>"Ss", |
| "3std13basic_istreamIcE"=>"Si", |
| "3std13basic_ostreamIcE"=>"So", |
| "3std14basic_iostreamIcE"=>"Sd" |
| ); |
| |
| my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; |
| my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); |
| |
| my $ADD_TMPL_INSTANCES = 1; |
| my $GCC_MISSED_MNGL = 0; |
| |
| my %ConstantSuffix = ( |
| "unsigned int"=>"u", |
| "long"=>"l", |
| "unsigned long"=>"ul", |
| "long long"=>"ll", |
| "unsigned long long"=>"ull" |
| ); |
| |
| my %ConstantSuffixR = |
| reverse(%ConstantSuffix); |
| |
| my %OperatorMangling = ( |
| "~" => "co", |
| "=" => "aS", |
| "|" => "or", |
| "^" => "eo", |
| "&" => "an",#ad (addr) |
| "==" => "eq", |
| "!" => "nt", |
| "!=" => "ne", |
| "<" => "lt", |
| "<=" => "le", |
| "<<" => "ls", |
| "<<=" => "lS", |
| ">" => "gt", |
| ">=" => "ge", |
| ">>" => "rs", |
| ">>=" => "rS", |
| "()" => "cl", |
| "%" => "rm", |
| "[]" => "ix", |
| "&&" => "aa", |
| "||" => "oo", |
| "*" => "ml",#de (deref) |
| "++" => "pp",# |
| "--" => "mm",# |
| "new" => "nw", |
| "delete" => "dl", |
| "new[]" => "na", |
| "delete[]" => "da", |
| "+=" => "pL", |
| "+" => "pl",#ps (pos) |
| "-" => "mi",#ng (neg) |
| "-=" => "mI", |
| "*=" => "mL", |
| "/=" => "dV", |
| "&=" => "aN", |
| "|=" => "oR", |
| "%=" => "rM", |
| "^=" => "eO", |
| "/" => "dv", |
| "->*" => "pm", |
| "->" => "pt",#rf (ref) |
| "," => "cm", |
| "?" => "qu", |
| "." => "dt", |
| "sizeof"=> "sz"#st |
| ); |
| |
| my %Intrinsic_Keywords = map {$_=>1} ( |
| "true", |
| "false", |
| "_Bool", |
| "_Complex", |
| "const", |
| "int", |
| "long", |
| "void", |
| "short", |
| "float", |
| "volatile", |
| "restrict", |
| "unsigned", |
| "signed", |
| "char", |
| "double", |
| "class", |
| "struct", |
| "union", |
| "enum" |
| ); |
| |
| my %GlibcHeader = map {$_=>1} ( |
| "aliases.h", |
| "argp.h", |
| "argz.h", |
| "assert.h", |
| "cpio.h", |
| "ctype.h", |
| "dirent.h", |
| "envz.h", |
| "errno.h", |
| "error.h", |
| "execinfo.h", |
| "fcntl.h", |
| "fstab.h", |
| "ftw.h", |
| "glob.h", |
| "grp.h", |
| "iconv.h", |
| "ifaddrs.h", |
| "inttypes.h", |
| "langinfo.h", |
| "limits.h", |
| "link.h", |
| "locale.h", |
| "malloc.h", |
| "math.h", |
| "mntent.h", |
| "monetary.h", |
| "nl_types.h", |
| "obstack.h", |
| "printf.h", |
| "pwd.h", |
| "regex.h", |
| "sched.h", |
| "search.h", |
| "setjmp.h", |
| "shadow.h", |
| "signal.h", |
| "spawn.h", |
| "stdarg.h", |
| "stdint.h", |
| "stdio.h", |
| "stdlib.h", |
| "string.h", |
| "strings.h", |
| "tar.h", |
| "termios.h", |
| "time.h", |
| "ulimit.h", |
| "unistd.h", |
| "utime.h", |
| "wchar.h", |
| "wctype.h", |
| "wordexp.h" ); |
| |
| my %GlibcDir = map {$_=>1} ( |
| "arpa", |
| "bits", |
| "gnu", |
| "netinet", |
| "net", |
| "nfs", |
| "rpc", |
| "sys", |
| "linux" ); |
| |
| my %WinHeaders = map {$_=>1} ( |
| "dos.h", |
| "process.h", |
| "winsock.h", |
| "config-win.h", |
| "mem.h", |
| "windows.h", |
| "winsock2.h", |
| "crtdbg.h", |
| "ws2tcpip.h" |
| ); |
| |
| my %ObsoleteHeaders = map {$_=>1} ( |
| "iostream.h", |
| "fstream.h" |
| ); |
| |
| my %AlienHeaders = map {$_=>1} ( |
| # Solaris |
| "thread.h", |
| "sys/atomic.h", |
| # HPUX |
| "sys/stream.h", |
| # Symbian |
| "AknDoc.h", |
| # Atari ST |
| "ext.h", |
| "tos.h", |
| # MS-DOS |
| "alloc.h", |
| # Sparc |
| "sys/atomic.h" |
| ); |
| |
| my %ConfHeaders = map {$_=>1} ( |
| "atomic", |
| "conf.h", |
| "config.h", |
| "configure.h", |
| "build.h", |
| "setup.h" |
| ); |
| |
| my %LocalIncludes = map {$_=>1} ( |
| "/usr/local/include", |
| "/usr/local" ); |
| |
| my %OS_AddPath=( |
| # These paths are needed if the tool cannot detect them automatically |
| "macos"=>{ |
| "include"=>[ |
| "/Library", |
| "/Developer/usr/include" |
| ], |
| "lib"=>[ |
| "/Library", |
| "/Developer/usr/lib" |
| ], |
| "bin"=>[ |
| "/Developer/usr/bin" |
| ] |
| }, |
| "beos"=>{ |
| # Haiku has GCC 2.95.3 by default |
| # try to find GCC>=3.0 in /boot/develop/abi |
| "include"=>[ |
| "/boot/common", |
| "/boot/develop" |
| ], |
| "lib"=>[ |
| "/boot/common/lib", |
| "/boot/system/lib", |
| "/boot/apps" |
| ], |
| "bin"=>[ |
| "/boot/common/bin", |
| "/boot/system/bin", |
| "/boot/develop/abi" |
| ] |
| } |
| ); |
| |
| my %Slash_Type=( |
| "default"=>"/", |
| "windows"=>"\\" |
| ); |
| |
| my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"}; |
| |
| # Global Variables |
| my %COMMON_LANGUAGE=( |
| 1 => "C", |
| 2 => "C" ); |
| |
| my $MAX_COMMAND_LINE_ARGUMENTS = 4096; |
| my $MAX_CPPFILT_FILE_SIZE = 50000; |
| my $CPPFILT_SUPPORT_FILE; |
| |
| my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION, %CLANG_VERSION); |
| |
| my $STDCXX_TESTING = 0; |
| my $GLIBC_TESTING = 0; |
| my $CPP_HEADERS = 0; |
| |
| my $CheckHeadersOnly = $CheckHeadersOnly_Opt; |
| my $CheckUndefined = 0; |
| |
| my $TargetComponent = undef; |
| if($TargetComponent_Opt) { |
| $TargetComponent = lc($TargetComponent_Opt); |
| } |
| else |
| { # default: library |
| # other components: header, system, ... |
| $TargetComponent = "library"; |
| } |
| |
| my $TOP_REF = "<a class='top_ref' href='#Top'>to the top</a>"; |
| |
| my $SystemRoot; |
| |
| my $MAIN_CPP_DIR; |
| my %RESULT; |
| my %LOG_PATH; |
| my %DEBUG_PATH; |
| my %Cache; |
| my %LibInfo; |
| my $COMPILE_ERRORS = 0; |
| my %CompilerOptions; |
| my %CheckedDyLib; |
| my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup); |
| |
| # Constants (#defines) |
| my %Constants; |
| my %SkipConstants; |
| my %EnumConstants; |
| |
| # Extra Info |
| my %SymbolHeader; |
| my %KnownLibs; |
| |
| # Templates |
| my %TemplateInstance; |
| my %BasicTemplate; |
| my %TemplateArg; |
| my %TemplateDecl; |
| my %TemplateMap; |
| |
| # Types |
| my %TypeInfo; |
| my %SkipTypes = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %CheckedTypes; |
| my %TName_Tid; |
| my %EnumMembName_Id; |
| my %NestedNameSpaces = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %VirtualTable; |
| my %VirtualTable_Model; |
| my %ClassVTable; |
| my %ClassVTable_Content; |
| my %VTableClass; |
| my %AllocableClass; |
| my %ClassMethods; |
| my %ClassNames; |
| my %Class_SubClasses; |
| my %OverriddenMethods; |
| my %TypedefToAnon; |
| my $MAX_ID = 0; |
| |
| my %CheckedTypeInfo; |
| |
| # Typedefs |
| my %Typedef_BaseName; |
| my %Typedef_Tr; |
| my %Typedef_Eq; |
| my %StdCxxTypedef; |
| my %MissedTypedef; |
| my %MissedBase; |
| my %MissedBase_R; |
| my %TypeTypedef; |
| |
| # Symbols |
| my %SymbolInfo; |
| my %tr_name; |
| my %mangled_name_gcc; |
| my %mangled_name; |
| my %SkipSymbols = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %SkipNameSpaces = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %AddNameSpaces = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %SymbolsList; |
| my %TypesList; |
| my %SymbolsList_App; |
| my %CheckedSymbols; |
| my %Symbol_Library = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %Library_Symbol = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %DepSymbol_Library = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %DepLibrary_Symbol = ( |
| "1"=>{}, |
| "2"=>{} ); |
| my %MangledNames; |
| my %Func_ShortName; |
| my %AddIntParams; |
| my %GlobalDataObject; |
| my %WeakSymbols; |
| my %Library_Needed= ( |
| "1"=>{}, |
| "2"=>{} ); |
| my $DisabledMSVCUnmangling = undef; |
| |
| # Extra Info |
| my %UndefinedSymbols; |
| my %PreprocessedHeaders; |
| |
| # Headers |
| my %Include_Preamble = ( |
| "1"=>[], |
| "2"=>[] ); |
| my %Registered_Headers; |
| my %Registered_Sources; |
| my %HeaderName_Paths; |
| my %Header_Dependency; |
| my %Include_Neighbors; |
| my %Include_Paths = ( |
| "1"=>[], |
| "2"=>[] ); |
| my %INC_PATH_AUTODETECT = ( |
| "1"=>1, |
| "2"=>1 ); |
| my %Add_Include_Paths = ( |
| "1"=>[], |
| "2"=>[] ); |
| my %Skip_Include_Paths; |
| my %RegisteredDirs; |
| my %Header_ErrorRedirect; |
| my %Header_Includes; |
| my %Header_Includes_R; |
| my %Header_ShouldNotBeUsed; |
| my %RecursiveIncludes; |
| my %Header_Include_Prefix; |
| my %SkipHeaders; |
| my %SkipHeadersList=( |
| "1"=>{}, |
| "2"=>{} ); |
| my %SkipLibs; |
| my %Include_Order; |
| my %TUnit_NameSpaces; |
| my %TUnit_Classes; |
| my %TUnit_Funcs; |
| my %TUnit_Vars; |
| |
| my %CppMode = ( |
| "1"=>0, |
| "2"=>0 ); |
| my %AutoPreambleMode = ( |
| "1"=>0, |
| "2"=>0 ); |
| my %MinGWMode = ( |
| "1"=>0, |
| "2"=>0 ); |
| my %Cpp0xMode = ( |
| "1"=>0, |
| "2"=>0 ); |
| |
| # Shared Objects |
| my %RegisteredObjects; |
| my %RegisteredObjects_Short; |
| my %RegisteredSONAMEs; |
| my %RegisteredObject_Dirs; |
| |
| my %CheckedArch; |
| |
| # System Objects |
| my %SystemObjects; |
| my @DefaultLibPaths; |
| my %DyLib_DefaultPath; |
| |
| # System Headers |
| my %SystemHeaders; |
| my @DefaultCppPaths; |
| my @DefaultGccPaths; |
| my @DefaultIncPaths; |
| my %DefaultCppHeader; |
| my %DefaultGccHeader; |
| my @UsersIncPath; |
| |
| # Merging |
| my %CompleteSignature; |
| my $Version; |
| my %AddedInt; |
| my %RemovedInt; |
| my %AddedInt_Virt; |
| my %RemovedInt_Virt; |
| my %VirtualReplacement; |
| my %ChangedTypedef; |
| my %CompatRules; |
| my %IncompleteRules; |
| my %UnknownRules; |
| my %VTableChanged_M; |
| my %ExtendedSymbols; |
| my %ReturnedClass; |
| my %ParamClass; |
| my %SourceAlternative; |
| my %SourceAlternative_B; |
| my %SourceReplacement; |
| my $CurrentSymbol; # for debugging |
| |
| #Report |
| my %TypeChanges; |
| |
| #Speedup |
| my %TypeProblemsIndex; |
| |
| # Calling Conventions |
| my %UseConv_Real = ( |
| 1=>{ "R"=>0, "P"=>0 }, |
| 2=>{ "R"=>0, "P"=>0 } |
| ); |
| |
| # ABI Dump |
| my %UsedDump; |
| |
| # Filters |
| my %TargetLibs; |
| my %TargetHeaders; |
| |
| # Format of objects |
| my $OStarget = $OSgroup; |
| my %TargetTools; |
| |
| # Recursion locks |
| my @RecurLib; |
| my @RecurTypes; |
| my @RecurTypes_Diff; |
| my @RecurInclude; |
| my @RecurConstant; |
| |
| # System |
| my %SystemPaths = ( |
| "include"=>[], |
| "lib"=>[], |
| "bin"=>[] |
| ); |
| my @DefaultBinPaths; |
| my $GCC_PATH; |
| |
| # Symbols versioning |
| my %SymVer = ( |
| "1"=>{}, |
| "2"=>{} ); |
| |
| # Problem descriptions |
| my %CompatProblems; |
| my %CompatProblems_Constants; |
| my %TotalAffected; |
| |
| # Reports |
| my $ContentID = 1; |
| my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; |
| my $ContentSpanStart_Affected = "<span class=\"sect_aff\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; |
| my $ContentSpanStart_Info = "<span class=\"sect_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; |
| my $ContentSpanEnd = "</span>\n"; |
| my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n"; |
| my $ContentDivEnd = "</div>\n"; |
| my $Content_Counter = 0; |
| |
| # Modes |
| my $JoinReport = 1; |
| my $DoubleReport = 0; |
| |
| my %Severity_Val=( |
| "High"=>3, |
| "Medium"=>2, |
| "Low"=>1, |
| "Safe"=>-1 |
| ); |
| |
| sub get_Modules() |
| { |
| my $TOOL_DIR = get_dirname($0); |
| if(not $TOOL_DIR) |
| { # patch for MS Windows |
| $TOOL_DIR = "."; |
| } |
| my @SEARCH_DIRS = ( |
| # tool's directory |
| abs_path($TOOL_DIR), |
| # relative path to modules |
| abs_path($TOOL_DIR)."/../share/abi-compliance-checker", |
| # install path |
| 'MODULES_INSTALL_PATH' |
| ); |
| foreach my $DIR (@SEARCH_DIRS) |
| { |
| if(not is_abs($DIR)) |
| { # relative path |
| $DIR = abs_path($TOOL_DIR)."/".$DIR; |
| } |
| if(-d $DIR."/modules") { |
| return $DIR."/modules"; |
| } |
| } |
| exitStatus("Module_Error", "can't find modules"); |
| } |
| |
| my %LoadedModules = (); |
| |
| sub loadModule($) |
| { |
| my $Name = $_[0]; |
| if(defined $LoadedModules{$Name}) { |
| return; |
| } |
| my $Path = $MODULES_DIR."/Internals/$Name.pm"; |
| if(not -f $Path) { |
| exitStatus("Module_Error", "can't access \'$Path\'"); |
| } |
| require $Path; |
| $LoadedModules{$Name} = 1; |
| } |
| |
| sub readModule($$) |
| { |
| my ($Module, $Name) = @_; |
| my $Path = $MODULES_DIR."/Internals/$Module/".$Name; |
| if(not -f $Path) { |
| exitStatus("Module_Error", "can't access \'$Path\'"); |
| } |
| return readFile($Path); |
| } |
| |
| sub showPos($) |
| { |
| my $Number = $_[0]; |
| if(not $Number) { |
| $Number = 1; |
| } |
| else { |
| $Number = int($Number)+1; |
| } |
| if($Number>3) { |
| return $Number."th"; |
| } |
| elsif($Number==1) { |
| return "1st"; |
| } |
| elsif($Number==2) { |
| return "2nd"; |
| } |
| elsif($Number==3) { |
| return "3rd"; |
| } |
| else { |
| return $Number; |
| } |
| } |
| |
| sub search_Tools($) |
| { |
| my $Name = $_[0]; |
| return "" if(not $Name); |
| if(my @Paths = keys(%TargetTools)) |
| { |
| foreach my $Path (@Paths) |
| { |
| if(-f join_P($Path, $Name)) { |
| return join_P($Path, $Name); |
| } |
| if($CrossPrefix) |
| { # user-defined prefix (arm-none-symbianelf, ...) |
| my $Candidate = join_P($Path, $CrossPrefix."-".$Name); |
| if(-f $Candidate) { |
| return $Candidate; |
| } |
| } |
| } |
| } |
| else { |
| return ""; |
| } |
| } |
| |
| sub synch_Cmd($) |
| { |
| my $Name = $_[0]; |
| if(not $GCC_PATH) |
| { # GCC was not found yet |
| return ""; |
| } |
| my $Candidate = $GCC_PATH; |
| if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) { |
| return $Candidate; |
| } |
| return ""; |
| } |
| |
| sub get_CmdPath($) |
| { |
| my $Name = $_[0]; |
| return "" if(not $Name); |
| if(defined $Cache{"get_CmdPath"}{$Name}) { |
| return $Cache{"get_CmdPath"}{$Name}; |
| } |
| my %BinUtils = map {$_=>1} ( |
| "c++filt", |
| "objdump", |
| "readelf" |
| ); |
| if($BinUtils{$Name} and $GCC_PATH) |
| { |
| if(my $Dir = get_dirname($GCC_PATH)) { |
| $TargetTools{$Dir}=1; |
| } |
| } |
| my $Path = search_Tools($Name); |
| if(not $Path and $OSgroup eq "windows") { |
| $Path = search_Tools($Name.".exe"); |
| } |
| if(not $Path and $BinUtils{$Name}) |
| { |
| if($CrossPrefix) |
| { # user-defined prefix |
| $Path = search_Cmd($CrossPrefix."-".$Name); |
| } |
| } |
| if(not $Path and $BinUtils{$Name}) |
| { |
| if(my $Candidate = synch_Cmd($Name)) |
| { # synch with GCC |
| if($Candidate=~/[\/\\]/) |
| { # command path |
| if(-f $Candidate) { |
| $Path = $Candidate; |
| } |
| } |
| elsif($Candidate = search_Cmd($Candidate)) |
| { # command name |
| $Path = $Candidate; |
| } |
| } |
| } |
| if(not $Path) { |
| $Path = search_Cmd($Name); |
| } |
| if(not $Path and $OSgroup eq "windows") |
| { # search for *.exe file |
| $Path=search_Cmd($Name.".exe"); |
| } |
| if($Path=~/\s/) { |
| $Path = "\"".$Path."\""; |
| } |
| return ($Cache{"get_CmdPath"}{$Name}=$Path); |
| } |
| |
| sub search_Cmd($) |
| { |
| my $Name = $_[0]; |
| return "" if(not $Name); |
| if(defined $Cache{"search_Cmd"}{$Name}) { |
| return $Cache{"search_Cmd"}{$Name}; |
| } |
| if(my $DefaultPath = get_CmdPath_Default($Name)) { |
| return ($Cache{"search_Cmd"}{$Name} = $DefaultPath); |
| } |
| foreach my $Path (@{$SystemPaths{"bin"}}) |
| { |
| my $CmdPath = join_P($Path,$Name); |
| if(-f $CmdPath) |
| { |
| if($Name=~/gcc/) { |
| next if(not check_gcc($CmdPath, "3")); |
| } |
| return ($Cache{"search_Cmd"}{$Name} = $CmdPath); |
| } |
| } |
| return ($Cache{"search_Cmd"}{$Name} = ""); |
| } |
| |
| sub get_CmdPath_Default($) |
| { # search in PATH |
| return "" if(not $_[0]); |
| if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) { |
| return $Cache{"get_CmdPath_Default"}{$_[0]}; |
| } |
| return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0])); |
| } |
| |
| sub get_CmdPath_Default_I($) |
| { # search in PATH |
| my $Name = $_[0]; |
| if($Name=~/find/) |
| { # special case: search for "find" utility |
| if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) { |
| return "find"; |
| } |
| } |
| elsif($Name=~/gcc/) { |
| return check_gcc($Name, "3"); |
| } |
| if(checkCmd($Name)) { |
| return $Name; |
| } |
| if($OSgroup eq "windows") |
| { |
| if(`$Name /? 2>\"$TMP_DIR/null\"`) { |
| return $Name; |
| } |
| } |
| foreach my $Path (@DefaultBinPaths) |
| { |
| if(-f $Path."/".$Name) { |
| return join_P($Path, $Name); |
| } |
| } |
| return ""; |
| } |
| |
| sub classifyPath($) |
| { |
| my $Path = $_[0]; |
| if($Path=~/[\*\+\(\[\|]/) |
| { # pattern |
| return ($Path, "Pattern"); |
| } |
| elsif($Path=~/[\/\\]/) |
| { # directory or relative path |
| return (path_format($Path, $OSgroup), "Path"); |
| } |
| else { |
| return ($Path, "Name"); |
| } |
| } |
| |
| sub readDescriptor($$) |
| { |
| my ($LibVersion, $Content) = @_; |
| return if(not $LibVersion); |
| my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\""; |
| if(not $Content) { |
| exitStatus("Error", "$DName is empty"); |
| } |
| if($Content!~/\</) { |
| exitStatus("Error", "incorrect descriptor (see -d1 option)"); |
| } |
| $Content=~s/\/\*(.|\n)+?\*\///g; |
| $Content=~s/<\!--(.|\n)+?-->//g; |
| |
| $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version"); |
| if($TargetVersion{$LibVersion}) { |
| $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion}; |
| } |
| if(not $Descriptor{$LibVersion}{"Version"}) { |
| exitStatus("Error", "version in the $DName is not specified (<version> section)"); |
| } |
| if($Content=~/{RELPATH}/) |
| { |
| if(my $RelDir = $RelativeDirectory{$LibVersion}) { |
| $Content =~ s/{RELPATH}/$RelDir/g; |
| } |
| else |
| { |
| my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion"; |
| exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro"); |
| } |
| } |
| |
| my $DHeaders = parseTag(\$Content, "headers"); |
| if(not $DHeaders) { |
| exitStatus("Error", "header files in the $DName are not specified (<headers> section)"); |
| } |
| elsif(lc($DHeaders) ne "none") |
| { # append the descriptor headers list |
| if($Descriptor{$LibVersion}{"Headers"}) |
| { # multiple descriptors |
| $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders; |
| } |
| else { |
| $Descriptor{$LibVersion}{"Headers"} = $DHeaders; |
| } |
| foreach my $Path (split(/\s*\n\s*/, $DHeaders)) |
| { |
| if(not -e $Path) { |
| exitStatus("Access_Error", "can't access \'$Path\'"); |
| } |
| } |
| } |
| |
| if(not $CheckHeadersOnly_Opt) |
| { |
| my $DObjects = parseTag(\$Content, "libs"); |
| if(not $DObjects) { |
| exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)"); |
| } |
| elsif(lc($DObjects) ne "none") |
| { # append the descriptor libraries list |
| if($Descriptor{$LibVersion}{"Libs"}) |
| { # multiple descriptors |
| $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects; |
| } |
| else { |
| $Descriptor{$LibVersion}{"Libs"} .= $DObjects; |
| } |
| foreach my $Path (split(/\s*\n\s*/, $DObjects)) |
| { |
| if(not -e $Path) { |
| exitStatus("Access_Error", "can't access \'$Path\'"); |
| } |
| } |
| } |
| } |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) |
| { |
| if(not -d $Path) { |
| exitStatus("Access_Error", "can't access directory \'$Path\'"); |
| } |
| $Path = get_abs_path($Path); |
| $Path = path_format($Path, $OSgroup); |
| push_U($SystemPaths{"include"}, $Path); |
| } |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) |
| { |
| if(not -d $Path) { |
| exitStatus("Access_Error", "can't access directory \'$Path\'"); |
| } |
| $Path = get_abs_path($Path); |
| $Path = path_format($Path, $OSgroup); |
| push_U($SystemPaths{"lib"}, $Path); |
| } |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) |
| { |
| if(not -d $Path) { |
| exitStatus("Access_Error", "can't access directory \'$Path\'"); |
| } |
| $Path = get_abs_path($Path); |
| $Path = path_format($Path, $OSgroup); |
| push_U($SystemPaths{"bin"}, $Path); |
| $TargetTools{$Path}=1; |
| } |
| if(my $Prefix = parseTag(\$Content, "cross_prefix")) { |
| $CrossPrefix = $Prefix; |
| } |
| $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //= |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) |
| { |
| if(not -d $Path) { |
| exitStatus("Access_Error", "can't access directory \'$Path\'"); |
| } |
| $Path = get_abs_path($Path); |
| $Path = path_format($Path, $OSgroup); |
| push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path); |
| } |
| $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"}); |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) |
| { |
| if(not -d $Path) { |
| exitStatus("Access_Error", "can't access directory \'$Path\'"); |
| } |
| $Path = get_abs_path($Path); |
| $Path = path_format($Path, $OSgroup); |
| push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path); |
| } |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) |
| { # skip some auto-generated include paths |
| if(not is_abs($Path)) |
| { |
| if(my $P = abs_path($Path)) { |
| $Path = $P; |
| } |
| } |
| $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1; |
| } |
| foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) |
| { # skip direct including of some headers |
| my ($CPath, $Type) = classifyPath($Path); |
| $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2; |
| } |
| $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options"); |
| foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) |
| { |
| if($Option!~/\A\-(Wl|l|L)/) |
| { # skip linker options |
| $CompilerOptions{$LibVersion} .= " ".$Option; |
| } |
| } |
| $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers"); |
| foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"})) |
| { |
| $SkipHeadersList{$LibVersion}{$Path} = 1; |
| |
| my ($CPath, $Type) = classifyPath($Path); |
| $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1; |
| } |
| $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs"); |
| foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"})) |
| { |
| my ($CPath, $Type) = classifyPath($Path); |
| $SkipLibs{$LibVersion}{$Type}{$CPath} = 1; |
| } |
| if(my $DDefines = parseTag(\$Content, "defines")) |
| { |
| if($Descriptor{$LibVersion}{"Defines"}) |
| { # multiple descriptors |
| $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines; |
| } |
| else { |
| $Descriptor{$LibVersion}{"Defines"} = $DDefines; |
| } |
| } |
| foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) |
| { |
| if($Order=~/\A(.+):(.+)\Z/) { |
| $Include_Order{$LibVersion}{$1} = $2; |
| } |
| } |
| foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), |
| split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) |
| { # opaque_types renamed to skip_types (1.23.4) |
| $SkipTypes{$LibVersion}{$Type_Name} = 1; |
| } |
| foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), |
| split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) |
| { # skip_interfaces renamed to skip_symbols (1.22.1) |
| $SkipSymbols{$LibVersion}{$Symbol} = 1; |
| } |
| foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { |
| $SkipNameSpaces{$LibVersion}{$NameSpace} = 1; |
| } |
| foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { |
| $AddNameSpaces{$LibVersion}{$NameSpace} = 1; |
| } |
| foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { |
| $SkipConstants{$LibVersion}{$Constant} = 1; |
| } |
| if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) |
| { |
| if($Descriptor{$LibVersion}{"IncludePreamble"}) |
| { # multiple descriptors |
| $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble; |
| } |
| else { |
| $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble; |
| } |
| } |
| } |
| |
| sub parseTag(@) |
| { |
| my $CodeRef = shift(@_); |
| my $Tag = shift(@_); |
| if(not $Tag or not $CodeRef) { |
| return undef; |
| } |
| my $Sp = 0; |
| if(@_) { |
| $Sp = shift(@_); |
| } |
| my $Start = index(${$CodeRef}, "<$Tag>"); |
| if($Start!=-1) |
| { |
| my $End = index(${$CodeRef}, "</$Tag>"); |
| if($End!=-1) |
| { |
| my $TS = length($Tag)+3; |
| my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, ""); |
| substr($Content, 0, $TS-1, ""); # cut start tag |
| substr($Content, -$TS, $TS, ""); # cut end tag |
| if(not $Sp) |
| { |
| $Content=~s/\A\s+//g; |
| $Content=~s/\s+\Z//g; |
| } |
| if(substr($Content, 0, 1) ne "<") { |
| $Content = xmlSpecChars_R($Content); |
| } |
| return $Content; |
| } |
| } |
| return undef; |
| } |
| |
| sub getInfo($) |
| { |
| my $DumpPath = $_[0]; |
| return if(not $DumpPath or not -f $DumpPath); |
| |
| readTUDump($DumpPath); |
| |
| # processing info |
| setTemplateParams_All(); |
| |
| if($ExtraDump) { |
| setAnonTypedef_All(); |
| } |
| |
| getTypeInfo_All(); |
| simplifyNames(); |
| simplifyConstants(); |
| getVarInfo_All(); |
| getSymbolInfo_All(); |
| |
| # clean memory |
| %LibInfo = (); |
| %TemplateInstance = (); |
| %BasicTemplate = (); |
| %MangledNames = (); |
| %TemplateDecl = (); |
| %StdCxxTypedef = (); |
| %MissedTypedef = (); |
| %Typedef_Tr = (); |
| %Typedef_Eq = (); |
| %TypedefToAnon = (); |
| |
| # clean cache |
| delete($Cache{"getTypeAttr"}); |
| delete($Cache{"getTypeDeclId"}); |
| |
| if($ExtraDump) |
| { |
| remove_Unused($Version, "Extra"); |
| } |
| else |
| { # remove unused types |
| if($BinaryOnly and not $ExtendedCheck) |
| { # --binary |
| remove_Unused($Version, "All"); |
| } |
| else { |
| remove_Unused($Version, "Extended"); |
| } |
| } |
| |
| if($CheckInfo) |
| { |
| foreach my $Tid (keys(%{$TypeInfo{$Version}})) { |
| check_Completeness($TypeInfo{$Version}{$Tid}, $Version); |
| } |
| |
| foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { |
| check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); |
| } |
| } |
| |
| if($Debug) { |
| # debugMangling($Version); |
| } |
| } |
| |
| sub readTUDump($) |
| { |
| my $DumpPath = $_[0]; |
| |
| open(TU_DUMP, $DumpPath); |
| local $/ = undef; |
| my $Content = <TU_DUMP>; |
| close(TU_DUMP); |
| |
| unlink($DumpPath); |
| |
| $Content=~s/\n[ ]+/ /g; |
| my @Lines = split(/\n/, $Content); |
| |
| # clean memory |
| undef $Content; |
| |
| $MAX_ID = $#Lines+1; # number of lines == number of nodes |
| |
| foreach (0 .. $#Lines) |
| { |
| if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i) |
| { # get a number and attributes of a node |
| next if(not $NodeType{$2}); |
| $LibInfo{$Version}{"info_type"}{$1}=$2; |
| $LibInfo{$Version}{"info"}{$1}=$3." "; |
| } |
| |
| # clean memory |
| delete($Lines[$_]); |
| } |
| |
| # clean memory |
| undef @Lines; |
| } |
| |
| sub simplifyConstants() |
| { |
| foreach my $Constant (keys(%{$Constants{$Version}})) |
| { |
| if(defined $Constants{$Version}{$Constant}{"Header"}) |
| { |
| my $Value = $Constants{$Version}{$Constant}{"Value"}; |
| if(defined $EnumConstants{$Version}{$Value}) { |
| $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"}; |
| } |
| } |
| } |
| } |
| |
| sub simplifyNames() |
| { |
| foreach my $Base (keys(%{$Typedef_Tr{$Version}})) |
| { |
| if($Typedef_Eq{$Version}{$Base}) { |
| next; |
| } |
| my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}}); |
| if($#Translations==0) |
| { |
| if(length($Translations[0])<=length($Base)) { |
| $Typedef_Eq{$Version}{$Base} = $Translations[0]; |
| } |
| } |
| else |
| { # select most appropriate |
| foreach my $Tr (@Translations) |
| { |
| if($Base=~/\A\Q$Tr\E/) |
| { |
| $Typedef_Eq{$Version}{$Base} = $Tr; |
| last; |
| } |
| } |
| } |
| } |
| foreach my $TypeId (keys(%{$TypeInfo{$Version}})) |
| { |
| my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"}; |
| if(not $TypeName) { |
| next; |
| } |
| next if(index($TypeName,"<")==-1);# template instances only |
| if($TypeName=~/>(::\w+)+\Z/) |
| { # skip unused types |
| next; |
| } |
| foreach my $Base (sort {length($b)<=>length($a)} |
| sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}})) |
| { |
| next if(not $Base); |
| next if(index($TypeName,$Base)==-1); |
| next if(length($TypeName) - length($Base) <= 3); |
| if(my $Typedef = $Typedef_Eq{$Version}{$Base}) |
| { |
| $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g; |
| $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g; |
| if(defined $TypeInfo{$Version}{$TypeId}{"TParam"}) |
| { |
| foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}})) |
| { |
| if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"}) |
| { |
| $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g; |
| $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g; |
| $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T"); |
| } |
| } |
| } |
| } |
| } |
| $TypeName = formatName($TypeName, "T"); |
| $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName; |
| $TName_Tid{$Version}{$TypeName} = $TypeId; |
| } |
| } |
| |
| sub setAnonTypedef_All() |
| { |
| foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}})) |
| { |
| if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl") |
| { |
| if(isAnon(getNameByInfo($InfoId))) { |
| $TypedefToAnon{getTypeId($InfoId)} = 1; |
| } |
| } |
| } |
| } |
| |
| sub setTemplateParams_All() |
| { |
| foreach (keys(%{$LibInfo{$Version}{"info"}})) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") { |
| setTemplateParams($_); |
| } |
| } |
| } |
| |
| sub setTemplateParams($) |
| { |
| my $Tid = getTypeId($_[0]); |
| if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) |
| { |
| my $TmplInst_Id = $2; |
| setTemplateInstParams($_[0], $TmplInst_Id); |
| while($TmplInst_Id = getNextElem($TmplInst_Id)) { |
| setTemplateInstParams($_[0], $TmplInst_Id); |
| } |
| } |
| |
| $BasicTemplate{$Version}{$Tid} = $_[0]; |
| |
| if(my $Prms = getTreeAttr_Prms($_[0])) |
| { |
| if(my $Valu = getTreeAttr_Valu($Prms)) |
| { |
| my $Vector = getTreeVec($Valu); |
| foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) |
| { |
| if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) |
| { |
| if(my $Name = getNameByInfo($Val)) |
| { |
| $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; |
| if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { |
| $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; |
| } |
| else { |
| $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| if(my $TypeId = getTreeAttr_Type($_[0])) |
| { |
| if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) |
| { |
| if($IType eq "record_type") { |
| $TemplateDecl{$Version}{$TypeId} = 1; |
| } |
| } |
| } |
| } |
| |
| sub setTemplateInstParams($$) |
| { |
| my ($Tmpl, $Inst) = @_; |
| |
| if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) |
| { |
| my ($Params_InfoId, $ElemId) = (); |
| if($Info=~/purp[ ]*:[ ]*@(\d+) /) { |
| $Params_InfoId = $1; |
| } |
| if($Info=~/valu[ ]*:[ ]*@(\d+) /) { |
| $ElemId = $1; |
| } |
| if($Params_InfoId and $ElemId) |
| { |
| my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId}; |
| while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) |
| { |
| my ($PPos, $PTypeId) = ($1, $2); |
| if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) |
| { |
| if($PType eq "template_type_parm") { |
| $TemplateDecl{$Version}{$ElemId} = 1; |
| } |
| } |
| if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") |
| { # functions |
| $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; |
| $BasicTemplate{$Version}{$ElemId} = $Tmpl; |
| } |
| else |
| { # types |
| $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; |
| $BasicTemplate{$Version}{$ElemId} = $Tmpl; |
| } |
| } |
| } |
| } |
| } |
| |
| sub getTypeDeclId($) |
| { |
| if($_[0]) |
| { |
| if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) { |
| return $Cache{"getTypeDeclId"}{$Version}{$_[0]}; |
| } |
| if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($Info=~/name[ ]*:[ ]*@(\d+)/) { |
| return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1); |
| } |
| } |
| } |
| return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0); |
| } |
| |
| sub getTypeInfo_All() |
| { |
| if(not check_gcc($GCC_PATH, "4.5")) |
| { # support for GCC < 4.5 |
| # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag> |
| # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump |
| # FIXME: check GCC versions |
| addMissedTypes_Pre(); |
| } |
| |
| foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) |
| { # forward order only |
| my $IType = $LibInfo{$Version}{"info_type"}{$_}; |
| if($IType=~/_type\Z/ and $IType ne "function_type" |
| and $IType ne "method_type") { |
| getTypeInfo("$_"); |
| } |
| } |
| |
| # add "..." type |
| $TypeInfo{$Version}{"-1"} = { |
| "Name" => "...", |
| "Type" => "Intrinsic", |
| "Tid" => "-1" |
| }; |
| $TName_Tid{$Version}{"..."} = "-1"; |
| |
| if(not check_gcc($GCC_PATH, "4.5")) |
| { # support for GCC < 4.5 |
| addMissedTypes_Post(); |
| } |
| |
| if($ADD_TMPL_INSTANCES) |
| { |
| # templates |
| foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) |
| { |
| if(defined $TemplateMap{$Version}{$Tid} |
| and not defined $TypeInfo{$Version}{$Tid}{"Template"}) |
| { |
| if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) |
| { |
| foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) |
| { |
| if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) |
| { |
| if(my %MAttr = getTypeAttr($MembTypeId)) |
| { |
| $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; |
| $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); |
| } |
| } |
| } |
| } |
| if(defined $TypeInfo{$Version}{$Tid}{"Base"}) |
| { |
| foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) |
| { |
| my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); |
| |
| if($NBid ne $Bid |
| and $NBid ne $Tid) |
| { |
| %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; |
| delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| sub createType($$) |
| { |
| my ($Attr, $LibVersion) = @_; |
| my $NewId = ++$MAX_ID; |
| |
| $Attr->{"Tid"} = $NewId; |
| $TypeInfo{$Version}{$NewId} = $Attr; |
| $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; |
| |
| return "$NewId"; |
| } |
| |
| sub instType($$$) |
| { # create template instances |
| my ($Map, $Tid, $LibVersion) = @_; |
| |
| if(not $TypeInfo{$LibVersion}{$Tid}) { |
| return undef; |
| } |
| my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); |
| |
| foreach my $Key (sort keys(%{$Map})) |
| { |
| if(my $Val = $Map->{$Key}) |
| { |
| $Attr->{"Name"}=~s/\b$Key\b/$Val/g; |
| |
| if(defined $Attr->{"NameSpace"}) { |
| $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; |
| } |
| foreach (keys(%{$Attr->{"TParam"}})) { |
| $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; |
| } |
| } |
| else |
| { # remove absent |
| # _Traits, etc. |
| $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; |
| if(defined $Attr->{"NameSpace"}) { |
| $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; |
| } |
| foreach (keys(%{$Attr->{"TParam"}})) |
| { |
| if($Attr->{"TParam"}{$_}{"name"} eq $Key) { |
| delete($Attr->{"TParam"}{$_}); |
| } |
| else { |
| $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; |
| } |
| } |
| } |
| } |
| |
| my $Tmpl = 0; |
| |
| if(defined $Attr->{"TParam"}) |
| { |
| foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) |
| { |
| my $PName = $Attr->{"TParam"}{$_}{"name"}; |
| |
| if(my $PTid = $TName_Tid{$LibVersion}{$PName}) |
| { |
| my %Base = get_BaseType($PTid, $LibVersion); |
| |
| if($Base{"Type"} eq "TemplateParam" |
| or defined $Base{"Template"}) |
| { |
| $Tmpl = 1; |
| last |
| } |
| } |
| } |
| } |
| |
| if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { |
| return "$Id"; |
| } |
| else |
| { |
| if(not $Tmpl) { |
| delete($Attr->{"Template"}); |
| } |
| |
| my $New = createType($Attr, $LibVersion); |
| |
| my %EMap = (); |
| if(defined $TemplateMap{$LibVersion}{$Tid}) { |
| %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; |
| } |
| foreach (keys(%{$Map})) { |
| $EMap{$_} = $Map->{$_}; |
| } |
| |
| if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { |
| $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); |
| } |
| if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) |
| { |
| foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) |
| { |
| my $NBid = instType(\%EMap, $Bid, $LibVersion); |
| |
| if($NBid ne $Bid |
| and $NBid ne $New) |
| { |
| %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; |
| delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); |
| } |
| } |
| } |
| |
| if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) |
| { |
| foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) |
| { |
| if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { |
| $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); |
| } |
| } |
| } |
| |
| if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) |
| { |
| foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { |
| $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); |
| } |
| } |
| |
| if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { |
| $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); |
| } |
| |
| return $New; |
| } |
| } |
| |
| sub addMissedTypes_Pre() |
| { |
| my %MissedTypes = (); |
| foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) |
| { # detecting missed typedefs |
| if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl") |
| { |
| my $TypeId = getTreeAttr_Type($MissedTDid); |
| next if(not $TypeId); |
| my $TypeType = getTypeType($TypeId); |
| if($TypeType eq "Unknown") |
| { # template_type_parm |
| next; |
| } |
| my $TypeDeclId = getTypeDeclId($TypeId); |
| next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId |
| my $TypedefName = getNameByInfo($MissedTDid); |
| next if(not $TypedefName); |
| next if($TypedefName eq "__float80"); |
| next if(isAnon($TypedefName)); |
| if(not $TypeDeclId |
| or getNameByInfo($TypeDeclId) ne $TypedefName) { |
| $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1; |
| } |
| } |
| } |
| my %AddTypes = (); |
| foreach my $Tid (keys(%{$MissedTypes{$Version}})) |
| { # add missed typedefs |
| my @Missed = keys(%{$MissedTypes{$Version}{$Tid}}); |
| if(not @Missed or $#Missed>=1) { |
| next; |
| } |
| my $MissedTDid = $Missed[0]; |
| my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid); |
| if(not $TypedefName) { |
| next; |
| } |
| my $NewId = ++$MAX_ID; |
| my %MissedInfo = ( # typedef info |
| "Name" => $TypedefName, |
| "NameSpace" => $TypedefNS, |
| "BaseType" => $Tid, |
| "Type" => "Typedef", |
| "Tid" => "$NewId" ); |
| my ($H, $L) = getLocation($MissedTDid); |
| $MissedInfo{"Header"} = $H; |
| $MissedInfo{"Line"} = $L; |
| if($TypedefName=~/\*|\&|\s/) |
| { # other types |
| next; |
| } |
| if($TypedefName=~/>(::\w+)+\Z/) |
| { # QFlags<Qt::DropAction>::enum_type |
| next; |
| } |
| if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) |
| { # double-check for the name of typedef |
| my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info |
| next if(not $TName); |
| if(length($TypedefName)>=length($TName)) |
| { # too long typedef |
| next; |
| } |
| if($TName=~/\A\Q$TypedefName\E</) { |
| next; |
| } |
| if($TypedefName=~/\A\Q$TName\E/) |
| { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type |
| next; |
| } |
| if(get_depth($TypedefName)==0 and get_depth($TName)!=0) |
| { # std::_Vector_base and std::vector::_Base |
| next; |
| } |
| } |
| |
| $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo; |
| |
| # register typedef |
| $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"}; |
| $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid; |
| $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"}; |
| } |
| |
| # add missed & remove other |
| $TypeInfo{$Version} = \%AddTypes; |
| delete($Cache{"getTypeAttr"}{$Version}); |
| } |
| |
| sub addMissedTypes_Post() |
| { |
| foreach my $BaseId (keys(%{$MissedTypedef{$Version}})) |
| { |
| if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"}) |
| { |
| $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"}; |
| if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) { |
| $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"}; |
| } |
| } |
| } |
| } |
| |
| sub getTypeInfo($) |
| { |
| my $TypeId = $_[0]; |
| %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId); |
| my $TName = $TypeInfo{$Version}{$TypeId}{"Name"}; |
| if(not $TName) { |
| delete($TypeInfo{$Version}{$TypeId}); |
| } |
| } |
| |
| sub getArraySize($$) |
| { |
| my ($TypeId, $BaseName) = @_; |
| if(my $Size = getSize($TypeId)) |
| { |
| my $Elems = $Size/$BYTE_SIZE; |
| while($BaseName=~s/\s*\[(\d+)\]//) { |
| $Elems/=$1; |
| } |
| if(my $BasicId = $TName_Tid{$Version}{$BaseName}) |
| { |
| if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) { |
| $Elems/=$BasicSize; |
| } |
| } |
| return $Elems; |
| } |
| return 0; |
| } |
| |
| sub getTParams($$) |
| { |
| my ($TypeId, $Kind) = @_; |
| my @TmplParams = (); |
| my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}}); |
| foreach my $Pos (@Positions) |
| { |
| my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos}; |
| my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId}; |
| if(not $NodeType) |
| { # typename_type |
| return (); |
| } |
| if($NodeType eq "tree_vec") |
| { |
| if($Pos!=$#Positions) |
| { # select last vector of parameters ( ns<P1>::type<P2> ) |
| next; |
| } |
| } |
| my @Params = get_TemplateParam($Pos, $Param_TypeId); |
| foreach my $P (@Params) |
| { |
| if($P eq "") { |
| return (); |
| } |
| elsif($P ne "\@skip\@") { |
| @TmplParams = (@TmplParams, $P); |
| } |
| } |
| } |
| return @TmplParams; |
| } |
| |
| sub getTypeAttr($) |
| { |
| my $TypeId = $_[0]; |
| my %TypeAttr = (); |
| if(defined $TypeInfo{$Version}{$TypeId} |
| and $TypeInfo{$Version}{$TypeId}{"Name"}) |
| { # already created |
| return %{$TypeInfo{$Version}{$TypeId}}; |
| } |
| elsif($Cache{"getTypeAttr"}{$Version}{$TypeId}) |
| { # incomplete type |
| return (); |
| } |
| $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1; |
| |
| my $TypeDeclId = getTypeDeclId($TypeId); |
| $TypeAttr{"Tid"} = $TypeId; |
| |
| if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId)) |
| { |
| if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) |
| { |
| if($Info=~/qual[ ]*:/) |
| { |
| my $NewId = ++$MAX_ID; |
| |
| $MissedBase{$Version}{$TypeId} = "$NewId"; |
| $MissedBase_R{$Version}{$NewId} = $TypeId; |
| $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; |
| $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; |
| } |
| } |
| $TypeAttr{"Type"} = "Typedef"; |
| } |
| else { |
| $TypeAttr{"Type"} = getTypeType($TypeId); |
| } |
| |
| if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) |
| { |
| if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") |
| { # local code |
| return (); |
| } |
| } |
| |
| if($TypeAttr{"Type"} eq "Unknown") { |
| return (); |
| } |
| elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/) |
| { |
| %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"}); |
| if(my $TName = $TypeAttr{"Name"}) |
| { |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| $TName_Tid{$Version}{$TName} = $TypeId; |
| return %TypeAttr; |
| } |
| else { |
| return (); |
| } |
| } |
| elsif($TypeAttr{"Type"} eq "Array") |
| { |
| my ($BTid, $BTSpec) = selectBaseType($TypeId); |
| if(not $BTid) { |
| return (); |
| } |
| if(my $Algn = getAlgn($TypeId)) { |
| $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; |
| } |
| $TypeAttr{"BaseType"} = $BTid; |
| if(my %BTAttr = getTypeAttr($BTid)) |
| { |
| if(not $BTAttr{"Name"}) { |
| return (); |
| } |
| if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"})) |
| { |
| if(my $Size = getSize($TypeId)) { |
| $TypeAttr{"Size"} = $Size/$BYTE_SIZE; |
| } |
| if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { |
| $TypeAttr{"Name"} = $1."[$NElems]".$2; |
| } |
| else { |
| $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]"; |
| } |
| } |
| else |
| { |
| $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer |
| if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { |
| $TypeAttr{"Name"} = $1."[]".$2; |
| } |
| else { |
| $TypeAttr{"Name"} = $BTAttr{"Name"}."[]"; |
| } |
| } |
| $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); |
| if($BTAttr{"Header"}) { |
| $TypeAttr{"Header"} = $BTAttr{"Header"}; |
| } |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; |
| return %TypeAttr; |
| } |
| return (); |
| } |
| elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) |
| { |
| %TypeAttr = getTrivialTypeAttr($TypeId); |
| if($TypeAttr{"Name"}) |
| { |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| |
| if(not defined $IntrinsicNames{$TypeAttr{"Name"}} |
| or getTypeDeclId($TypeAttr{"Tid"})) |
| { # NOTE: register only one int: with built-in decl |
| if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { |
| $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; |
| } |
| } |
| return %TypeAttr; |
| } |
| else { |
| return (); |
| } |
| } |
| elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) |
| { |
| %TypeAttr = getTrivialTypeAttr($TypeId); |
| if($TypeAttr{"Name"}) |
| { |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { |
| $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; |
| } |
| return %TypeAttr; |
| } |
| else { |
| return (); |
| } |
| } |
| elsif($TypeAttr{"Type"} eq "SizeOf") |
| { |
| $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); |
| my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); |
| $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; |
| if($TypeAttr{"Name"}) |
| { |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| return %TypeAttr; |
| } |
| else { |
| return (); |
| } |
| } |
| else |
| { # derived types |
| my ($BTid, $BTSpec) = selectBaseType($TypeId); |
| if(not $BTid) { |
| return (); |
| } |
| $TypeAttr{"BaseType"} = $BTid; |
| if(defined $MissedTypedef{$Version}{$BTid}) |
| { |
| if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"}) |
| { |
| if($MissedTDid ne $TypeDeclId) { |
| $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"}; |
| } |
| } |
| } |
| my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); |
| if(not $BTAttr{"Name"}) |
| { # templates |
| return (); |
| } |
| if($BTAttr{"Type"} eq "Typedef") |
| { # relinking typedefs |
| my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version); |
| if($BTAttr{"Name"} eq $BaseBase{"Name"}) { |
| $TypeAttr{"BaseType"} = $BaseBase{"Tid"}; |
| } |
| } |
| if($BTSpec) |
| { |
| if($TypeAttr{"Type"} eq "Pointer" |
| and $BTAttr{"Name"}=~/\([\*]+\)/) |
| { |
| $TypeAttr{"Name"} = $BTAttr{"Name"}; |
| $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g; |
| } |
| else { |
| $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec; |
| } |
| } |
| else { |
| $TypeAttr{"Name"} = $BTAttr{"Name"}; |
| } |
| if($TypeAttr{"Type"} eq "Typedef") |
| { |
| $TypeAttr{"Name"} = getNameByInfo($TypeDeclId); |
| |
| if(index($TypeAttr{"Name"}, "tmp_add_type")==0) { |
| return (); |
| } |
| |
| if(isAnon($TypeAttr{"Name"})) |
| { # anon typedef to anon type: ._N |
| return (); |
| } |
| |
| if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i) |
| { # artificial typedef of "struct X" to "X" |
| $TypeAttr{"Artificial"} = 1; |
| } |
| |
| if(my $NS = getNameSpace($TypeDeclId)) |
| { |
| my $TypeName = $TypeAttr{"Name"}; |
| if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/) |
| { # "some_type" is the typedef to "struct some_type" in C++ |
| if($3) { |
| $TypeAttr{"Name"} = $3."::".$TypeName; |
| } |
| } |
| else |
| { |
| $TypeAttr{"NameSpace"} = $NS; |
| $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; |
| |
| if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ |
| and $TypeAttr{"Name"}!~/>(::\w+)+\Z/) |
| { |
| if($BTAttr{"NameSpace"} |
| and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</) |
| { # types like "std::fpos<__mbstate_t>" are |
| # not covered by typedefs in the TU dump |
| # so trying to add such typedefs manually |
| $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; |
| if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"})) |
| { |
| if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) |
| { # skip "other" in "std" and "type" in "boost" |
| $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"}; |
| } |
| } |
| } |
| } |
| } |
| } |
| if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"} |
| and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/) |
| { |
| if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}}) |
| { # typedef int*const TYPEDEF; // first |
| # int foo(TYPEDEF p); // const is optimized out |
| $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"}; |
| if($BTAttr{"Name"}=~/</) |
| { |
| if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) { |
| $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; |
| } |
| } |
| } |
| } |
| ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId); |
| } |
| if(not $TypeAttr{"Size"}) |
| { |
| if($TypeAttr{"Type"} eq "Pointer") { |
| $TypeAttr{"Size"} = $WORD_SIZE{$Version}; |
| } |
| elsif($BTAttr{"Size"}) { |
| $TypeAttr{"Size"} = $BTAttr{"Size"}; |
| } |
| } |
| if(my $Algn = getAlgn($TypeId)) { |
| $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; |
| } |
| $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); |
| if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) { |
| $TypeAttr{"Header"} = $BTAttr{"Header"}; |
| } |
| %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; |
| if($TypeAttr{"Name"} ne $BTAttr{"Name"}) |
| { # typedef to "class Class" |
| # should not be registered in TName_Tid |
| if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { |
| $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; |
| } |
| } |
| return %TypeAttr; |
| } |
| } |
| |
| sub getTreeVec($) |
| { |
| my %Vector = (); |
| if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) |
| { # string length is N-1 because of the null terminator |
| $Vector{$1} = $2; |
| } |
| } |
| return \%Vector; |
| } |
| |
| sub get_TemplateParam($$) |
| { |
| my ($Pos, $Type_Id) = @_; |
| return () if(not $Type_Id); |
| my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id}; |
| return () if(not $NodeType); |
| if($NodeType eq "integer_cst") |
| { # int (1), unsigned (2u), char ('c' as 99), ... |
| my $CstTid = getTreeAttr_Type($Type_Id); |
| my %CstType = getTypeAttr($CstTid); # without recursion |
| my $Num = getNodeIntCst($Type_Id); |
| if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) { |
| return ($Num.$CstSuffix); |
| } |
| else { |
| return ("(".$CstType{"Name"}.")".$Num); |
| } |
| } |
| elsif($NodeType eq "string_cst") { |
| return (getNodeStrCst($Type_Id)); |
| } |
| elsif($NodeType eq "tree_vec") |
| { |
| my $Vector = getTreeVec($Type_Id); |
| my @Params = (); |
| foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector})) |
| { |
| foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) { |
| push(@Params, $P2); |
| } |
| } |
| return @Params; |
| } |
| elsif($NodeType eq "parm_decl") |
| { |
| (getNameByInfo($Type_Id)); |
| } |
| else |
| { |
| my %ParamAttr = getTypeAttr($Type_Id); |
| my $PName = $ParamAttr{"Name"}; |
| if(not $PName) { |
| return (); |
| } |
| if($PName=~/\>/) |
| { |
| if(my $Cover = cover_stdcxx_typedef($PName)) { |
| $PName = $Cover; |
| } |
| } |
| if($Pos>=1 and |
| $PName=~/\A$DEFAULT_STD_PARMS\</) |
| { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> > |
| # template<typename _Key, typename _Compare = std::less<_Key> |
| # template<typename _CharT, typename _Traits = std::char_traits<_CharT> > |
| # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> > |
| # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> > |
| # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> > |
| return ("\@skip\@"); |
| } |
| return ($PName); |
| } |
| } |
| |
| sub cover_stdcxx_typedef($) |
| { |
| my $TypeName = $_[0]; |
| if(my @Covers = sort {length($a)<=>length($b)} |
| sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) |
| { # take the shortest typedef |
| # FIXME: there may be more than |
| # one typedefs to the same type |
| return $Covers[0]; |
| } |
| my $Covered = $TypeName; |
| while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){}; |
| if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) |
| { |
| if(my $Cover = $Covers[0]) |
| { |
| $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g; |
| $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g; |
| } |
| } |
| return formatName($Covered, "T"); |
| } |
| |
| sub getNodeIntCst($) |
| { |
| my $CstId = $_[0]; |
| my $CstTypeId = getTreeAttr_Type($CstId); |
| if($EnumMembName_Id{$Version}{$CstId}) { |
| return $EnumMembName_Id{$Version}{$CstId}; |
| } |
| elsif((my $Value = getTreeValue($CstId)) ne "") |
| { |
| if($Value eq "0") |
| { |
| if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { |
| return "false"; |
| } |
| else { |
| return "0"; |
| } |
| } |
| elsif($Value eq "1") |
| { |
| if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { |
| return "true"; |
| } |
| else { |
| return "1"; |
| } |
| } |
| else { |
| return $Value; |
| } |
| } |
| return ""; |
| } |
| |
| sub getNodeStrCst($) |
| { |
| if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst") |
| { # string length is N-1 because of the null terminator |
| return substr($1, 0, $2-1); |
| } |
| else |
| { # identifier_node |
| return substr($1, 0, $2); |
| } |
| } |
| } |
| return ""; |
| } |
| |
| sub getMemPtrAttr($$$) |
| { # function, method and field pointers |
| my ($PtrId, $TypeId, $Type) = @_; |
| my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId}; |
| if($Type eq "FieldPtr") { |
| $MemInfo = $LibInfo{$Version}{"info"}{$TypeId}; |
| } |
| my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId}; |
| my $MemPtrName = ""; |
| my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId); |
| if($Type eq "MethodPtr") |
| { # size of "method pointer" may be greater than WORD size |
| if(my $Size = getSize($TypeId)) |
| { |
| $Size/=$BYTE_SIZE; |
| $TypeAttr{"Size"} = "$Size"; |
| } |
| } |
| if(my $Algn = getAlgn($TypeId)) { |
| $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; |
| } |
| # Return |
| if($Type eq "FieldPtr") |
| { |
| my %ReturnAttr = getTypeAttr($PtrId); |
| if($ReturnAttr{"Name"}) { |
| $MemPtrName .= $ReturnAttr{"Name"}; |
| } |
| $TypeAttr{"Return"} = $PtrId; |
| } |
| else |
| { |
| if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /) |
| { |
| my $ReturnTypeId = $1; |
| my %ReturnAttr = getTypeAttr($ReturnTypeId); |
| if(not $ReturnAttr{"Name"}) |
| { # templates |
| return (); |
| } |
| $MemPtrName .= $ReturnAttr{"Name"}; |
| $TypeAttr{"Return"} = $ReturnTypeId; |
| } |
| } |
| # Class |
| if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /) |
| { |
| $TypeAttr{"Class"} = $2; |
| my %Class = getTypeAttr($TypeAttr{"Class"}); |
| if($Class{"Name"}) { |
| $MemPtrName .= " (".$Class{"Name"}."\:\:*)"; |
| } |
| else { |
| $MemPtrName .= " (*)"; |
| } |
| } |
| else { |
| $MemPtrName .= " (*)"; |
| } |
| # Parameters |
| if($Type eq "FuncPtr" |
| or $Type eq "MethodPtr") |
| { |
| my @ParamTypeName = (); |
| if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /) |
| { |
| my $PTypeInfoId = $1; |
| my ($Pos, $PPos) = (0, 0); |
| while($PTypeInfoId) |
| { |
| my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId}; |
| if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /) |
| { |
| my $PTypeId = $1; |
| my %ParamAttr = getTypeAttr($PTypeId); |
| if(not $ParamAttr{"Name"}) |
| { # templates (template_type_parm), etc. |
| return (); |
| } |
| if($ParamAttr{"Name"} eq "void") { |
| last; |
| } |
| if($Pos!=0 or $Type ne "MethodPtr") |
| { |
| $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId; |
| push(@ParamTypeName, $ParamAttr{"Name"}); |
| } |
| if($PTypeInfoId = getNextElem($PTypeInfoId)) { |
| $Pos+=1; |
| } |
| else { |
| last; |
| } |
| } |
| else { |
| last; |
| } |
| } |
| } |
| $MemPtrName .= " (".join(", ", @ParamTypeName).")"; |
| } |
| $TypeAttr{"Name"} = formatName($MemPtrName, "T"); |
| return %TypeAttr; |
| } |
| |
| sub getTreeTypeName($) |
| { |
| my $TypeId = $_[0]; |
| if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type") |
| { |
| if(my $Name = getNameByInfo($TypeId)) |
| { # bit_size_type |
| return $Name; |
| } |
| elsif($Info=~/unsigned/) { |
| return "unsigned int"; |
| } |
| else { |
| return "int"; |
| } |
| } |
| elsif($Info=~/name[ ]*:[ ]*@(\d+) /) { |
| return getNameByInfo($1); |
| } |
| } |
| return ""; |
| } |
| |
| sub isFuncPtr($) |
| { |
| my $Ptd = pointTo($_[0]); |
| return 0 if(not $Ptd); |
| if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) { |
| return 0; |
| } |
| } |
| if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]} |
| and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd}) |
| { |
| if($InfoT1 eq "pointer_type" |
| and $InfoT2 eq "function_type") { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| sub isMethodPtr($) |
| { |
| my $Ptd = pointTo($_[0]); |
| return 0 if(not $Ptd); |
| if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type" |
| and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type" |
| and $Info=~/ ptrmem /) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| sub isFieldPtr($) |
| { |
| if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type" |
| and $Info=~/ ptrmem /) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| sub pointTo($) |
| { |
| if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if($Info=~/ptd[ ]*:[ ]*@(\d+)/) { |
| return $1; |
| } |
| } |
| return ""; |
| } |
| |
| sub getTypeTypeByTypeId($) |
| { |
| my $TypeId = $_[0]; |
| if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId}) |
| { |
| my $NType = $NodeType{$TType}; |
| if($NType eq "Intrinsic") { |
| return $NType; |
| } |
| elsif(isFuncPtr($TypeId)) { |
| return "FuncPtr"; |
| } |
| elsif(isMethodPtr($TypeId)) { |
| return "MethodPtr"; |
| } |
| elsif(isFieldPtr($TypeId)) { |
| return "FieldPtr"; |
| } |
| elsif($NType ne "Other") { |
| return $NType; |
| } |
| } |
| return "Unknown"; |
| } |
| |
| my %UnQual = ( |
| "r"=>"restrict", |
| "v"=>"volatile", |
| "c"=>"const", |
| "cv"=>"const volatile" |
| ); |
| |
| sub getQual($) |
| { |
| my $TypeId = $_[0]; |
| if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) |
| { |
| my ($Qual, $To) = (); |
| if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) { |
| $Qual = $UnQual{$1}; |
| } |
| if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { |
| $To = $1; |
| } |
| if($Qual and $To) { |
| return ($Qual, $To); |
| } |
| } |
| return (); |
| } |
| |
| sub getQualType($) |
| { |
| if($_[0] eq "const volatile") { |
| return "ConstVolatile"; |
| } |
| return ucfirst($_[0]); |
| } |
| |
| sub getTypeType($) |
| { |
| my $TypeId = $_[0]; |
| my $TypeDeclId = getTypeDeclId($TypeId); |
| if(defined $MissedTypedef{$Version}{$TypeId}) |
| { # support for old GCC versions |
| if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) { |
| return "Typedef"; |
| } |
| } |
| my $Info = $LibInfo{$Version}{"info"}{$TypeId}; |
| my ($Qual, $To) = getQual($TypeId); |
| if(($Qual or $To) and $TypeDeclId |
| and (getTypeId($TypeDeclId) ne $TypeId)) |
| { # qualified types (special) |
| return getQualType($Qual); |
| } |
| elsif(not $MissedBase_R{$Version}{$TypeId} |
| and isTypedef($TypeId)) { |
| return "Typedef"; |
| } |
| elsif($Qual) |
| { # qualified types |
| return getQualType($Qual); |
| } |
| |
| if($Info=~/unql[ ]*:[ ]*\@(\d+)/) |
| { # typedef struct { ... } name |
| $TypeTypedef{$Version}{$TypeId} = $1; |
| } |
| |
| my $TypeType = getTypeTypeByTypeId($TypeId); |
| if($TypeType eq "Struct") |
| { |
| if($TypeDeclId |
| and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") { |
| return "Template"; |
| } |
| } |
| return $TypeType; |
| } |
| |
| sub isTypedef($) |
| { |
| if($_[0]) |
| { |
| if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") |
| { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); |
| return 0; |
| } |
| if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) |
| { |
| if(my $TDid = getTypeDeclId($_[0])) |
| { |
| if(getTypeId($TDid) eq $_[0] |
| and getNameByInfo($TDid)) |
| { |
| if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { |
| return $1; |
| } |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| sub selectBaseType($) |
| { |
| my $TypeId = $_[0]; |
| if(defined $MissedTypedef{$Version}{$TypeId}) |
| { # add missed typedefs |
| if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) { |
| return ($TypeId, ""); |
| } |
| } |
| my $Info = $LibInfo{$Version}{"info"}{$TypeId}; |
| my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId}; |
| |
| my $MB_R = $MissedBase_R{$Version}{$TypeId}; |
| my $MB = $MissedBase{$Version}{$TypeId}; |
| |
| my ($Qual, $To) = getQual($TypeId); |
| if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) / |
| and (getTypeId($1) ne $TypeId) |
| and (not $MB_R or getTypeId($1) ne $MB_R)) |
| { # qualified types (special) |
| return (getTypeId($1), $Qual); |
| } |
| elsif($MB) |
| { # add base |
| return ($MB, ""); |
| } |
| elsif(not $MB_R and my $Bid = isTypedef($TypeId)) |
| { # typedefs |
| return ($Bid, ""); |
| } |
| elsif($Qual or $To) |
| { # qualified types |
| return ($To, $Qual); |
| } |
| elsif($InfoType eq "reference_type") |
| { |
| if($Info=~/refd[ ]*:[ ]*@(\d+) /) { |
| return ($1, "&"); |
| } |
| } |
| elsif($InfoType eq "array_type") |
| { |
| if($Info=~/elts[ ]*:[ ]*@(\d+) /) { |
| return ($1, ""); |
| } |
| } |
| elsif($InfoType eq "pointer_type") |
| { |
| if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { |
| return ($1, "*"); |
| } |
| } |
| |
| return (0, ""); |
| } |
| |
| sub getSymbolInfo_All() |
| { |
| foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) |
| { # reverse order |
| if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") { |
| getSymbolInfo($_); |
| } |
| } |
| |
| if($ADD_TMPL_INSTANCES) |
| { |
| # templates |
| foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) |
| { |
| my %Map = (); |
| |
| if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) |
| { |
| if(defined $TemplateMap{$Version}{$ClassId}) |
| { |
| foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { |
| $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; |
| } |
| } |
| } |
| |
| if(defined $TemplateMap{$Version}{$Sid}) |
| { |
| foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { |
| $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; |
| } |
| } |
| |
| if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) |
| { |
| foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) |
| { |
| my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; |
| $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); |
| } |
| } |
| if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { |
| $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); |
| } |
| } |
| } |
| } |
| |
| sub getVarInfo_All() |
| { |
| foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) |
| { # reverse order |
| if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") { |
| getVarInfo($_); |
| } |
| } |
| } |
| |
| sub isBuiltIn($) { |
| return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./); |
| } |
| |
| sub getVarInfo($) |
| { |
| my $InfoId = $_[0]; |
| if(my $NSid = getTreeAttr_Scpe($InfoId)) |
| { |
| my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid}; |
| if($NSInfoType and $NSInfoType eq "function_decl") { |
| return; |
| } |
| } |
| ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); |
| if(not $SymbolInfo{$Version}{$InfoId}{"Header"} |
| or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| my $ShortName = getTreeStr(getTreeAttr_Name($InfoId)); |
| if(not $ShortName) { |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| if($ShortName=~/\Atmp_add_class_\d+\Z/) { |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName; |
| if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) |
| { |
| if($OSgroup eq "windows") |
| { # cut the offset |
| $MnglName=~s/\@\d+\Z//g; |
| } |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; |
| } |
| if($SymbolInfo{$Version}{$InfoId}{"MnglName"} |
| and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) |
| { # validate mangled name |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} |
| and index($ShortName, "_Z")==0) |
| { # _ZTS, etc. |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"})) |
| { # non-public global data |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; |
| if(my $Rid = getTypeId($InfoId)) |
| { |
| if(not defined $TypeInfo{$Version}{$Rid} |
| or not $TypeInfo{$Version}{$Rid}{"Name"}) |
| { |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid; |
| my $Val = getDataVal($InfoId, $Rid); |
| if(defined $Val) { |
| $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val; |
| } |
| } |
| set_Class_And_Namespace($InfoId); |
| if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) |
| { |
| if(not defined $TypeInfo{$Version}{$ClassId} |
| or not $TypeInfo{$Version}{$ClassId}{"Name"}) |
| { |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| } |
| if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) |
| { # extern "C" |
| $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| if($UserLang and $UserLang eq "C") |
| { # --lang=C option |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| if(not $CheckHeadersOnly) |
| { |
| if(not $SymbolInfo{$Version}{$InfoId}{"Class"}) |
| { |
| if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} |
| or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) |
| { |
| if(link_symbol($ShortName, $Version, "-Deps")) |
| { # "const" global data is mangled as _ZL... in the TU dump |
| # but not mangled when compiling a C shared library |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| } |
| } |
| } |
| if($COMMON_LANGUAGE{$Version} eq "C++") |
| { |
| if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) |
| { # for some symbols (_ZTI) the short name is the mangled name |
| if(index($ShortName, "_Z")==0) { |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| } |
| if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) |
| { # try to mangle symbol (link with libraries) |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId); |
| } |
| if($OStarget eq "windows") |
| { |
| if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) |
| { # link MS C++ symbols from library with GCC symbols from headers |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; |
| } |
| } |
| } |
| if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { |
| $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; |
| } |
| if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) |
| { |
| if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) |
| { # non-target symbols |
| delete($SymbolInfo{$Version}{$InfoId}); |
| return; |
| } |
| } |
| if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) |
| { |
| if(defined $MissedTypedef{$Version}{$Rid}) |
| { |
| if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { |
| $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; |
| } |
| } |
| } |
| setFuncAccess($InfoId); |
| if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) { |
| delete($SymbolInfo{$Version}{$InfoId}{"Return"}); |
| } |
| if($ShortName=~/\A(_Z|\?)/) { |
| delete($SymbolInfo{$Version}{$InfoId}{"ShortName"}); |
| } |
| |
| if($ExtraDump) { |
| $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); |
| } |
| } |
| |
| sub isConstType($$) |
| { |
| my ($TypeId, $LibVersion) = @_; |
| my %Base = get_Type($TypeId, $LibVersion); |
| while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { |
| %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion}); |
| } |
| return ($Base{"Type"} eq "Const"); |
| } |
| |
| sub getTrivialName($$) |
| { |
| my ($TypeInfoId, $TypeId) = @_; |
| my %TypeAttr = (); |
| $TypeAttr{"Name"} = getNameByInfo($TypeInfoId); |
| if(not $TypeAttr{"Name"}) { |
| $TypeAttr{"Name"} = getTreeTypeName($TypeId); |
| } |
| ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); |
| $TypeAttr{"Type"} = getTypeType($TypeId); |
| $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name |
| if(isAnon($TypeAttr{"Name"})) |
| { |
| my $NameSpaceId = $TypeId; |
| while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId))) |
| { # searching for a first not anon scope |
| if($NSId eq $NameSpaceId) { |
| last; |
| } |
| else |
| { |
| $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId)); |
| if(not $TypeAttr{"NameSpace"} |
| or not isAnon($TypeAttr{"NameSpace"})) { |
| last; |
| } |
| } |
| $NameSpaceId = $NSId; |
| } |
| } |
| else |
| { |
| if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId)) |
| { |
| if($NameSpaceId ne $TypeId) { |
| $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId); |
| } |
| } |
| } |
| if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) { |
| $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; |
| } |
| $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); |
| if(isAnon($TypeAttr{"Name"})) |
| { # anon-struct-header.h-line |
| $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-"; |
| $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"}; |
| if($TypeAttr{"NameSpace"}) { |
| $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; |
| } |
| } |
| if(defined $TemplateInstance{$Version}{"Type"}{$TypeId} |
| and getTypeDeclId($TypeId) eq $TypeInfoId) |
| { |
| if(my @TParams = getTParams($TypeId, "Type")) { |
| $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); |
| } |
| else { |
| $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."<...>", "T"); |
| } |
| } |
| return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); |
| } |
| |
| sub getTrivialTypeAttr($) |
| { |
| my $TypeId = $_[0]; |
| my $TypeInfoId = getTypeDeclId($_[0]); |
| |
| my %TypeAttr = (); |
| |
| if($TemplateDecl{$Version}{$TypeId}) |
| { # template_decl |
| $TypeAttr{"Template"} = 1; |
| } |
| |
| setTypeAccess($TypeId, \%TypeAttr); |
| ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); |
| if(isBuiltIn($TypeAttr{"Header"})) |
| { |
| delete($TypeAttr{"Header"}); |
| delete($TypeAttr{"Line"}); |
| } |
| |
| $TypeAttr{"Type"} = getTypeType($TypeId); |
| ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId); |
| if(not $TypeAttr{"Name"}) { |
| return (); |
| } |
| if(not $TypeAttr{"NameSpace"}) { |
| delete($TypeAttr{"NameSpace"}); |
| } |
| |
| if($TypeAttr{"Type"} eq "Intrinsic") |
| { |
| if(defined $TypeAttr{"Header"}) |
| { |
| if($TypeAttr{"Header"}=~/\Adump[1-2]\.[ih]\Z/) |
| { # support for SUSE 11.2 |
| # integer_type has srcp dump{1-2}.i |
| delete($TypeAttr{"Header"}); |
| } |
| } |
| } |
| |
| my $Tmpl = undef; |
| |
| if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) |
| { |
| $Tmpl = $BasicTemplate{$Version}{$TypeId}; |
| |
| if(my @TParams = getTParams($TypeId, "Type")) |
| { |
| foreach my $Pos (0 .. $#TParams) |
| { |
| my $Val = $TParams[$Pos]; |
| $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; |
| |
| if(not defined $TypeAttr{"Template"}) |
| { |
| my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); |
| |
| if($Base{"Type"} eq "TemplateParam" |
| or defined $Base{"Template"}) { |
| $TypeAttr{"Template"} = 1; |
| } |
| } |
| |
| if($Tmpl) |
| { |
| if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) |
| { |
| $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; |
| |
| if($Val eq $Arg) { |
| $TypeAttr{"Template"} = 1; |
| } |
| } |
| } |
| } |
| |
| if($Tmpl) |
| { |
| foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) |
| { |
| if($Pos>$#TParams) |
| { |
| my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; |
| $TemplateMap{$Version}{$TypeId}{$Arg} = ""; |
| } |
| } |
| } |
| } |
| |
| if($ADD_TMPL_INSTANCES) |
| { |
| if($Tmpl) |
| { |
| if(my $MainInst = getTreeAttr_Type($Tmpl)) |
| { |
| if(not getTreeAttr_Flds($TypeId)) |
| { |
| if(my $Flds = getTreeAttr_Flds($MainInst)) { |
| $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; |
| } |
| } |
| if(not getTreeAttr_Binf($TypeId)) |
| { |
| if(my $Binf = getTreeAttr_Binf($MainInst)) { |
| $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); |
| |
| if(my $Size = getSize($TypeId)) |
| { |
| $Size = $Size/$BYTE_SIZE; |
| $TypeAttr{"Size"} = "$Size"; |
| } |
| else |
| { |
| if($ExtraDump) |
| { |
| if(not defined $TypeAttr{"Memb"} |
| and not $Tmpl) |
| { # declaration only |
| $TypeAttr{"Forward"} = 1; |
| } |
| } |
| } |
| |
| if($TypeAttr{"Type"} eq "Struct" |
| and ($StaticFields or detect_lang($TypeId))) |
| { |
| $TypeAttr{"Type"} = "Class"; |
| $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo() |
| } |
| if($TypeAttr{"Type"} eq "Struct" |
| or $TypeAttr{"Type"} eq "Class") |
| { |
| my $Skip = setBaseClasses($TypeId, \%TypeAttr); |
| if($Skip) { |
| return (); |
| } |
| } |
| if(my $Algn = getAlgn($TypeId)) { |
| $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; |
| } |
| setSpec($TypeId, \%TypeAttr); |
| |
| if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) |
| { |
| if(not $TypedefToAnon{$TypeId} |
| and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) |
| { |
| if(not isAnon($TypeAttr{"Name"})) { |
| $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; |
| } |
| } |
| } |
| |
| $TypeAttr{"Tid"} = $TypeId; |
| if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}}) |
| { |
| my @Entries = split(/\n/, $VTable); |
| foreach (1 .. $#Entries) |
| { |
| my $Entry = $Entries[$_]; |
| if($Entry=~/\A(\d+)\s+(.+)\Z/) { |
| $TypeAttr{"VTable"}{$1} = simplifyVTable($2); |
| } |
| } |
| } |
| |
| if($TypeAttr{"Type"} eq "Enum") |
| { |
| if(not $TypeAttr{"NameSpace"}) |
| { |
| foreach my $Pos (keys(%{$TypeAttr{"Memb"}})) |
| { |
| my $MName = $TypeAttr{"Memb"}{$Pos}{"name"}; |
| my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"}; |
| $EnumConstants{$Version}{$MName} = { |
| "Value"=>$MVal, |
| "Header"=>$TypeAttr{"Header"} |
| }; |
| if(isAnon($TypeAttr{"Name"})) |
| { |
| if($ExtraDump |
| or is_target_header($TypeAttr{"Header"}, $Version)) |
| { |
| %{$Constants{$Version}{$MName}} = ( |
| "Value" => $MVal, |
| "Header" => $TypeAttr{"Header"} |
| ); |
| } |
| } |
| } |
| } |
| } |
| if($ExtraDump) |
| { |
| if(defined $TypedefToAnon{$TypeId}) { |
| $TypeAttr{"AnonTypedef"} = 1; |
| } |
| } |
| |
| return %TypeAttr; |
| } |
| |
| sub simplifyVTable($) |
| { |
| my $Content = $_[0]; |
| if($Content=~s/ \[with (.+)]//) |
| { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>] |
| if(my @Elems = separate_Params($1, 0, 0)) |
| { |
| foreach my $Elem (@Elems) |
| { |
| if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) |
| { |
| my ($Arg, $Val) = ($1, $2); |
| |
| if(defined $DEFAULT_STD_ARGS{$Arg}) { |
| $Content=~s/,\s*$Arg\b//g; |
| } |
| else { |
| $Content=~s/\b$Arg\b/$Val/g; |
| } |
| } |
| } |
| } |
| } |
| |
| return $Content; |
| } |
| |
| sub detect_lang($) |
| { |
| my $TypeId = $_[0]; |
| my $Info = $LibInfo{$Version}{"info"}{$TypeId}; |
| if(check_gcc($GCC_PATH, "4")) |
| { # GCC 4 fncs-node points to only non-artificial methods |
| return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /); |
| } |
| else |
| { # GCC 3 |
| my $Fncs = getTreeAttr_Fncs($TypeId); |
| while($Fncs) |
| { |
| if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) { |
| return 1; |
| } |
| $Fncs = getTreeAttr_Chan($Fncs); |
| } |
| } |
| return 0; |
| } |
| |
| sub setSpec($$) |
| { |
| my ($TypeId, $TypeAttr) = @_; |
| my $Info = $LibInfo{$Version}{"info"}{$TypeId}; |
| if($Info=~/\s+spec\s+/) { |
| $TypeAttr->{"Spec"} = 1; |
| } |
| } |
| |
| sub setBaseClasses($$) |
| { |
| my ($TypeId, $TypeAttr) = @_; |
| my $Info = $LibInfo{$Version}{"info"}{$TypeId}; |
| if(my $Binf = getTreeAttr_Binf($TypeId)) |
| { |
| my $Info = $LibInfo{$Version}{"info"}{$Binf}; |
| my $Pos = 0; |
| while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) |
| { |
| my ($Access, $BInfoId) = ($1, $2); |
| my $ClassId = getBinfClassId($BInfoId); |
| |
| if($ClassId eq $TypeId) |
| { # class A<N>:public A<N-1> |
| next; |
| } |
| |
| my $CType = $LibInfo{$Version}{"info_type"}{$ClassId}; |
| if(not $CType or $CType eq "template_type_parm" |
| or $CType eq "typename_type") |
| { # skip |
| # return 1; |
| } |
| my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; |
| if($Access=~/prot/) { |
| $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected"; |
| } |
| elsif($Access=~/priv/) { |
| $TypeAttr->{"Base"}{$ClassId}{"access"} = "private"; |
| } |
| $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos"; |
| if($BaseInfo=~/virt/) |
| { # virtual base |
| $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1; |
| } |
| $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1; |
| $Pos += 1; |
| } |
| } |
| return 0; |
| } |
| |
| sub getBinfClassId($) |
| { |
| my $Info = $LibInfo{$Version}{"info"}{$_[0]}; |
| if($Info=~/type[ ]*:[ ]*@(\d+) /) { |
| return $1; |
| } |
| |
| return ""; |
| } |
| |
| sub unmangledFormat($$) |
| { |
| my ($Name, $LibVersion) = @_; |
| $Name = uncover_typedefs($Name, $LibVersion); |
| while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){}; |
| $Name=~s/\(\w+\)(\d)/$1/; |
| return $Name; |
| } |
| |
| sub modelUnmangled($$) |
| { |
| my ($InfoId, $Compiler) = @_; |
| if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) { |
| return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}; |
| } |
| my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; |
| if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) { |
| $PureSignature = "~".$PureSignature; |
| } |
| if(not $SymbolInfo{$Version}{$InfoId}{"Data"}) |
| { |
| my (@Params, @ParamTypes) = (); |
| if(defined $SymbolInfo{$Version}{$InfoId}{"Param"} |
| and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { |
| @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}}); |
| } |
| foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) |
| { # checking parameters |
| my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; |
| my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; |
| my %PType = get_PureType($PId, $TypeInfo{$Version}); |
| my $PTName = unmangledFormat($PType{"Name"}, $Version); |
| |
| if($PName eq "this" |
| and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") |
| { |
| next; |
| } |
| |
| $PTName=~s/\b(restrict|register)\b//g; |
| if($Compiler eq "MSVC") { |
| $PTName=~s/\blong long\b/__int64/; |
| } |
| @ParamTypes = (@ParamTypes, $PTName); |
| } |
| if(@ParamTypes) { |
| $PureSignature .= "(".join(", ", @ParamTypes).")"; |
| } |
| else |
| { |
| if($Compiler eq "MSVC") |
| { |
| $PureSignature .= "(void)"; |
| } |
| else |
| { # GCC |
| $PureSignature .= "()"; |
| } |
| } |
| $PureSignature = delete_keywords($PureSignature); |
| } |
| if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) |
| { |
| my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version); |
| $PureSignature = $ClassName."::".$PureSignature; |
| } |
| elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { |
| $PureSignature = $NS."::".$PureSignature; |
| } |
| if($SymbolInfo{$Version}{$InfoId}{"Const"}) { |
| $PureSignature .= " const"; |
| } |
| if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) { |
| $PureSignature .= " volatile"; |
| } |
| my $ShowReturn = 0; |
| if($Compiler eq "MSVC" |
| and $SymbolInfo{$Version}{$InfoId}{"Data"}) |
| { |
|