1#!/usr/bin/perl 2########################################################################### 3# ABI Compliance Checker (ABICC) 1.99.26 4# A tool for checking backward compatibility of a C/C++ library API 5# 6# Copyright (C) 2009-2011 Institute for System Programming, RAS 7# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) 8# Copyright (C) 2011-2012 ROSA Laboratory 9# Copyright (C) 2012-2016 Andrey Ponomarenko's ABI Laboratory 10# 11# Written by Andrey Ponomarenko 12# 13# PLATFORMS 14# ========= 15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian 16# 17# REQUIREMENTS 18# ============ 19# Linux 20# - G++ (3.0-4.7, 4.8.3, 4.9 or newer) 21# - GNU Binutils (readelf, c++filt, objdump) 22# - Perl 5 23# - Ctags 24# - ABI Dumper >= 0.99.15 25# 26# Mac OS X 27# - Xcode (g++, c++filt, otool, nm) 28# - Ctags 29# 30# MS Windows 31# - MinGW (3.0-4.7, 4.8.3, 4.9 or newer) 32# - MS Visual C++ (dumpbin, undname, cl) 33# - Active Perl 5 (5.8 or newer) 34# - Sigcheck v2.52 or newer 35# - GnuWin Zip and UnZip 36# - Ctags (Exuberant or Universal) 37# - Add tool locations to the PATH environment variable 38# - Run vcvars64.bat (C:\Microsoft Visual Studio 9.0\VC\bin\) 39# 40# This program is free software: you can redistribute it and/or modify 41# it under the terms of the GNU General Public License or the GNU Lesser 42# General Public License as published by the Free Software Foundation. 43# 44# This program is distributed in the hope that it will be useful, 45# but WITHOUT ANY WARRANTY; without even the implied warranty of 46# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47# GNU General Public License for more details. 48# 49# You should have received a copy of the GNU General Public License 50# and the GNU Lesser General Public License along with this program. 51# If not, see <http://www.gnu.org/licenses/>. 52########################################################################### 53use Getopt::Long; 54Getopt::Long::Configure ("posix_default", "no_ignore_case"); 55use File::Path qw(mkpath rmtree); 56use File::Temp qw(tempdir); 57use File::Copy qw(copy move); 58use Cwd qw(abs_path cwd realpath); 59use Storable qw(dclone); 60use Data::Dumper; 61use Config; 62 63my $TOOL_VERSION = "1.99.26"; 64my $ABI_DUMP_VERSION = "3.3"; 65my $XML_REPORT_VERSION = "1.2"; 66my $XML_ABI_DUMP_VERSION = "1.2"; 67my $OSgroup = get_OSgroup(); 68my $ORIG_DIR = cwd(); 69my $TMP_DIR = tempdir(CLEANUP=>1); 70my $LOCALE = "C.UTF-8"; 71 72# Internal modules 73my $MODULES_DIR = get_Modules(); 74push(@INC, get_dirname($MODULES_DIR)); 75# Rules DB 76my %RULES_PATH = ( 77 "Binary" => $MODULES_DIR."/RulesBin.xml", 78 "Source" => $MODULES_DIR."/RulesSrc.xml"); 79 80my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, 81$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps, 82$AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath, 83%RelativeDirectory, $TargetTitle, $TestDump, $LoggingPath, 84%TargetVersion, $InfoMsg, $CrossGcc, %OutputLogPath, 85$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem, 86$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc, 87$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet, 88$SkipHeadersPath, $CxxCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, 89$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, 90$SourceReportPath, $UseXML, $SortDump, $DumpFormat, 91$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, 92$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CxxIncompat, 93$SkipInternalSymbols, $SkipInternalTypes, $TargetArch, $GccOptions, 94$TypesListPath, $SkipTypesListPath, $CheckPrivateABI, $CountSymbols, $OldStyle, 95$DisableQuickEmptyReport, $SkipTypedefUncover, $MinGWCompat, $SkipUnidentified, 96$DisableConstantsCheck, $SkipAddedConstants, $SkipRemovedConstants, $TestABIDumper); 97 98my $CmdName = get_filename($0); 99my %OS_LibExt = ( 100 "dynamic" => { 101 "linux"=>"so", 102 "macos"=>"dylib", 103 "windows"=>"dll", 104 "symbian"=>"dso", 105 "default"=>"so" 106 }, 107 "static" => { 108 "linux"=>"a", 109 "windows"=>"lib", 110 "symbian"=>"lib", 111 "default"=>"a" 112 } 113); 114 115my %OS_Archive = ( 116 "windows"=>"zip", 117 "default"=>"tar.gz" 118); 119 120my %ERROR_CODE = ( 121 # Compatible verdict 122 "Compatible"=>0, 123 "Success"=>0, 124 # Incompatible verdict 125 "Incompatible"=>1, 126 # Undifferentiated error code 127 "Error"=>2, 128 # System command is not found 129 "Not_Found"=>3, 130 # Cannot access input files 131 "Access_Error"=>4, 132 # Cannot compile header files 133 "Cannot_Compile"=>5, 134 # Header compiled with errors 135 "Compile_Error"=>6, 136 # Invalid input ABI dump 137 "Invalid_Dump"=>7, 138 # Incompatible version of ABI dump 139 "Dump_Version"=>8, 140 # Cannot find a module 141 "Module_Error"=>9, 142 # Empty intersection between 143 # headers and shared objects 144 "Empty_Intersection"=>10, 145 # Empty set of symbols in headers 146 "Empty_Set"=>11 147); 148 149my %HomePage = ( 150 "Dev"=>"https://github.com/lvc/abi-compliance-checker", 151 "Wiki"=>"https://lvc.github.io/abi-compliance-checker/" 152); 153 154my $ShortUsage = "ABI Compliance Checker (ABICC) $TOOL_VERSION 155A tool for checking backward compatibility of a C/C++ library API 156Copyright (C) 2016 Andrey Ponomarenko's ABI Laboratory 157License: GNU LGPL or GNU GPL 158 159Usage: $CmdName [options] 160Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml 161 162OLD.xml and NEW.xml are XML-descriptors: 163 164 <version> 165 1.0 166 </version> 167 168 <headers> 169 /path/to/headers/ 170 </headers> 171 172 <libs> 173 /path/to/libraries/ 174 </libs> 175 176More info: $CmdName --help\n"; 177 178if($#ARGV==-1) 179{ 180 printMsg("INFO", $ShortUsage); 181 exit(0); 182} 183 184GetOptions("h|help!" => \$Help, 185 "i|info!" => \$InfoMsg, 186 "v|version!" => \$ShowVersion, 187 "dumpversion!" => \$DumpVersion, 188# general options 189 "l|lib|library=s" => \$TargetLibraryName, 190 "d1|old|o=s" => \$Descriptor{1}{"Path"}, 191 "d2|new|n=s" => \$Descriptor{2}{"Path"}, 192 "dump|dump-abi|dump_abi=s" => \$DumpAPI, 193# extra options 194 "app|application=s" => \$AppPath, 195 "static|static-libs!" => \$UseStaticLibs, 196 "gcc-path|cross-gcc=s" => \$CrossGcc, 197 "gcc-prefix|cross-prefix=s" => \$CrossPrefix, 198 "gcc-options=s" => \$GccOptions, 199 "sysroot=s" => \$SystemRoot_Opt, 200 "v1|vnum1|version1|vnum=s" => \$TargetVersion{1}, 201 "v2|vnum2|version2=s" => \$TargetVersion{2}, 202 "s|strict!" => \$StrictCompat, 203 "symbols-list=s" => \$SymbolsListPath, 204 "types-list=s" => \$TypesListPath, 205 "skip-symbols=s" => \$SkipSymbolsListPath, 206 "skip-types=s" => \$SkipTypesListPath, 207 "disable-constants-check!" => \$DisableConstantsCheck, 208 "skip-added-constants!" => \$SkipAddedConstants, 209 "skip-removed-constants!" => \$SkipRemovedConstants, 210 "headers-list=s" => \$TargetHeadersPath, 211 "skip-headers=s" => \$SkipHeadersPath, 212 "header=s" => \$TargetHeader, 213 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt, 214 "show-retval!" => \$ShowRetVal, 215 "use-dumps!" => \$UseDumps, 216 "nostdinc!" => \$NoStdInc, 217 "dump-system=s" => \$DumpSystem, 218 "sysinfo=s" => \$TargetSysInfo, 219 "cmp-systems!" => \$CmpSystems, 220 "libs-list=s" => \$TargetLibsPath, 221 "ext|extended!" => \$ExtendedCheck, 222 "q|quiet!" => \$Quiet, 223 "stdout!" => \$StdOut, 224 "report-format=s" => \$ReportFormat, 225 "dump-format=s" => \$DumpFormat, 226 "xml!" => \$UseXML, 227 "lang=s" => \$UserLang, 228 "arch=s" => \$TargetArch, 229 "binary|bin|abi!" => \$BinaryOnly, 230 "source|src|api!" => \$SourceOnly, 231 "limit-affected|affected-limit=s" => \$AffectLimit, 232 "count-symbols=s" => \$CountSymbols, 233 "old-style!" => \$OldStyle, 234# other options 235 "test!" => \$TestTool, 236 "test-dump!" => \$TestDump, 237 "test-abi-dumper!" => \$TestABIDumper, 238 "debug!" => \$Debug, 239 "cpp-compatible!" => \$CxxCompat, 240 "cxx-incompatible|cpp-incompatible!" => \$CxxIncompat, 241 "mingw-compatible!" => \$MinGWCompat, 242 "p|params=s" => \$ParamNamesPath, 243 "relpath1|relpath=s" => \$RelativeDirectory{1}, 244 "relpath2=s" => \$RelativeDirectory{2}, 245 "dump-path=s" => \$OutputDumpPath, 246 "sort!" => \$SortDump, 247 "report-path=s" => \$OutputReportPath, 248 "bin-report-path=s" => \$BinaryReportPath, 249 "src-report-path=s" => \$SourceReportPath, 250 "log-path=s" => \$LoggingPath, 251 "log1-path=s" => \$OutputLogPath{1}, 252 "log2-path=s" => \$OutputLogPath{2}, 253 "logging-mode=s" => \$LogMode, 254 "list-affected!" => \$ListAffected, 255 "title|l-full|lib-full=s" => \$TargetTitle, 256 "component=s" => \$TargetComponent_Opt, 257 "extra-info=s" => \$ExtraInfo, 258 "extra-dump!" => \$ExtraDump, 259 "force!" => \$Force, 260 "tolerance=s" => \$Tolerance, 261 "tolerant!" => \$Tolerant, 262 "skip-unidentified!" => \$SkipUnidentified, 263 "check!" => \$CheckInfo, 264 "quick!" => \$Quick, 265 "disable-quick-empty-report!" => \$DisableQuickEmptyReport, 266 "all-affected!" => \$AllAffected, 267 "skip-internal-symbols|skip-internal=s" => \$SkipInternalSymbols, 268 "skip-internal-types=s" => \$SkipInternalTypes, 269 "skip-typedef-uncover!" => \$SkipTypedefUncover, 270 "check-private-abi!" => \$CheckPrivateABI 271) or ERR_MESSAGE(); 272 273sub ERR_MESSAGE() 274{ 275 printMsg("INFO", "\n".$ShortUsage); 276 exit($ERROR_CODE{"Error"}); 277} 278 279my $LIB_TYPE = $UseStaticLibs?"static":"dynamic"; 280my $SLIB_TYPE = $LIB_TYPE; 281if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic") 282{ # show as "shared" library 283 $SLIB_TYPE = "shared"; 284} 285my $LIB_EXT = getLIB_EXT($OSgroup); 286my $AR_EXT = getAR_EXT($OSgroup); 287my $BYTE_SIZE = 8; 288my $COMMON_LOG_PATH = "logs/run.log"; 289 290my $HelpMessage=" 291NAME: 292 ABI Compliance Checker ($CmdName) 293 Check backward compatibility of a C/C++ library API 294 295DESCRIPTION: 296 ABI Compliance Checker (ABICC) is a tool for checking backward binary and 297 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks 298 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and 299 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary 300 and/or source-level compatibility: changes in calling stack, v-table changes, 301 removed symbols, renamed fields, etc. Binary incompatibility may result in 302 crashing or incorrect behavior of applications built with an old version of 303 a library if they run on a new one. Source incompatibility may result in 304 recompilation errors with a new library version. 305 306 The tool is intended for developers of software libraries and maintainers 307 of operating systems who are interested in ensuring backward compatibility, 308 i.e. allow old applications to run or to be recompiled with newer library 309 versions. 310 311 Also the tool can be used by ISVs for checking applications portability to 312 new library versions. Found issues can be taken into account when adapting 313 the application to a new library version. 314 315 This tool is free software: you can redistribute it and/or modify it 316 under the terms of the GNU LGPL or GNU GPL. 317 318USAGE: 319 $CmdName [options] 320 321EXAMPLE: 322 $CmdName -lib NAME -old OLD.xml -new NEW.xml 323 324 OLD.xml and NEW.xml are XML-descriptors: 325 326 <version> 327 1.0 328 </version> 329 330 <headers> 331 /path1/to/header(s)/ 332 /path2/to/header(s)/ 333 ... 334 </headers> 335 336 <libs> 337 /path1/to/library(ies)/ 338 /path2/to/library(ies)/ 339 ... 340 </libs> 341 342INFORMATION OPTIONS: 343 -h|-help 344 Print this help. 345 346 -i|-info 347 Print complete info. 348 349 -v|-version 350 Print version information. 351 352 -dumpversion 353 Print the tool version ($TOOL_VERSION) and don't do anything else. 354 355GENERAL OPTIONS: 356 -l|-lib|-library NAME 357 Library name (without version). 358 359 -d1|-old|-o PATH 360 Descriptor of 1st (old) library version. 361 It may be one of the following: 362 363 1. XML-descriptor (VERSION.xml file): 364 365 <version> 366 1.0 367 </version> 368 369 <headers> 370 /path1/to/header(s)/ 371 /path2/to/header(s)/ 372 ... 373 </headers> 374 375 <libs> 376 /path1/to/library(ies)/ 377 /path2/to/library(ies)/ 378 ... 379 </libs> 380 381 ... 382 383 2. ABI dump generated by -dump option 384 3. Directory with headers and/or $SLIB_TYPE libraries 385 4. Single header file 386 387 If you are using an 2-4 descriptor types then you should 388 specify version numbers with -v1 and -v2 options too. 389 390 For more information, please see: 391 http://ispras.linuxbase.org/index.php/Library_Descriptor 392 393 -d2|-new|-n PATH 394 Descriptor of 2nd (new) library version. 395 396 -dump|-dump-abi PATH 397 Create library ABI dump for the input XML descriptor. You can 398 transfer it anywhere and pass instead of the descriptor. Also 399 it can be used for debugging the tool. 400 401 Supported versions of ABI dump: 2.0<=V<=$ABI_DUMP_VERSION\n"; 402 403sub HELP_MESSAGE() { 404 printMsg("INFO", $HelpMessage." 405MORE INFO: 406 $CmdName --info\n"); 407} 408 409sub INFO_MESSAGE() 410{ 411 printMsg("INFO", "$HelpMessage 412EXTRA OPTIONS: 413 -app|-application PATH 414 This option allows to specify the application that should be checked 415 for portability to the new library version. 416 417 -static 418 Check static libraries instead of the shared ones. The <libs> section 419 of the XML-descriptor should point to static libraries location. 420 421 -gcc-path PATH 422 Path to the cross GCC compiler to use instead of the usual (host) GCC. 423 424 -gcc-prefix PREFIX 425 GCC toolchain prefix. 426 427 -gcc-options OPTS 428 Additional compiler options. 429 430 -sysroot DIR 431 Specify the alternative root directory. The tool will search for include 432 paths in the DIR/usr/include and DIR/usr/lib directories. 433 434 -v1|-version1 NUM 435 Specify 1st library version outside the descriptor. This option is needed 436 if you have preferred an alternative descriptor type (see -d1 option). 437 438 In general case you should specify it in the XML-descriptor: 439 <version> 440 VERSION 441 </version> 442 443 -v2|-version2 NUM 444 Specify 2nd library version outside the descriptor. 445 446 -vnum NUM 447 Specify the library version in the generated ABI dump. The <version> section 448 of the input XML descriptor will be overwritten in this case. 449 450 -s|-strict 451 Treat all compatibility warnings as problems. Add a number of \"Low\" 452 severity problems to the return value of the tool. 453 454 -headers-only 455 Check header files without $SLIB_TYPE libraries. It is easy to run, but may 456 provide a low quality compatibility report with false positives and 457 without detecting of added/removed symbols. 458 459 Alternatively you can write \"none\" word to the <libs> section 460 in the XML-descriptor: 461 <libs> 462 none 463 </libs> 464 465 -show-retval 466 Show the symbol's return type in the report. 467 468 -symbols-list PATH 469 This option allows to specify a file with a list of symbols (mangled 470 names in C++) that should be checked. Other symbols will not be checked. 471 472 -types-list PATH 473 This option allows to specify a file with a list of types that should 474 be checked. Other types will not be checked. 475 476 -skip-symbols PATH 477 The list of symbols that should not be checked. 478 479 -skip-types PATH 480 The list of types that should not be checked. 481 482 -disable-constants-check 483 Do not check for changes in constants. 484 485 -skip-added-constants 486 Do not detect added constants. 487 488 -skip-removed-constants 489 Do not detect removed constants. 490 491 -headers-list PATH 492 The file with a list of headers, that should be checked/dumped. 493 494 -skip-headers PATH 495 The file with the list of header files, that should not be checked. 496 497 -header NAME 498 Check/Dump ABI of this header only. 499 500 -use-dumps 501 Make dumps for two versions of a library and compare dumps. This should 502 increase the performance of the tool and decrease the system memory usage. 503 504 -nostdinc 505 Do not search in GCC standard system directories for header files. 506 507 -dump-system NAME -sysroot DIR 508 Find all the shared libraries and header files in DIR directory, 509 create XML descriptors and make ABI dumps for each library. The result 510 set of ABI dumps can be compared (--cmp-systems) with the other one 511 created for other version of operating system in order to check them for 512 compatibility. Do not forget to specify -cross-gcc option if your target 513 system requires some specific version of GCC compiler (different from 514 the host GCC). The system ABI dump will be generated to: 515 sys_dumps/NAME/ARCH 516 517 -dump-system DESCRIPTOR.xml 518 The same as the previous option but takes an XML descriptor of the target 519 system as input, where you should describe it: 520 521 /* Primary sections */ 522 523 <name> 524 /* Name of the system */ 525 </name> 526 527 <headers> 528 /* The list of paths to header files and/or 529 directories with header files, one per line */ 530 </headers> 531 532 <libs> 533 /* The list of paths to shared libraries and/or 534 directories with shared libraries, one per line */ 535 </libs> 536 537 /* Optional sections */ 538 539 <search_headers> 540 /* List of directories to be searched 541 for header files to automatically 542 generate include paths, one per line */ 543 </search_headers> 544 545 <search_libs> 546 /* List of directories to be searched 547 for shared libraries to resolve 548 dependencies, one per line */ 549 </search_libs> 550 551 <tools> 552 /* List of directories with tools used 553 for analysis (GCC toolchain), one per line */ 554 </tools> 555 556 <cross_prefix> 557 /* GCC toolchain prefix. 558 Examples: 559 arm-linux-gnueabi 560 arm-none-symbianelf */ 561 </cross_prefix> 562 563 <gcc_options> 564 /* Additional GCC options, one per line */ 565 </gcc_options> 566 567 -sysinfo DIR 568 This option should be used with -dump-system option to dump 569 ABI of operating systems and configure the dumping process. 570 571 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH 572 Compare two ABI dumps of a system. Create compatibility reports for 573 each system library and the common HTML report including the summary 574 of test results for all checked libraries. 575 576 Summary report will be generated to: 577 sys_compat_reports/NAME1_to_NAME2/ARCH 578 579 -libs-list PATH 580 The file with a list of libraries, that should be dumped by 581 the -dump-system option or should be checked by the -cmp-systems option. 582 583 -ext|-extended 584 If your library A is supposed to be used by other library B and you 585 want to control the ABI of B, then you should enable this option. The 586 tool will check for changes in all data types, even if they are not 587 used by any function in the library A. Such data types are not part 588 of the A library ABI, but may be a part of the ABI of the B library. 589 590 The short scheme is: 591 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI) 592 593 -q|-quiet 594 Print all messages to the file instead of stdout and stderr. 595 Default path (can be changed by -log-path option): 596 $COMMON_LOG_PATH 597 598 -stdout 599 Print analysis results (compatibility reports and ABI dumps) to stdout 600 instead of creating a file. This would allow piping data to other programs. 601 602 -report-format FMT 603 Change format of compatibility report. 604 Formats: 605 htm - HTML format (default) 606 xml - XML format 607 608 -dump-format FMT 609 Change format of ABI dump. 610 Formats: 611 perl - Data::Dumper format (default) 612 xml - XML format 613 614 -xml 615 Alias for: --report-format=xml or --dump-format=xml 616 617 -lang LANG 618 Set library language (C or C++). You can use this option if the tool 619 cannot auto-detect a language. This option may be useful for checking 620 C-library headers (--lang=C) in --headers-only or --extended modes. 621 622 -arch ARCH 623 Set library architecture (x86, x86_64, ia64, arm, ppc32, ppc64, s390, 624 ect.). The option is useful if the tool cannot detect correct architecture 625 of the input objects. 626 627 -binary|-bin|-abi 628 Show \"Binary\" compatibility problems only. 629 Generate report to: 630 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 631 632 -source|-src|-api 633 Show \"Source\" compatibility problems only. 634 Generate report to: 635 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 636 637 -limit-affected LIMIT 638 The maximum number of affected symbols listed under the description 639 of the changed type in the report. 640 641 -count-symbols PATH 642 Count total public symbols in the ABI dump. 643 644 -old-style 645 Generate old-style report. 646 647OTHER OPTIONS: 648 -test 649 Run internal tests. Create two binary incompatible versions of a sample 650 library and run the tool to check them for compatibility. This option 651 allows to check if the tool works correctly in the current environment. 652 653 -test-dump 654 Test ability to create, read and compare ABI dumps. 655 656 -test-abi-dumper 657 Compare ABI dumps created by the ABI Dumper tool. 658 659 -debug 660 Debugging mode. Print debug info on the screen. Save intermediate 661 analysis stages in the debug directory: 662 debug/LIB_NAME/VERSION/ 663 664 Also consider using -dump option for debugging the tool. 665 666 -cpp-compatible 667 Do nothing. 668 669 -cxx-incompatible 670 Set this option if input C header files use C++ keywords. The tool 671 will try to replace such keywords at preprocessor stage and replace 672 them back in the final TU dump. 673 674 -mingw-compatible 675 If input header files are compatible with the MinGW GCC compiler, 676 then you can tell the tool about this and speedup the analysis. 677 678 -p|-params PATH 679 Path to file with the function parameter names. It can be used 680 for improving report view if the library header files have no 681 parameter names. File format: 682 683 func1;param1;param2;param3 ... 684 func2;param1;param2;param3 ... 685 ... 686 687 -relpath PATH 688 Replace {RELPATH} macros to PATH in the XML-descriptor used 689 for dumping the library ABI (see -dump option). 690 691 -relpath1 PATH 692 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1). 693 694 -relpath2 PATH 695 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2). 696 697 -dump-path PATH 698 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump. 699 Default: 700 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT 701 702 -sort 703 Enable sorting of data in ABI dumps. 704 705 -report-path PATH 706 Path to compatibility report. 707 Default: 708 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 709 710 -bin-report-path PATH 711 Path to \"Binary\" compatibility report. 712 Default: 713 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 714 715 -src-report-path PATH 716 Path to \"Source\" compatibility report. 717 Default: 718 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 719 720 -log-path PATH 721 Log path for all messages. 722 Default: 723 logs/LIB_NAME/VERSION/log.txt 724 725 -log1-path PATH 726 Log path for 1st version of a library. 727 Default: 728 logs/LIB_NAME/V1/log.txt 729 730 -log2-path PATH 731 Log path for 2nd version of a library. 732 Default: 733 logs/LIB_NAME/V2/log.txt 734 735 -logging-mode MODE 736 Change logging mode. 737 Modes: 738 w - overwrite old logs (default) 739 a - append old logs 740 n - do not write any logs 741 742 -list-affected 743 Generate file with the list of incompatible 744 symbols beside the HTML compatibility report. 745 Use 'c++filt \@file' command from GNU binutils 746 to unmangle C++ symbols in the generated file. 747 Default names: 748 abi_affected.txt 749 src_affected.txt 750 751 -component NAME 752 The component name in the title and summary of the HTML report. 753 Default: 754 library 755 756 -title NAME 757 Change library name in the report title to NAME. By default 758 will be displayed a name specified by -l option. 759 760 -extra-info DIR 761 Dump extra info to DIR. 762 763 -extra-dump 764 Create extended ABI dump containing all symbols 765 from the translation unit. 766 767 -force 768 Try to enable this option if the tool checked not all 769 types and symbols in header files. 770 771 -tolerance LEVEL 772 Apply a set of heuristics to successfully compile input 773 header files. You can enable several tolerance levels by 774 joining them into one string (e.g. 13, 124, etc.). 775 Levels: 776 1 - skip non-Linux headers (e.g. win32_*.h, etc.) 777 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.) 778 3 - skip headers that include non-Linux headers 779 4 - skip headers included by others 780 781 -tolerant 782 Enable highest tolerance level [1234]. 783 784 -skip-unidentified 785 Skip header files in 'headers' and 'include_preamble' sections 786 of the XML descriptor that cannot be found. This is useful if 787 you are trying to use the same descriptor for different targets. 788 789 -check 790 Check completeness of the ABI dump. 791 792 -quick 793 Quick analysis. Disable check of some template instances. 794 795 -disable-quick-empty-report 796 Do not generate quick empty report if input ABI dumps are equal. 797 798 -skip-internal-symbols PATTERN 799 Do not check symbols matched by the pattern. 800 801 -skip-internal-types PATTERN 802 Do not check types matched by the pattern. 803 804 -skip-typedef-uncover 805 Do not report a problem if type is covered or 806 uncovered by typedef (useful for broken debug info). 807 808 -check-private-abi 809 Check data types from the private part of the ABI when 810 comparing ABI dumps created by the ABI Dumper tool with 811 use of the -public-headers option. 812 813 Requires ABI Dumper >= 0.99.14 814 815REPORT: 816 Compatibility report will be generated to: 817 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 818 819 Log will be generated to: 820 logs/LIB_NAME/V1/log.txt 821 logs/LIB_NAME/V2/log.txt 822 823EXIT CODES: 824 0 - Compatible. The tool has run without any errors. 825 non-zero - Incompatible or the tool has run with errors. 826 827MORE INFORMATION: 828 ".$HomePage{"Wiki"}." 829 ".$HomePage{"Dev"}."\n\n"); 830} 831 832my %Operator_Indication = ( 833 "not" => "~", 834 "assign" => "=", 835 "andassign" => "&=", 836 "orassign" => "|=", 837 "xorassign" => "^=", 838 "or" => "|", 839 "xor" => "^", 840 "addr" => "&", 841 "and" => "&", 842 "lnot" => "!", 843 "eq" => "==", 844 "ne" => "!=", 845 "lt" => "<", 846 "lshift" => "<<", 847 "lshiftassign" => "<<=", 848 "rshiftassign" => ">>=", 849 "call" => "()", 850 "mod" => "%", 851 "modassign" => "%=", 852 "subs" => "[]", 853 "land" => "&&", 854 "lor" => "||", 855 "rshift" => ">>", 856 "ref" => "->", 857 "le" => "<=", 858 "deref" => "*", 859 "mult" => "*", 860 "preinc" => "++", 861 "delete" => " delete", 862 "vecnew" => " new[]", 863 "vecdelete" => " delete[]", 864 "predec" => "--", 865 "postinc" => "++", 866 "postdec" => "--", 867 "plusassign" => "+=", 868 "plus" => "+", 869 "minus" => "-", 870 "minusassign" => "-=", 871 "gt" => ">", 872 "ge" => ">=", 873 "new" => " new", 874 "multassign" => "*=", 875 "divassign" => "/=", 876 "div" => "/", 877 "neg" => "-", 878 "pos" => "+", 879 "memref" => "->*", 880 "compound" => "," ); 881 882my %UnknownOperator; 883 884my %NodeType= ( 885 "array_type" => "Array", 886 "binfo" => "Other", 887 "boolean_type" => "Intrinsic", 888 "complex_type" => "Intrinsic", 889 "const_decl" => "Other", 890 "enumeral_type" => "Enum", 891 "field_decl" => "Other", 892 "function_decl" => "Other", 893 "function_type" => "FunctionType", 894 "identifier_node" => "Other", 895 "integer_cst" => "Other", 896 "integer_type" => "Intrinsic", 897 "vector_type" => "Vector", 898 "method_type" => "MethodType", 899 "namespace_decl" => "Other", 900 "parm_decl" => "Other", 901 "pointer_type" => "Pointer", 902 "real_cst" => "Other", 903 "real_type" => "Intrinsic", 904 "record_type" => "Struct", 905 "reference_type" => "Ref", 906 "string_cst" => "Other", 907 "template_decl" => "Other", 908 "template_type_parm" => "TemplateParam", 909 "typename_type" => "TypeName", 910 "sizeof_expr" => "SizeOf", 911 "tree_list" => "Other", 912 "tree_vec" => "Other", 913 "type_decl" => "Other", 914 "union_type" => "Union", 915 "var_decl" => "Other", 916 "void_type" => "Intrinsic", 917 "nop_expr" => "Other", # 918 "addr_expr" => "Other", # 919 "offset_type" => "Other" ); 920 921my %CppKeywords_C = map {$_=>1} ( 922 # C++ 2003 keywords 923 "public", 924 "protected", 925 "private", 926 "default", 927 "template", 928 "new", 929 #"asm", 930 "dynamic_cast", 931 "auto", 932 "try", 933 "namespace", 934 "typename", 935 "using", 936 "reinterpret_cast", 937 "friend", 938 "class", 939 "virtual", 940 "const_cast", 941 "mutable", 942 "static_cast", 943 "export", 944 # C++0x keywords 945 "noexcept", 946 "nullptr", 947 "constexpr", 948 "static_assert", 949 "explicit", 950 # cannot be used as a macro name 951 # as it is an operator in C++ 952 "and", 953 #"and_eq", 954 "not", 955 #"not_eq", 956 "or" 957 #"or_eq", 958 #"bitand", 959 #"bitor", 960 #"xor", 961 #"xor_eq", 962 #"compl" 963); 964 965my %CppKeywords_F = map {$_=>1} ( 966 "delete", 967 "catch", 968 "alignof", 969 "thread_local", 970 "decltype", 971 "typeid" 972); 973 974my %CppKeywords_O = map {$_=>1} ( 975 "bool", 976 "register", 977 "inline", 978 "operator" 979); 980 981my %CppKeywords_A = map {$_=>1} ( 982 "this", 983 "throw", 984 "template" 985); 986 987foreach (keys(%CppKeywords_C), 988keys(%CppKeywords_F), 989keys(%CppKeywords_O)) { 990 $CppKeywords_A{$_}=1; 991} 992 993# Header file extensions as described by gcc 994my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+"; 995 996my %IntrinsicMangling = ( 997 "void" => "v", 998 "bool" => "b", 999 "wchar_t" => "w", 1000 "char" => "c", 1001 "signed char" => "a", 1002 "unsigned char" => "h", 1003 "short" => "s", 1004 "unsigned short" => "t", 1005 "int" => "i", 1006 "unsigned int" => "j", 1007 "long" => "l", 1008 "unsigned long" => "m", 1009 "long long" => "x", 1010 "__int64" => "x", 1011 "unsigned long long" => "y", 1012 "__int128" => "n", 1013 "unsigned __int128" => "o", 1014 "float" => "f", 1015 "double" => "d", 1016 "long double" => "e", 1017 "__float80" => "e", 1018 "__float128" => "g", 1019 "..." => "z" 1020); 1021 1022my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); 1023 1024my %StdcxxMangling = ( 1025 "3std"=>"St", 1026 "3std9allocator"=>"Sa", 1027 "3std12basic_string"=>"Sb", 1028 "3std12basic_stringIcE"=>"Ss", 1029 "3std13basic_istreamIcE"=>"Si", 1030 "3std13basic_ostreamIcE"=>"So", 1031 "3std14basic_iostreamIcE"=>"Sd" 1032); 1033 1034my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; 1035my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); 1036 1037my $ADD_TMPL_INSTANCES = 1; 1038my $GCC_MISSED_MNGL = 0; 1039 1040my %ConstantSuffix = ( 1041 "unsigned int"=>"u", 1042 "long"=>"l", 1043 "unsigned long"=>"ul", 1044 "long long"=>"ll", 1045 "unsigned long long"=>"ull" 1046); 1047 1048my %ConstantSuffixR = 1049reverse(%ConstantSuffix); 1050 1051my %OperatorMangling = ( 1052 "~" => "co", 1053 "=" => "aS", 1054 "|" => "or", 1055 "^" => "eo", 1056 "&" => "an",#ad (addr) 1057 "==" => "eq", 1058 "!" => "nt", 1059 "!=" => "ne", 1060 "<" => "lt", 1061 "<=" => "le", 1062 "<<" => "ls", 1063 "<<=" => "lS", 1064 ">" => "gt", 1065 ">=" => "ge", 1066 ">>" => "rs", 1067 ">>=" => "rS", 1068 "()" => "cl", 1069 "%" => "rm", 1070 "[]" => "ix", 1071 "&&" => "aa", 1072 "||" => "oo", 1073 "*" => "ml",#de (deref) 1074 "++" => "pp",# 1075 "--" => "mm",# 1076 "new" => "nw", 1077 "delete" => "dl", 1078 "new[]" => "na", 1079 "delete[]" => "da", 1080 "+=" => "pL", 1081 "+" => "pl",#ps (pos) 1082 "-" => "mi",#ng (neg) 1083 "-=" => "mI", 1084 "*=" => "mL", 1085 "/=" => "dV", 1086 "&=" => "aN", 1087 "|=" => "oR", 1088 "%=" => "rM", 1089 "^=" => "eO", 1090 "/" => "dv", 1091 "->*" => "pm", 1092 "->" => "pt",#rf (ref) 1093 "," => "cm", 1094 "?" => "qu", 1095 "." => "dt", 1096 "sizeof"=> "sz"#st 1097); 1098 1099my %Intrinsic_Keywords = map {$_=>1} ( 1100 "true", 1101 "false", 1102 "_Bool", 1103 "_Complex", 1104 "const", 1105 "int", 1106 "long", 1107 "void", 1108 "short", 1109 "float", 1110 "volatile", 1111 "restrict", 1112 "unsigned", 1113 "signed", 1114 "char", 1115 "double", 1116 "class", 1117 "struct", 1118 "union", 1119 "enum" 1120); 1121 1122my %GlibcHeader = map {$_=>1} ( 1123 "aliases.h", 1124 "argp.h", 1125 "argz.h", 1126 "assert.h", 1127 "cpio.h", 1128 "ctype.h", 1129 "dirent.h", 1130 "envz.h", 1131 "errno.h", 1132 "error.h", 1133 "execinfo.h", 1134 "fcntl.h", 1135 "fstab.h", 1136 "ftw.h", 1137 "glob.h", 1138 "grp.h", 1139 "iconv.h", 1140 "ifaddrs.h", 1141 "inttypes.h", 1142 "langinfo.h", 1143 "limits.h", 1144 "link.h", 1145 "locale.h", 1146 "malloc.h", 1147 "math.h", 1148 "mntent.h", 1149 "monetary.h", 1150 "nl_types.h", 1151 "obstack.h", 1152 "printf.h", 1153 "pwd.h", 1154 "regex.h", 1155 "sched.h", 1156 "search.h", 1157 "setjmp.h", 1158 "shadow.h", 1159 "signal.h", 1160 "spawn.h", 1161 "stdarg.h", 1162 "stdint.h", 1163 "stdio.h", 1164 "stdlib.h", 1165 "string.h", 1166 "strings.h", 1167 "tar.h", 1168 "termios.h", 1169 "time.h", 1170 "ulimit.h", 1171 "unistd.h", 1172 "utime.h", 1173 "wchar.h", 1174 "wctype.h", 1175 "wordexp.h" ); 1176 1177my %GlibcDir = map {$_=>1} ( 1178 "arpa", 1179 "bits", 1180 "gnu", 1181 "netinet", 1182 "net", 1183 "nfs", 1184 "rpc", 1185 "sys", 1186 "linux" ); 1187 1188my %WinHeaders = map {$_=>1} ( 1189 "dos.h", 1190 "process.h", 1191 "winsock.h", 1192 "config-win.h", 1193 "mem.h", 1194 "windows.h", 1195 "winsock2.h", 1196 "crtdbg.h", 1197 "ws2tcpip.h" 1198); 1199 1200my %ObsoleteHeaders = map {$_=>1} ( 1201 "iostream.h", 1202 "fstream.h" 1203); 1204 1205my %AlienHeaders = map {$_=>1} ( 1206 # Solaris 1207 "thread.h", 1208 "sys/atomic.h", 1209 # HPUX 1210 "sys/stream.h", 1211 # Symbian 1212 "AknDoc.h", 1213 # Atari ST 1214 "ext.h", 1215 "tos.h", 1216 # MS-DOS 1217 "alloc.h", 1218 # Sparc 1219 "sys/atomic.h" 1220); 1221 1222my %ConfHeaders = map {$_=>1} ( 1223 "atomic", 1224 "conf.h", 1225 "config.h", 1226 "configure.h", 1227 "build.h", 1228 "setup.h" 1229); 1230 1231my %LocalIncludes = map {$_=>1} ( 1232 "/usr/local/include", 1233 "/usr/local" ); 1234 1235my %OS_AddPath=( 1236# These paths are needed if the tool cannot detect them automatically 1237 "macos"=>{ 1238 "include"=>[ 1239 "/Library", 1240 "/Developer/usr/include" 1241 ], 1242 "lib"=>[ 1243 "/Library", 1244 "/Developer/usr/lib" 1245 ], 1246 "bin"=>[ 1247 "/Developer/usr/bin" 1248 ] 1249 }, 1250 "beos"=>{ 1251 # Haiku has GCC 2.95.3 by default 1252 # try to find GCC>=3.0 in /boot/develop/abi 1253 "include"=>[ 1254 "/boot/common", 1255 "/boot/develop" 1256 ], 1257 "lib"=>[ 1258 "/boot/common/lib", 1259 "/boot/system/lib", 1260 "/boot/apps" 1261 ], 1262 "bin"=>[ 1263 "/boot/common/bin", 1264 "/boot/system/bin", 1265 "/boot/develop/abi" 1266 ] 1267 } 1268); 1269 1270my %Slash_Type=( 1271 "default"=>"/", 1272 "windows"=>"\\" 1273); 1274 1275my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"}; 1276 1277# Global Variables 1278my %COMMON_LANGUAGE=( 1279 1 => "C", 1280 2 => "C" ); 1281 1282my $MAX_COMMAND_LINE_ARGUMENTS = 4096; 1283my $MAX_CPPFILT_FILE_SIZE = 50000; 1284my $CPPFILT_SUPPORT_FILE; 1285 1286my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION, %CLANG_VERSION); 1287 1288my $STDCXX_TESTING = 0; 1289my $GLIBC_TESTING = 0; 1290my $CPP_HEADERS = 0; 1291 1292my $CheckHeadersOnly = $CheckHeadersOnly_Opt; 1293my $CheckUndefined = 0; 1294 1295my $TargetComponent = undef; 1296if($TargetComponent_Opt) { 1297 $TargetComponent = lc($TargetComponent_Opt); 1298} 1299else 1300{ # default: library 1301 # other components: header, system, ... 1302 $TargetComponent = "library"; 1303} 1304 1305my $TOP_REF = "<a class='top_ref' href='#Top'>to the top</a>"; 1306 1307my $SystemRoot; 1308 1309my $MAIN_CPP_DIR; 1310my %RESULT; 1311my %LOG_PATH; 1312my %DEBUG_PATH; 1313my %Cache; 1314my %LibInfo; 1315my $COMPILE_ERRORS = 0; 1316my %CompilerOptions; 1317my %CheckedDyLib; 1318my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup); 1319 1320# Constants (#defines) 1321my %Constants; 1322my %SkipConstants; 1323my %EnumConstants; 1324 1325# Extra Info 1326my %SymbolHeader; 1327my %KnownLibs; 1328 1329# Templates 1330my %TemplateInstance; 1331my %BasicTemplate; 1332my %TemplateArg; 1333my %TemplateDecl; 1334my %TemplateMap; 1335 1336# Types 1337my %TypeInfo; 1338my %SkipTypes = ( 1339 "1"=>{}, 1340 "2"=>{} ); 1341my %CheckedTypes; 1342my %TName_Tid; 1343my %EnumMembName_Id; 1344my %NestedNameSpaces = ( 1345 "1"=>{}, 1346 "2"=>{} ); 1347my %VirtualTable; 1348my %VirtualTable_Model; 1349my %ClassVTable; 1350my %ClassVTable_Content; 1351my %VTableClass; 1352my %AllocableClass; 1353my %ClassMethods; 1354my %ClassNames; 1355my %Class_SubClasses; 1356my %OverriddenMethods; 1357my %TypedefToAnon; 1358my $MAX_ID = 0; 1359 1360my %CheckedTypeInfo; 1361 1362# Typedefs 1363my %Typedef_BaseName; 1364my %Typedef_Tr; 1365my %Typedef_Eq; 1366my %StdCxxTypedef; 1367my %MissedTypedef; 1368my %MissedBase; 1369my %MissedBase_R; 1370my %TypeTypedef; 1371 1372# Symbols 1373my %SymbolInfo; 1374my %tr_name; 1375my %mangled_name_gcc; 1376my %mangled_name; 1377my %SkipSymbols = ( 1378 "1"=>{}, 1379 "2"=>{} ); 1380my %SkipNameSpaces = ( 1381 "1"=>{}, 1382 "2"=>{} ); 1383my %AddNameSpaces = ( 1384 "1"=>{}, 1385 "2"=>{} ); 1386my %SymbolsList; 1387my %TypesList; 1388my %SymbolsList_App; 1389my %CheckedSymbols; 1390my %Symbol_Library = ( 1391 "1"=>{}, 1392 "2"=>{} ); 1393my %Library_Symbol = ( 1394 "1"=>{}, 1395 "2"=>{} ); 1396my %DepSymbol_Library = ( 1397 "1"=>{}, 1398 "2"=>{} ); 1399my %DepLibrary_Symbol = ( 1400 "1"=>{}, 1401 "2"=>{} ); 1402my %MangledNames; 1403my %Func_ShortName; 1404my %AddIntParams; 1405my %GlobalDataObject; 1406my %WeakSymbols; 1407my %Library_Needed= ( 1408 "1"=>{}, 1409 "2"=>{} ); 1410my $DisabledMSVCUnmangling = undef; 1411 1412# Extra Info 1413my %UndefinedSymbols; 1414my %PreprocessedHeaders; 1415 1416# Headers 1417my %Include_Preamble = ( 1418 "1"=>[], 1419 "2"=>[] ); 1420my %Registered_Headers; 1421my %Registered_Sources; 1422my %HeaderName_Paths; 1423my %Header_Dependency; 1424my %Include_Neighbors; 1425my %Include_Paths = ( 1426 "1"=>[], 1427 "2"=>[] ); 1428my %INC_PATH_AUTODETECT = ( 1429 "1"=>1, 1430 "2"=>1 ); 1431my %Add_Include_Paths = ( 1432 "1"=>[], 1433 "2"=>[] ); 1434my %Skip_Include_Paths; 1435my %RegisteredDirs; 1436my %Header_ErrorRedirect; 1437my %Header_Includes; 1438my %Header_Includes_R; 1439my %Header_ShouldNotBeUsed; 1440my %RecursiveIncludes; 1441my %Header_Include_Prefix; 1442my %SkipHeaders; 1443my %SkipHeadersList=( 1444 "1"=>{}, 1445 "2"=>{} ); 1446my %SkipLibs; 1447my %Include_Order; 1448my %TUnit_NameSpaces; 1449my %TUnit_Classes; 1450my %TUnit_Funcs; 1451my %TUnit_Vars; 1452 1453my %CppMode = ( 1454 "1"=>0, 1455 "2"=>0 ); 1456my %AutoPreambleMode = ( 1457 "1"=>0, 1458 "2"=>0 ); 1459my %MinGWMode = ( 1460 "1"=>0, 1461 "2"=>0 ); 1462my %Cpp0xMode = ( 1463 "1"=>0, 1464 "2"=>0 ); 1465 1466# Shared Objects 1467my %RegisteredObjects; 1468my %RegisteredObjects_Short; 1469my %RegisteredSONAMEs; 1470my %RegisteredObject_Dirs; 1471 1472my %CheckedArch; 1473 1474# System Objects 1475my %SystemObjects; 1476my @DefaultLibPaths; 1477my %DyLib_DefaultPath; 1478 1479# System Headers 1480my %SystemHeaders; 1481my @DefaultCppPaths; 1482my @DefaultGccPaths; 1483my @DefaultIncPaths; 1484my %DefaultCppHeader; 1485my %DefaultGccHeader; 1486my @UsersIncPath; 1487 1488# Merging 1489my %CompleteSignature; 1490my $Version; 1491my %AddedInt; 1492my %RemovedInt; 1493my %AddedInt_Virt; 1494my %RemovedInt_Virt; 1495my %VirtualReplacement; 1496my %ChangedTypedef; 1497my %CompatRules; 1498my %IncompleteRules; 1499my %UnknownRules; 1500my %VTableChanged_M; 1501my %ExtendedSymbols; 1502my %ReturnedClass; 1503my %ParamClass; 1504my %SourceAlternative; 1505my %SourceAlternative_B; 1506my %SourceReplacement; 1507my $CurrentSymbol; # for debugging 1508 1509#Report 1510my %TypeChanges; 1511 1512#Speedup 1513my %TypeProblemsIndex; 1514 1515# Calling Conventions 1516my %UseConv_Real = ( 1517 1=>{ "R"=>0, "P"=>0 }, 1518 2=>{ "R"=>0, "P"=>0 } 1519); 1520 1521# ABI Dump 1522my %UsedDump; 1523 1524# Filters 1525my %TargetLibs; 1526my %TargetHeaders; 1527 1528# Format of objects 1529my $OStarget = $OSgroup; 1530my %TargetTools; 1531 1532# Recursion locks 1533my @RecurLib; 1534my @RecurTypes; 1535my @RecurTypes_Diff; 1536my @RecurInclude; 1537my @RecurConstant; 1538 1539# System 1540my %SystemPaths = ( 1541 "include"=>[], 1542 "lib"=>[], 1543 "bin"=>[] 1544); 1545my @DefaultBinPaths; 1546my $GCC_PATH; 1547 1548# Symbols versioning 1549my %SymVer = ( 1550 "1"=>{}, 1551 "2"=>{} ); 1552 1553# Problem descriptions 1554my %CompatProblems; 1555my %CompatProblems_Constants; 1556my %TotalAffected; 1557 1558# Reports 1559my $ContentID = 1; 1560my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1561my $ContentSpanStart_Affected = "<span class=\"sect_aff\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1562my $ContentSpanStart_Info = "<span class=\"sect_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1563my $ContentSpanEnd = "</span>\n"; 1564my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n"; 1565my $ContentDivEnd = "</div>\n"; 1566my $Content_Counter = 0; 1567 1568# Modes 1569my $JoinReport = 1; 1570my $DoubleReport = 0; 1571 1572my %Severity_Val=( 1573 "High"=>3, 1574 "Medium"=>2, 1575 "Low"=>1, 1576 "Safe"=>-1 1577); 1578 1579sub get_Modules() 1580{ 1581 my $TOOL_DIR = get_dirname($0); 1582 if(not $TOOL_DIR) 1583 { # patch for MS Windows 1584 $TOOL_DIR = "."; 1585 } 1586 my @SEARCH_DIRS = ( 1587 # tool's directory 1588 abs_path($TOOL_DIR), 1589 # relative path to modules 1590 abs_path($TOOL_DIR)."/../share/abi-compliance-checker", 1591 # install path 1592 'MODULES_INSTALL_PATH' 1593 ); 1594 foreach my $DIR (@SEARCH_DIRS) 1595 { 1596 if(not is_abs($DIR)) 1597 { # relative path 1598 $DIR = abs_path($TOOL_DIR)."/".$DIR; 1599 } 1600 if(-d $DIR."/modules") { 1601 return $DIR."/modules"; 1602 } 1603 } 1604 exitStatus("Module_Error", "can't find modules"); 1605} 1606 1607my %LoadedModules = (); 1608 1609sub loadModule($) 1610{ 1611 my $Name = $_[0]; 1612 if(defined $LoadedModules{$Name}) { 1613 return; 1614 } 1615 my $Path = $MODULES_DIR."/Internals/$Name.pm"; 1616 if(not -f $Path) { 1617 exitStatus("Module_Error", "can't access \'$Path\'"); 1618 } 1619 require $Path; 1620 $LoadedModules{$Name} = 1; 1621} 1622 1623sub readModule($$) 1624{ 1625 my ($Module, $Name) = @_; 1626 my $Path = $MODULES_DIR."/Internals/$Module/".$Name; 1627 if(not -f $Path) { 1628 exitStatus("Module_Error", "can't access \'$Path\'"); 1629 } 1630 return readFile($Path); 1631} 1632 1633sub showPos($) 1634{ 1635 my $Number = $_[0]; 1636 if(not $Number) { 1637 $Number = 1; 1638 } 1639 else { 1640 $Number = int($Number)+1; 1641 } 1642 if($Number>3) { 1643 return $Number."th"; 1644 } 1645 elsif($Number==1) { 1646 return "1st"; 1647 } 1648 elsif($Number==2) { 1649 return "2nd"; 1650 } 1651 elsif($Number==3) { 1652 return "3rd"; 1653 } 1654 else { 1655 return $Number; 1656 } 1657} 1658 1659sub search_Tools($) 1660{ 1661 my $Name = $_[0]; 1662 return "" if(not $Name); 1663 if(my @Paths = keys(%TargetTools)) 1664 { 1665 foreach my $Path (@Paths) 1666 { 1667 if(-f join_P($Path, $Name)) { 1668 return join_P($Path, $Name); 1669 } 1670 if($CrossPrefix) 1671 { # user-defined prefix (arm-none-symbianelf, ...) 1672 my $Candidate = join_P($Path, $CrossPrefix."-".$Name); 1673 if(-f $Candidate) { 1674 return $Candidate; 1675 } 1676 } 1677 } 1678 } 1679 else { 1680 return ""; 1681 } 1682} 1683 1684sub synch_Cmd($) 1685{ 1686 my $Name = $_[0]; 1687 if(not $GCC_PATH) 1688 { # GCC was not found yet 1689 return ""; 1690 } 1691 my $Candidate = $GCC_PATH; 1692 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) { 1693 return $Candidate; 1694 } 1695 return ""; 1696} 1697 1698sub get_CmdPath($) 1699{ 1700 my $Name = $_[0]; 1701 return "" if(not $Name); 1702 if(defined $Cache{"get_CmdPath"}{$Name}) { 1703 return $Cache{"get_CmdPath"}{$Name}; 1704 } 1705 my %BinUtils = map {$_=>1} ( 1706 "c++filt", 1707 "objdump", 1708 "readelf" 1709 ); 1710 if($BinUtils{$Name} and $GCC_PATH) 1711 { 1712 if(my $Dir = get_dirname($GCC_PATH)) { 1713 $TargetTools{$Dir}=1; 1714 } 1715 } 1716 my $Path = search_Tools($Name); 1717 if(not $Path and $OSgroup eq "windows") { 1718 $Path = search_Tools($Name.".exe"); 1719 } 1720 if(not $Path and $BinUtils{$Name}) 1721 { 1722 if($CrossPrefix) 1723 { # user-defined prefix 1724 $Path = search_Cmd($CrossPrefix."-".$Name); 1725 } 1726 } 1727 if(not $Path and $BinUtils{$Name}) 1728 { 1729 if(my $Candidate = synch_Cmd($Name)) 1730 { # synch with GCC 1731 if($Candidate=~/[\/\\]/) 1732 { # command path 1733 if(-f $Candidate) { 1734 $Path = $Candidate; 1735 } 1736 } 1737 elsif($Candidate = search_Cmd($Candidate)) 1738 { # command name 1739 $Path = $Candidate; 1740 } 1741 } 1742 } 1743 if(not $Path) { 1744 $Path = search_Cmd($Name); 1745 } 1746 if(not $Path and $OSgroup eq "windows") 1747 { # search for *.exe file 1748 $Path=search_Cmd($Name.".exe"); 1749 } 1750 if($Path=~/\s/) { 1751 $Path = "\"".$Path."\""; 1752 } 1753 return ($Cache{"get_CmdPath"}{$Name}=$Path); 1754} 1755 1756sub search_Cmd($) 1757{ 1758 my $Name = $_[0]; 1759 return "" if(not $Name); 1760 if(defined $Cache{"search_Cmd"}{$Name}) { 1761 return $Cache{"search_Cmd"}{$Name}; 1762 } 1763 if(my $DefaultPath = get_CmdPath_Default($Name)) { 1764 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath); 1765 } 1766 foreach my $Path (@{$SystemPaths{"bin"}}) 1767 { 1768 my $CmdPath = join_P($Path,$Name); 1769 if(-f $CmdPath) 1770 { 1771 if($Name=~/gcc/) { 1772 next if(not check_gcc($CmdPath, "3")); 1773 } 1774 return ($Cache{"search_Cmd"}{$Name} = $CmdPath); 1775 } 1776 } 1777 return ($Cache{"search_Cmd"}{$Name} = ""); 1778} 1779 1780sub get_CmdPath_Default($) 1781{ # search in PATH 1782 return "" if(not $_[0]); 1783 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) { 1784 return $Cache{"get_CmdPath_Default"}{$_[0]}; 1785 } 1786 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0])); 1787} 1788 1789sub get_CmdPath_Default_I($) 1790{ # search in PATH 1791 my $Name = $_[0]; 1792 if($Name=~/find/) 1793 { # special case: search for "find" utility 1794 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) { 1795 return "find"; 1796 } 1797 } 1798 elsif($Name=~/gcc/) { 1799 return check_gcc($Name, "3"); 1800 } 1801 if(checkCmd($Name)) { 1802 return $Name; 1803 } 1804 if($OSgroup eq "windows") 1805 { 1806 if(`$Name /? 2>\"$TMP_DIR/null\"`) { 1807 return $Name; 1808 } 1809 } 1810 foreach my $Path (@DefaultBinPaths) 1811 { 1812 if(-f $Path."/".$Name) { 1813 return join_P($Path, $Name); 1814 } 1815 } 1816 return ""; 1817} 1818 1819sub classifyPath($) 1820{ 1821 my $Path = $_[0]; 1822 if($Path=~/[\*\+\(\[\|]/) 1823 { # pattern 1824 return ($Path, "Pattern"); 1825 } 1826 elsif($Path=~/[\/\\]/) 1827 { # directory or relative path 1828 return (path_format($Path, $OSgroup), "Path"); 1829 } 1830 else { 1831 return ($Path, "Name"); 1832 } 1833} 1834 1835sub readDescriptor($$) 1836{ 1837 my ($LibVersion, $Content) = @_; 1838 return if(not $LibVersion); 1839 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\""; 1840 if(not $Content) { 1841 exitStatus("Error", "$DName is empty"); 1842 } 1843 if($Content!~/\</) { 1844 exitStatus("Error", "incorrect descriptor (see -d1 option)"); 1845 } 1846 $Content=~s/\/\*(.|\n)+?\*\///g; 1847 $Content=~s/<\!--(.|\n)+?-->//g; 1848 1849 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version"); 1850 if($TargetVersion{$LibVersion}) { 1851 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion}; 1852 } 1853 if(not $Descriptor{$LibVersion}{"Version"}) { 1854 exitStatus("Error", "version in the $DName is not specified (<version> section)"); 1855 } 1856 if($Content=~/{RELPATH}/) 1857 { 1858 if(my $RelDir = $RelativeDirectory{$LibVersion}) { 1859 $Content =~ s/{RELPATH}/$RelDir/g; 1860 } 1861 else 1862 { 1863 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion"; 1864 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro"); 1865 } 1866 } 1867 1868 my $DHeaders = parseTag(\$Content, "headers"); 1869 if(not $DHeaders) { 1870 exitStatus("Error", "header files in the $DName are not specified (<headers> section)"); 1871 } 1872 elsif(lc($DHeaders) ne "none") 1873 { # append the descriptor headers list 1874 if($Descriptor{$LibVersion}{"Headers"}) 1875 { # multiple descriptors 1876 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders; 1877 } 1878 else { 1879 $Descriptor{$LibVersion}{"Headers"} = $DHeaders; 1880 } 1881 foreach my $Path (split(/\s*\n\s*/, $DHeaders)) 1882 { 1883 if(not -e $Path) { 1884 exitStatus("Access_Error", "can't access \'$Path\'"); 1885 } 1886 } 1887 } 1888 1889 if(not $CheckHeadersOnly_Opt) 1890 { 1891 my $DObjects = parseTag(\$Content, "libs"); 1892 if(not $DObjects) { 1893 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)"); 1894 } 1895 elsif(lc($DObjects) ne "none") 1896 { # append the descriptor libraries list 1897 if($Descriptor{$LibVersion}{"Libs"}) 1898 { # multiple descriptors 1899 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects; 1900 } 1901 else { 1902 $Descriptor{$LibVersion}{"Libs"} .= $DObjects; 1903 } 1904 foreach my $Path (split(/\s*\n\s*/, $DObjects)) 1905 { 1906 if(not -e $Path) { 1907 exitStatus("Access_Error", "can't access \'$Path\'"); 1908 } 1909 } 1910 } 1911 } 1912 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) 1913 { 1914 if(not -d $Path) { 1915 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1916 } 1917 $Path = get_abs_path($Path); 1918 $Path = path_format($Path, $OSgroup); 1919 push_U($SystemPaths{"include"}, $Path); 1920 } 1921 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) 1922 { 1923 if(not -d $Path) { 1924 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1925 } 1926 $Path = get_abs_path($Path); 1927 $Path = path_format($Path, $OSgroup); 1928 push_U($SystemPaths{"lib"}, $Path); 1929 } 1930 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) 1931 { 1932 if(not -d $Path) { 1933 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1934 } 1935 $Path = get_abs_path($Path); 1936 $Path = path_format($Path, $OSgroup); 1937 push_U($SystemPaths{"bin"}, $Path); 1938 $TargetTools{$Path}=1; 1939 } 1940 if(my $Prefix = parseTag(\$Content, "cross_prefix")) { 1941 $CrossPrefix = $Prefix; 1942 } 1943 $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //= 1944 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) 1945 { 1946 if(not -d $Path) { 1947 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1948 } 1949 $Path = get_abs_path($Path); 1950 $Path = path_format($Path, $OSgroup); 1951 push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path); 1952 } 1953 $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"}); 1954 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) 1955 { 1956 if(not -d $Path) { 1957 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1958 } 1959 $Path = get_abs_path($Path); 1960 $Path = path_format($Path, $OSgroup); 1961 push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path); 1962 } 1963 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) 1964 { # skip some auto-generated include paths 1965 if(not is_abs($Path)) 1966 { 1967 if(my $P = abs_path($Path)) { 1968 $Path = $P; 1969 } 1970 } 1971 $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1; 1972 } 1973 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) 1974 { # skip direct including of some headers 1975 my ($CPath, $Type) = classifyPath($Path); 1976 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2; 1977 } 1978 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options"); 1979 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) 1980 { 1981 if($Option!~/\A\-(Wl|l|L)/) 1982 { # skip linker options 1983 $CompilerOptions{$LibVersion} .= " ".$Option; 1984 } 1985 } 1986 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers"); 1987 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"})) 1988 { 1989 $SkipHeadersList{$LibVersion}{$Path} = 1; 1990 1991 my ($CPath, $Type) = classifyPath($Path); 1992 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1; 1993 } 1994 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs"); 1995 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"})) 1996 { 1997 my ($CPath, $Type) = classifyPath($Path); 1998 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1; 1999 } 2000 if(my $DDefines = parseTag(\$Content, "defines")) 2001 { 2002 if($Descriptor{$LibVersion}{"Defines"}) 2003 { # multiple descriptors 2004 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines; 2005 } 2006 else { 2007 $Descriptor{$LibVersion}{"Defines"} = $DDefines; 2008 } 2009 } 2010 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) 2011 { 2012 if($Order=~/\A(.+):(.+)\Z/) { 2013 $Include_Order{$LibVersion}{$1} = $2; 2014 } 2015 } 2016 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), 2017 split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) 2018 { # opaque_types renamed to skip_types (1.23.4) 2019 $SkipTypes{$LibVersion}{$Type_Name} = 1; 2020 } 2021 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), 2022 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) 2023 { # skip_interfaces renamed to skip_symbols (1.22.1) 2024 $SkipSymbols{$LibVersion}{$Symbol} = 1; 2025 } 2026 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { 2027 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1; 2028 } 2029 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { 2030 $AddNameSpaces{$LibVersion}{$NameSpace} = 1; 2031 } 2032 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { 2033 $SkipConstants{$LibVersion}{$Constant} = 1; 2034 } 2035 if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) 2036 { 2037 if($Descriptor{$LibVersion}{"IncludePreamble"}) 2038 { # multiple descriptors 2039 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble; 2040 } 2041 else { 2042 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble; 2043 } 2044 } 2045} 2046 2047sub parseTag(@) 2048{ 2049 my $CodeRef = shift(@_); 2050 my $Tag = shift(@_); 2051 if(not $Tag or not $CodeRef) { 2052 return undef; 2053 } 2054 my $Sp = 0; 2055 if(@_) { 2056 $Sp = shift(@_); 2057 } 2058 my $Start = index(${$CodeRef}, "<$Tag>"); 2059 if($Start!=-1) 2060 { 2061 my $End = index(${$CodeRef}, "</$Tag>"); 2062 if($End!=-1) 2063 { 2064 my $TS = length($Tag)+3; 2065 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, ""); 2066 substr($Content, 0, $TS-1, ""); # cut start tag 2067 substr($Content, -$TS, $TS, ""); # cut end tag 2068 if(not $Sp) 2069 { 2070 $Content=~s/\A\s+//g; 2071 $Content=~s/\s+\Z//g; 2072 } 2073 if(substr($Content, 0, 1) ne "<") { 2074 $Content = xmlSpecChars_R($Content); 2075 } 2076 return $Content; 2077 } 2078 } 2079 return undef; 2080} 2081 2082sub getInfo($) 2083{ 2084 my $DumpPath = $_[0]; 2085 return if(not $DumpPath or not -f $DumpPath); 2086 2087 readTUDump($DumpPath); 2088 2089 # processing info 2090 setTemplateParams_All(); 2091 2092 if($ExtraDump) { 2093 setAnonTypedef_All(); 2094 } 2095 2096 getTypeInfo_All(); 2097 simplifyNames(); 2098 simplifyConstants(); 2099 getVarInfo_All(); 2100 getSymbolInfo_All(); 2101 2102 # clean memory 2103 %LibInfo = (); 2104 %TemplateInstance = (); 2105 %BasicTemplate = (); 2106 %MangledNames = (); 2107 %TemplateDecl = (); 2108 %StdCxxTypedef = (); 2109 %MissedTypedef = (); 2110 %Typedef_Tr = (); 2111 %Typedef_Eq = (); 2112 %TypedefToAnon = (); 2113 2114 # clean cache 2115 delete($Cache{"getTypeAttr"}); 2116 delete($Cache{"getTypeDeclId"}); 2117 2118 if($ExtraDump) 2119 { 2120 remove_Unused($Version, "Extra"); 2121 } 2122 else 2123 { # remove unused types 2124 if($BinaryOnly and not $ExtendedCheck) 2125 { # --binary 2126 remove_Unused($Version, "All"); 2127 } 2128 else { 2129 remove_Unused($Version, "Extended"); 2130 } 2131 } 2132 2133 if($CheckInfo) 2134 { 2135 foreach my $Tid (keys(%{$TypeInfo{$Version}})) { 2136 check_Completeness($TypeInfo{$Version}{$Tid}, $Version); 2137 } 2138 2139 foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { 2140 check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); 2141 } 2142 } 2143 2144 if($Debug) { 2145 # debugMangling($Version); 2146 } 2147} 2148 2149sub readTUDump($) 2150{ 2151 my $DumpPath = $_[0]; 2152 2153 open(TU_DUMP, $DumpPath); 2154 local $/ = undef; 2155 my $Content = <TU_DUMP>; 2156 close(TU_DUMP); 2157 2158 unlink($DumpPath); 2159 2160 $Content=~s/\n[ ]+/ /g; 2161 my @Lines = split(/\n/, $Content); 2162 2163 # clean memory 2164 undef $Content; 2165 2166 $MAX_ID = $#Lines+1; # number of lines == number of nodes 2167 2168 foreach (0 .. $#Lines) 2169 { 2170 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i) 2171 { # get a number and attributes of a node 2172 next if(not $NodeType{$2}); 2173 $LibInfo{$Version}{"info_type"}{$1}=$2; 2174 $LibInfo{$Version}{"info"}{$1}=$3." "; 2175 } 2176 2177 # clean memory 2178 delete($Lines[$_]); 2179 } 2180 2181 # clean memory 2182 undef @Lines; 2183} 2184 2185sub simplifyConstants() 2186{ 2187 foreach my $Constant (keys(%{$Constants{$Version}})) 2188 { 2189 if(defined $Constants{$Version}{$Constant}{"Header"}) 2190 { 2191 my $Value = $Constants{$Version}{$Constant}{"Value"}; 2192 if(defined $EnumConstants{$Version}{$Value}) { 2193 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"}; 2194 } 2195 } 2196 } 2197} 2198 2199sub simplifyNames() 2200{ 2201 foreach my $Base (keys(%{$Typedef_Tr{$Version}})) 2202 { 2203 if($Typedef_Eq{$Version}{$Base}) { 2204 next; 2205 } 2206 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}}); 2207 if($#Translations==0) 2208 { 2209 if(length($Translations[0])<=length($Base)) { 2210 $Typedef_Eq{$Version}{$Base} = $Translations[0]; 2211 } 2212 } 2213 else 2214 { # select most appropriate 2215 foreach my $Tr (@Translations) 2216 { 2217 if($Base=~/\A\Q$Tr\E/) 2218 { 2219 $Typedef_Eq{$Version}{$Base} = $Tr; 2220 last; 2221 } 2222 } 2223 } 2224 } 2225 foreach my $TypeId (keys(%{$TypeInfo{$Version}})) 2226 { 2227 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2228 if(not $TypeName) { 2229 next; 2230 } 2231 next if(index($TypeName,"<")==-1);# template instances only 2232 if($TypeName=~/>(::\w+)+\Z/) 2233 { # skip unused types 2234 next; 2235 } 2236 foreach my $Base (sort {length($b)<=>length($a)} 2237 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}})) 2238 { 2239 next if(not $Base); 2240 next if(index($TypeName,$Base)==-1); 2241 next if(length($TypeName) - length($Base) <= 3); 2242 if(my $Typedef = $Typedef_Eq{$Version}{$Base}) 2243 { 2244 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g; 2245 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g; 2246 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"}) 2247 { 2248 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}})) 2249 { 2250 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"}) 2251 { 2252 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g; 2253 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g; 2254 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T"); 2255 } 2256 } 2257 } 2258 } 2259 } 2260 $TypeName = formatName($TypeName, "T"); 2261 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName; 2262 $TName_Tid{$Version}{$TypeName} = $TypeId; 2263 } 2264} 2265 2266sub setAnonTypedef_All() 2267{ 2268 foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}})) 2269 { 2270 if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl") 2271 { 2272 if(isAnon(getNameByInfo($InfoId))) { 2273 $TypedefToAnon{getTypeId($InfoId)} = 1; 2274 } 2275 } 2276 } 2277} 2278 2279sub setTemplateParams_All() 2280{ 2281 foreach (keys(%{$LibInfo{$Version}{"info"}})) 2282 { 2283 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") { 2284 setTemplateParams($_); 2285 } 2286 } 2287} 2288 2289sub setTemplateParams($) 2290{ 2291 my $Tid = getTypeId($_[0]); 2292 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2293 { 2294 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) 2295 { 2296 my $TmplInst_Id = $2; 2297 setTemplateInstParams($_[0], $TmplInst_Id); 2298 while($TmplInst_Id = getNextElem($TmplInst_Id)) { 2299 setTemplateInstParams($_[0], $TmplInst_Id); 2300 } 2301 } 2302 2303 $BasicTemplate{$Version}{$Tid} = $_[0]; 2304 2305 if(my $Prms = getTreeAttr_Prms($_[0])) 2306 { 2307 if(my $Valu = getTreeAttr_Valu($Prms)) 2308 { 2309 my $Vector = getTreeVec($Valu); 2310 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) 2311 { 2312 if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) 2313 { 2314 if(my $Name = getNameByInfo($Val)) 2315 { 2316 $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; 2317 if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { 2318 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; 2319 } 2320 else { 2321 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); 2322 } 2323 } 2324 } 2325 } 2326 } 2327 } 2328 } 2329 if(my $TypeId = getTreeAttr_Type($_[0])) 2330 { 2331 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) 2332 { 2333 if($IType eq "record_type") { 2334 $TemplateDecl{$Version}{$TypeId} = 1; 2335 } 2336 } 2337 } 2338} 2339 2340sub setTemplateInstParams($$) 2341{ 2342 my ($Tmpl, $Inst) = @_; 2343 2344 if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) 2345 { 2346 my ($Params_InfoId, $ElemId) = (); 2347 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 2348 $Params_InfoId = $1; 2349 } 2350 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 2351 $ElemId = $1; 2352 } 2353 if($Params_InfoId and $ElemId) 2354 { 2355 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId}; 2356 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 2357 { 2358 my ($PPos, $PTypeId) = ($1, $2); 2359 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) 2360 { 2361 if($PType eq "template_type_parm") { 2362 $TemplateDecl{$Version}{$ElemId} = 1; 2363 } 2364 } 2365 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") 2366 { # functions 2367 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; 2368 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2369 } 2370 else 2371 { # types 2372 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; 2373 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2374 } 2375 } 2376 } 2377 } 2378} 2379 2380sub getTypeDeclId($) 2381{ 2382 if($_[0]) 2383 { 2384 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) { 2385 return $Cache{"getTypeDeclId"}{$Version}{$_[0]}; 2386 } 2387 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2388 { 2389 if($Info=~/name[ ]*:[ ]*@(\d+)/) { 2390 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1); 2391 } 2392 } 2393 } 2394 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0); 2395} 2396 2397sub getTypeInfo_All() 2398{ 2399 if(not check_gcc($GCC_PATH, "4.5")) 2400 { # support for GCC < 4.5 2401 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag> 2402 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump 2403 # FIXME: check GCC versions 2404 addMissedTypes_Pre(); 2405 } 2406 2407 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2408 { # forward order only 2409 my $IType = $LibInfo{$Version}{"info_type"}{$_}; 2410 if($IType=~/_type\Z/ and $IType ne "function_type" 2411 and $IType ne "method_type") { 2412 getTypeInfo("$_"); 2413 } 2414 } 2415 2416 # add "..." type 2417 $TypeInfo{$Version}{"-1"} = { 2418 "Name" => "...", 2419 "Type" => "Intrinsic", 2420 "Tid" => "-1" 2421 }; 2422 $TName_Tid{$Version}{"..."} = "-1"; 2423 2424 if(not check_gcc($GCC_PATH, "4.5")) 2425 { # support for GCC < 4.5 2426 addMissedTypes_Post(); 2427 } 2428 2429 if($ADD_TMPL_INSTANCES) 2430 { 2431 # templates 2432 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) 2433 { 2434 if(defined $TemplateMap{$Version}{$Tid} 2435 and not defined $TypeInfo{$Version}{$Tid}{"Template"}) 2436 { 2437 if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) 2438 { 2439 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) 2440 { 2441 if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) 2442 { 2443 if(my %MAttr = getTypeAttr($MembTypeId)) 2444 { 2445 $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; 2446 $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); 2447 } 2448 } 2449 } 2450 } 2451 if(defined $TypeInfo{$Version}{$Tid}{"Base"}) 2452 { 2453 foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) 2454 { 2455 my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); 2456 2457 if($NBid ne $Bid 2458 and $NBid ne $Tid) 2459 { 2460 %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; 2461 delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); 2462 } 2463 } 2464 } 2465 } 2466 } 2467 } 2468} 2469 2470sub createType($$) 2471{ 2472 my ($Attr, $LibVersion) = @_; 2473 my $NewId = ++$MAX_ID; 2474 2475 $Attr->{"Tid"} = $NewId; 2476 $TypeInfo{$Version}{$NewId} = $Attr; 2477 $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; 2478 2479 return "$NewId"; 2480} 2481 2482sub instType($$$) 2483{ # create template instances 2484 my ($Map, $Tid, $LibVersion) = @_; 2485 2486 if(not $TypeInfo{$LibVersion}{$Tid}) { 2487 return undef; 2488 } 2489 my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); 2490 2491 foreach my $Key (sort keys(%{$Map})) 2492 { 2493 if(my $Val = $Map->{$Key}) 2494 { 2495 $Attr->{"Name"}=~s/\b$Key\b/$Val/g; 2496 2497 if(defined $Attr->{"NameSpace"}) { 2498 $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; 2499 } 2500 foreach (keys(%{$Attr->{"TParam"}})) { 2501 $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; 2502 } 2503 } 2504 else 2505 { # remove absent 2506 # _Traits, etc. 2507 $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; 2508 if(defined $Attr->{"NameSpace"}) { 2509 $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; 2510 } 2511 foreach (keys(%{$Attr->{"TParam"}})) 2512 { 2513 if($Attr->{"TParam"}{$_}{"name"} eq $Key) { 2514 delete($Attr->{"TParam"}{$_}); 2515 } 2516 else { 2517 $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; 2518 } 2519 } 2520 } 2521 } 2522 2523 my $Tmpl = 0; 2524 2525 if(defined $Attr->{"TParam"}) 2526 { 2527 foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) 2528 { 2529 my $PName = $Attr->{"TParam"}{$_}{"name"}; 2530 2531 if(my $PTid = $TName_Tid{$LibVersion}{$PName}) 2532 { 2533 my %Base = get_BaseType($PTid, $LibVersion); 2534 2535 if($Base{"Type"} eq "TemplateParam" 2536 or defined $Base{"Template"}) 2537 { 2538 $Tmpl = 1; 2539 last 2540 } 2541 } 2542 } 2543 } 2544 2545 if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { 2546 return "$Id"; 2547 } 2548 else 2549 { 2550 if(not $Tmpl) { 2551 delete($Attr->{"Template"}); 2552 } 2553 2554 my $New = createType($Attr, $LibVersion); 2555 2556 my %EMap = (); 2557 if(defined $TemplateMap{$LibVersion}{$Tid}) { 2558 %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; 2559 } 2560 foreach (keys(%{$Map})) { 2561 $EMap{$_} = $Map->{$_}; 2562 } 2563 2564 if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { 2565 $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); 2566 } 2567 if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) 2568 { 2569 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) 2570 { 2571 my $NBid = instType(\%EMap, $Bid, $LibVersion); 2572 2573 if($NBid ne $Bid 2574 and $NBid ne $New) 2575 { 2576 %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; 2577 delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); 2578 } 2579 } 2580 } 2581 2582 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) 2583 { 2584 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) 2585 { 2586 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { 2587 $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); 2588 } 2589 } 2590 } 2591 2592 if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) 2593 { 2594 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { 2595 $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); 2596 } 2597 } 2598 2599 if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { 2600 $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); 2601 } 2602 2603 return $New; 2604 } 2605} 2606 2607sub addMissedTypes_Pre() 2608{ 2609 my %MissedTypes = (); 2610 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2611 { # detecting missed typedefs 2612 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl") 2613 { 2614 my $TypeId = getTreeAttr_Type($MissedTDid); 2615 next if(not $TypeId); 2616 my $TypeType = getTypeType($TypeId); 2617 if($TypeType eq "Unknown") 2618 { # template_type_parm 2619 next; 2620 } 2621 my $TypeDeclId = getTypeDeclId($TypeId); 2622 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId 2623 my $TypedefName = getNameByInfo($MissedTDid); 2624 next if(not $TypedefName); 2625 next if($TypedefName eq "__float80"); 2626 next if(isAnon($TypedefName)); 2627 if(not $TypeDeclId 2628 or getNameByInfo($TypeDeclId) ne $TypedefName) { 2629 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1; 2630 } 2631 } 2632 } 2633 my %AddTypes = (); 2634 foreach my $Tid (keys(%{$MissedTypes{$Version}})) 2635 { # add missed typedefs 2636 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}}); 2637 if(not @Missed or $#Missed>=1) { 2638 next; 2639 } 2640 my $MissedTDid = $Missed[0]; 2641 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid); 2642 if(not $TypedefName) { 2643 next; 2644 } 2645 my $NewId = ++$MAX_ID; 2646 my %MissedInfo = ( # typedef info 2647 "Name" => $TypedefName, 2648 "NameSpace" => $TypedefNS, 2649 "BaseType" => $Tid, 2650 "Type" => "Typedef", 2651 "Tid" => "$NewId" ); 2652 my ($H, $L) = getLocation($MissedTDid); 2653 $MissedInfo{"Header"} = $H; 2654 $MissedInfo{"Line"} = $L; 2655 if($TypedefName=~/\*|\&|\s/) 2656 { # other types 2657 next; 2658 } 2659 if($TypedefName=~/>(::\w+)+\Z/) 2660 { # QFlags<Qt::DropAction>::enum_type 2661 next; 2662 } 2663 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) 2664 { # double-check for the name of typedef 2665 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info 2666 next if(not $TName); 2667 if(length($TypedefName)>=length($TName)) 2668 { # too long typedef 2669 next; 2670 } 2671 if($TName=~/\A\Q$TypedefName\E</) { 2672 next; 2673 } 2674 if($TypedefName=~/\A\Q$TName\E/) 2675 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type 2676 next; 2677 } 2678 if(get_depth($TypedefName)==0 and get_depth($TName)!=0) 2679 { # std::_Vector_base and std::vector::_Base 2680 next; 2681 } 2682 } 2683 2684 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo; 2685 2686 # register typedef 2687 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"}; 2688 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid; 2689 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"}; 2690 } 2691 2692 # add missed & remove other 2693 $TypeInfo{$Version} = \%AddTypes; 2694 delete($Cache{"getTypeAttr"}{$Version}); 2695} 2696 2697sub addMissedTypes_Post() 2698{ 2699 foreach my $BaseId (keys(%{$MissedTypedef{$Version}})) 2700 { 2701 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"}) 2702 { 2703 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"}; 2704 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) { 2705 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"}; 2706 } 2707 } 2708 } 2709} 2710 2711sub getTypeInfo($) 2712{ 2713 my $TypeId = $_[0]; 2714 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId); 2715 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2716 if(not $TName) { 2717 delete($TypeInfo{$Version}{$TypeId}); 2718 } 2719} 2720 2721sub getArraySize($$) 2722{ 2723 my ($TypeId, $BaseName) = @_; 2724 if(my $Size = getSize($TypeId)) 2725 { 2726 my $Elems = $Size/$BYTE_SIZE; 2727 while($BaseName=~s/\s*\[(\d+)\]//) { 2728 $Elems/=$1; 2729 } 2730 if(my $BasicId = $TName_Tid{$Version}{$BaseName}) 2731 { 2732 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) { 2733 $Elems/=$BasicSize; 2734 } 2735 } 2736 return $Elems; 2737 } 2738 return 0; 2739} 2740 2741sub getTParams($$) 2742{ 2743 my ($TypeId, $Kind) = @_; 2744 my @TmplParams = (); 2745 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}}); 2746 foreach my $Pos (@Positions) 2747 { 2748 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos}; 2749 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId}; 2750 if(not $NodeType) 2751 { # typename_type 2752 return (); 2753 } 2754 if($NodeType eq "tree_vec") 2755 { 2756 if($Pos!=$#Positions) 2757 { # select last vector of parameters ( ns<P1>::type<P2> ) 2758 next; 2759 } 2760 } 2761 my @Params = get_TemplateParam($Pos, $Param_TypeId); 2762 foreach my $P (@Params) 2763 { 2764 if($P eq "") { 2765 return (); 2766 } 2767 elsif($P ne "\@skip\@") { 2768 @TmplParams = (@TmplParams, $P); 2769 } 2770 } 2771 } 2772 return @TmplParams; 2773} 2774 2775sub getTypeAttr($) 2776{ 2777 my $TypeId = $_[0]; 2778 my %TypeAttr = (); 2779 if(defined $TypeInfo{$Version}{$TypeId} 2780 and $TypeInfo{$Version}{$TypeId}{"Name"}) 2781 { # already created 2782 return %{$TypeInfo{$Version}{$TypeId}}; 2783 } 2784 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId}) 2785 { # incomplete type 2786 return (); 2787 } 2788 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1; 2789 2790 my $TypeDeclId = getTypeDeclId($TypeId); 2791 $TypeAttr{"Tid"} = $TypeId; 2792 2793 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId)) 2794 { 2795 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 2796 { 2797 if($Info=~/qual[ ]*:/) 2798 { 2799 my $NewId = ++$MAX_ID; 2800 2801 $MissedBase{$Version}{$TypeId} = "$NewId"; 2802 $MissedBase_R{$Version}{$NewId} = $TypeId; 2803 $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; 2804 $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; 2805 } 2806 } 2807 $TypeAttr{"Type"} = "Typedef"; 2808 } 2809 else { 2810 $TypeAttr{"Type"} = getTypeType($TypeId); 2811 } 2812 2813 if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) 2814 { 2815 if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") 2816 { # local code 2817 return (); 2818 } 2819 } 2820 2821 if($TypeAttr{"Type"} eq "Unknown") { 2822 return (); 2823 } 2824 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/) 2825 { 2826 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"}); 2827 if(my $TName = $TypeAttr{"Name"}) 2828 { 2829 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2830 $TName_Tid{$Version}{$TName} = $TypeId; 2831 return %TypeAttr; 2832 } 2833 else { 2834 return (); 2835 } 2836 } 2837 elsif($TypeAttr{"Type"} eq "Array") 2838 { 2839 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2840 if(not $BTid) { 2841 return (); 2842 } 2843 if(my $Algn = getAlgn($TypeId)) { 2844 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 2845 } 2846 $TypeAttr{"BaseType"} = $BTid; 2847 if(my %BTAttr = getTypeAttr($BTid)) 2848 { 2849 if(not $BTAttr{"Name"}) { 2850 return (); 2851 } 2852 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"})) 2853 { 2854 if(my $Size = getSize($TypeId)) { 2855 $TypeAttr{"Size"} = $Size/$BYTE_SIZE; 2856 } 2857 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2858 $TypeAttr{"Name"} = $1."[$NElems]".$2; 2859 } 2860 else { 2861 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]"; 2862 } 2863 } 2864 else 2865 { 2866 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer 2867 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2868 $TypeAttr{"Name"} = $1."[]".$2; 2869 } 2870 else { 2871 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]"; 2872 } 2873 } 2874 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 2875 if($BTAttr{"Header"}) { 2876 $TypeAttr{"Header"} = $BTAttr{"Header"}; 2877 } 2878 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2879 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2880 return %TypeAttr; 2881 } 2882 return (); 2883 } 2884 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) 2885 { 2886 %TypeAttr = getTrivialTypeAttr($TypeId); 2887 if($TypeAttr{"Name"}) 2888 { 2889 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2890 2891 if(not defined $IntrinsicNames{$TypeAttr{"Name"}} 2892 or getTypeDeclId($TypeAttr{"Tid"})) 2893 { # NOTE: register only one int: with built-in decl 2894 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2895 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2896 } 2897 } 2898 return %TypeAttr; 2899 } 2900 else { 2901 return (); 2902 } 2903 } 2904 elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) 2905 { 2906 %TypeAttr = getTrivialTypeAttr($TypeId); 2907 if($TypeAttr{"Name"}) 2908 { 2909 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2910 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2911 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2912 } 2913 return %TypeAttr; 2914 } 2915 else { 2916 return (); 2917 } 2918 } 2919 elsif($TypeAttr{"Type"} eq "SizeOf") 2920 { 2921 $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); 2922 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2923 $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; 2924 if($TypeAttr{"Name"}) 2925 { 2926 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2927 return %TypeAttr; 2928 } 2929 else { 2930 return (); 2931 } 2932 } 2933 else 2934 { # derived types 2935 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2936 if(not $BTid) { 2937 return (); 2938 } 2939 $TypeAttr{"BaseType"} = $BTid; 2940 if(defined $MissedTypedef{$Version}{$BTid}) 2941 { 2942 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"}) 2943 { 2944 if($MissedTDid ne $TypeDeclId) { 2945 $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"}; 2946 } 2947 } 2948 } 2949 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2950 if(not $BTAttr{"Name"}) 2951 { # templates 2952 return (); 2953 } 2954 if($BTAttr{"Type"} eq "Typedef") 2955 { # relinking typedefs 2956 my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version); 2957 if($BTAttr{"Name"} eq $BaseBase{"Name"}) { 2958 $TypeAttr{"BaseType"} = $BaseBase{"Tid"}; 2959 } 2960 } 2961 if($BTSpec) 2962 { 2963 if($TypeAttr{"Type"} eq "Pointer" 2964 and $BTAttr{"Name"}=~/\([\*]+\)/) 2965 { 2966 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2967 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g; 2968 } 2969 else { 2970 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec; 2971 } 2972 } 2973 else { 2974 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2975 } 2976 if($TypeAttr{"Type"} eq "Typedef") 2977 { 2978 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId); 2979 2980 if(index($TypeAttr{"Name"}, "tmp_add_type")==0) { 2981 return (); 2982 } 2983 2984 if(isAnon($TypeAttr{"Name"})) 2985 { # anon typedef to anon type: ._N 2986 return (); 2987 } 2988 2989 if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i) 2990 { # artificial typedef of "struct X" to "X" 2991 $TypeAttr{"Artificial"} = 1; 2992 } 2993 2994 if(my $NS = getNameSpace($TypeDeclId)) 2995 { 2996 my $TypeName = $TypeAttr{"Name"}; 2997 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/) 2998 { # "some_type" is the typedef to "struct some_type" in C++ 2999 if($3) { 3000 $TypeAttr{"Name"} = $3."::".$TypeName; 3001 } 3002 } 3003 else 3004 { 3005 $TypeAttr{"NameSpace"} = $NS; 3006 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3007 3008 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ 3009 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/) 3010 { 3011 if($BTAttr{"NameSpace"} 3012 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</) 3013 { # types like "std::fpos<__mbstate_t>" are 3014 # not covered by typedefs in the TU dump 3015 # so trying to add such typedefs manually 3016 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 3017 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"})) 3018 { 3019 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) 3020 { # skip "other" in "std" and "type" in "boost" 3021 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"}; 3022 } 3023 } 3024 } 3025 } 3026 } 3027 } 3028 if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"} 3029 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/) 3030 { 3031 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}}) 3032 { # typedef int*const TYPEDEF; // first 3033 # int foo(TYPEDEF p); // const is optimized out 3034 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"}; 3035 if($BTAttr{"Name"}=~/</) 3036 { 3037 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) { 3038 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 3039 } 3040 } 3041 } 3042 } 3043 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId); 3044 } 3045 if(not $TypeAttr{"Size"}) 3046 { 3047 if($TypeAttr{"Type"} eq "Pointer") { 3048 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; 3049 } 3050 elsif($BTAttr{"Size"}) { 3051 $TypeAttr{"Size"} = $BTAttr{"Size"}; 3052 } 3053 } 3054 if(my $Algn = getAlgn($TypeId)) { 3055 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3056 } 3057 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3058 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) { 3059 $TypeAttr{"Header"} = $BTAttr{"Header"}; 3060 } 3061 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 3062 if($TypeAttr{"Name"} ne $BTAttr{"Name"}) 3063 { # typedef to "class Class" 3064 # should not be registered in TName_Tid 3065 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 3066 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 3067 } 3068 } 3069 return %TypeAttr; 3070 } 3071} 3072 3073sub getTreeVec($) 3074{ 3075 my %Vector = (); 3076 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3077 { 3078 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 3079 { # string length is N-1 because of the null terminator 3080 $Vector{$1} = $2; 3081 } 3082 } 3083 return \%Vector; 3084} 3085 3086sub get_TemplateParam($$) 3087{ 3088 my ($Pos, $Type_Id) = @_; 3089 return () if(not $Type_Id); 3090 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id}; 3091 return () if(not $NodeType); 3092 if($NodeType eq "integer_cst") 3093 { # int (1), unsigned (2u), char ('c' as 99), ... 3094 my $CstTid = getTreeAttr_Type($Type_Id); 3095 my %CstType = getTypeAttr($CstTid); # without recursion 3096 my $Num = getNodeIntCst($Type_Id); 3097 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) { 3098 return ($Num.$CstSuffix); 3099 } 3100 else { 3101 return ("(".$CstType{"Name"}.")".$Num); 3102 } 3103 } 3104 elsif($NodeType eq "string_cst") { 3105 return (getNodeStrCst($Type_Id)); 3106 } 3107 elsif($NodeType eq "tree_vec") 3108 { 3109 my $Vector = getTreeVec($Type_Id); 3110 my @Params = (); 3111 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector})) 3112 { 3113 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) { 3114 push(@Params, $P2); 3115 } 3116 } 3117 return @Params; 3118 } 3119 elsif($NodeType eq "parm_decl") 3120 { 3121 (getNameByInfo($Type_Id)); 3122 } 3123 else 3124 { 3125 my %ParamAttr = getTypeAttr($Type_Id); 3126 my $PName = $ParamAttr{"Name"}; 3127 if(not $PName) { 3128 return (); 3129 } 3130 if($PName=~/\>/) 3131 { 3132 if(my $Cover = cover_stdcxx_typedef($PName)) { 3133 $PName = $Cover; 3134 } 3135 } 3136 if($Pos>=1 and 3137 $PName=~/\A$DEFAULT_STD_PARMS\</) 3138 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> > 3139 # template<typename _Key, typename _Compare = std::less<_Key> 3140 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> > 3141 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> > 3142 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> > 3143 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> > 3144 return ("\@skip\@"); 3145 } 3146 return ($PName); 3147 } 3148} 3149 3150sub cover_stdcxx_typedef($) 3151{ 3152 my $TypeName = $_[0]; 3153 if(my @Covers = sort {length($a)<=>length($b)} 3154 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3155 { # take the shortest typedef 3156 # FIXME: there may be more than 3157 # one typedefs to the same type 3158 return $Covers[0]; 3159 } 3160 my $Covered = $TypeName; 3161 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){}; 3162 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3163 { 3164 if(my $Cover = $Covers[0]) 3165 { 3166 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g; 3167 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g; 3168 } 3169 } 3170 return formatName($Covered, "T"); 3171} 3172 3173sub getNodeIntCst($) 3174{ 3175 my $CstId = $_[0]; 3176 my $CstTypeId = getTreeAttr_Type($CstId); 3177 if($EnumMembName_Id{$Version}{$CstId}) { 3178 return $EnumMembName_Id{$Version}{$CstId}; 3179 } 3180 elsif((my $Value = getTreeValue($CstId)) ne "") 3181 { 3182 if($Value eq "0") 3183 { 3184 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3185 return "false"; 3186 } 3187 else { 3188 return "0"; 3189 } 3190 } 3191 elsif($Value eq "1") 3192 { 3193 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3194 return "true"; 3195 } 3196 else { 3197 return "1"; 3198 } 3199 } 3200 else { 3201 return $Value; 3202 } 3203 } 3204 return ""; 3205} 3206 3207sub getNodeStrCst($) 3208{ 3209 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3210 { 3211 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/) 3212 { 3213 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst") 3214 { # string length is N-1 because of the null terminator 3215 return substr($1, 0, $2-1); 3216 } 3217 else 3218 { # identifier_node 3219 return substr($1, 0, $2); 3220 } 3221 } 3222 } 3223 return ""; 3224} 3225 3226sub getMemPtrAttr($$$) 3227{ # function, method and field pointers 3228 my ($PtrId, $TypeId, $Type) = @_; 3229 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId}; 3230 if($Type eq "FieldPtr") { 3231 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId}; 3232 } 3233 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId}; 3234 my $MemPtrName = ""; 3235 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId); 3236 if($Type eq "MethodPtr") 3237 { # size of "method pointer" may be greater than WORD size 3238 if(my $Size = getSize($TypeId)) 3239 { 3240 $Size/=$BYTE_SIZE; 3241 $TypeAttr{"Size"} = "$Size"; 3242 } 3243 } 3244 if(my $Algn = getAlgn($TypeId)) { 3245 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3246 } 3247 # Return 3248 if($Type eq "FieldPtr") 3249 { 3250 my %ReturnAttr = getTypeAttr($PtrId); 3251 if($ReturnAttr{"Name"}) { 3252 $MemPtrName .= $ReturnAttr{"Name"}; 3253 } 3254 $TypeAttr{"Return"} = $PtrId; 3255 } 3256 else 3257 { 3258 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /) 3259 { 3260 my $ReturnTypeId = $1; 3261 my %ReturnAttr = getTypeAttr($ReturnTypeId); 3262 if(not $ReturnAttr{"Name"}) 3263 { # templates 3264 return (); 3265 } 3266 $MemPtrName .= $ReturnAttr{"Name"}; 3267 $TypeAttr{"Return"} = $ReturnTypeId; 3268 } 3269 } 3270 # Class 3271 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /) 3272 { 3273 $TypeAttr{"Class"} = $2; 3274 my %Class = getTypeAttr($TypeAttr{"Class"}); 3275 if($Class{"Name"}) { 3276 $MemPtrName .= " (".$Class{"Name"}."\:\:*)"; 3277 } 3278 else { 3279 $MemPtrName .= " (*)"; 3280 } 3281 } 3282 else { 3283 $MemPtrName .= " (*)"; 3284 } 3285 # Parameters 3286 if($Type eq "FuncPtr" 3287 or $Type eq "MethodPtr") 3288 { 3289 my @ParamTypeName = (); 3290 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /) 3291 { 3292 my $PTypeInfoId = $1; 3293 my ($Pos, $PPos) = (0, 0); 3294 while($PTypeInfoId) 3295 { 3296 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId}; 3297 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /) 3298 { 3299 my $PTypeId = $1; 3300 my %ParamAttr = getTypeAttr($PTypeId); 3301 if(not $ParamAttr{"Name"}) 3302 { # templates (template_type_parm), etc. 3303 return (); 3304 } 3305 if($ParamAttr{"Name"} eq "void") { 3306 last; 3307 } 3308 if($Pos!=0 or $Type ne "MethodPtr") 3309 { 3310 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId; 3311 push(@ParamTypeName, $ParamAttr{"Name"}); 3312 } 3313 if($PTypeInfoId = getNextElem($PTypeInfoId)) { 3314 $Pos+=1; 3315 } 3316 else { 3317 last; 3318 } 3319 } 3320 else { 3321 last; 3322 } 3323 } 3324 } 3325 $MemPtrName .= " (".join(", ", @ParamTypeName).")"; 3326 } 3327 $TypeAttr{"Name"} = formatName($MemPtrName, "T"); 3328 return %TypeAttr; 3329} 3330 3331sub getTreeTypeName($) 3332{ 3333 my $TypeId = $_[0]; 3334 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3335 { 3336 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type") 3337 { 3338 if(my $Name = getNameByInfo($TypeId)) 3339 { # bit_size_type 3340 return $Name; 3341 } 3342 elsif($Info=~/unsigned/) { 3343 return "unsigned int"; 3344 } 3345 else { 3346 return "int"; 3347 } 3348 } 3349 elsif($Info=~/name[ ]*:[ ]*@(\d+) /) { 3350 return getNameByInfo($1); 3351 } 3352 } 3353 return ""; 3354} 3355 3356sub isFuncPtr($) 3357{ 3358 my $Ptd = pointTo($_[0]); 3359 return 0 if(not $Ptd); 3360 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3361 { 3362 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) { 3363 return 0; 3364 } 3365 } 3366 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]} 3367 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd}) 3368 { 3369 if($InfoT1 eq "pointer_type" 3370 and $InfoT2 eq "function_type") { 3371 return 1; 3372 } 3373 } 3374 return 0; 3375} 3376 3377sub isMethodPtr($) 3378{ 3379 my $Ptd = pointTo($_[0]); 3380 return 0 if(not $Ptd); 3381 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3382 { 3383 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type" 3384 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type" 3385 and $Info=~/ ptrmem /) { 3386 return 1; 3387 } 3388 } 3389 return 0; 3390} 3391 3392sub isFieldPtr($) 3393{ 3394 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3395 { 3396 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type" 3397 and $Info=~/ ptrmem /) { 3398 return 1; 3399 } 3400 } 3401 return 0; 3402} 3403 3404sub pointTo($) 3405{ 3406 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3407 { 3408 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) { 3409 return $1; 3410 } 3411 } 3412 return ""; 3413} 3414 3415sub getTypeTypeByTypeId($) 3416{ 3417 my $TypeId = $_[0]; 3418 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId}) 3419 { 3420 my $NType = $NodeType{$TType}; 3421 if($NType eq "Intrinsic") { 3422 return $NType; 3423 } 3424 elsif(isFuncPtr($TypeId)) { 3425 return "FuncPtr"; 3426 } 3427 elsif(isMethodPtr($TypeId)) { 3428 return "MethodPtr"; 3429 } 3430 elsif(isFieldPtr($TypeId)) { 3431 return "FieldPtr"; 3432 } 3433 elsif($NType ne "Other") { 3434 return $NType; 3435 } 3436 } 3437 return "Unknown"; 3438} 3439 3440my %UnQual = ( 3441 "r"=>"restrict", 3442 "v"=>"volatile", 3443 "c"=>"const", 3444 "cv"=>"const volatile" 3445); 3446 3447sub getQual($) 3448{ 3449 my $TypeId = $_[0]; 3450 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3451 { 3452 my ($Qual, $To) = (); 3453 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) { 3454 $Qual = $UnQual{$1}; 3455 } 3456 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { 3457 $To = $1; 3458 } 3459 if($Qual and $To) { 3460 return ($Qual, $To); 3461 } 3462 } 3463 return (); 3464} 3465 3466sub getQualType($) 3467{ 3468 if($_[0] eq "const volatile") { 3469 return "ConstVolatile"; 3470 } 3471 return ucfirst($_[0]); 3472} 3473 3474sub getTypeType($) 3475{ 3476 my $TypeId = $_[0]; 3477 my $TypeDeclId = getTypeDeclId($TypeId); 3478 if(defined $MissedTypedef{$Version}{$TypeId}) 3479 { # support for old GCC versions 3480 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) { 3481 return "Typedef"; 3482 } 3483 } 3484 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3485 my ($Qual, $To) = getQual($TypeId); 3486 if(($Qual or $To) and $TypeDeclId 3487 and (getTypeId($TypeDeclId) ne $TypeId)) 3488 { # qualified types (special) 3489 return getQualType($Qual); 3490 } 3491 elsif(not $MissedBase_R{$Version}{$TypeId} 3492 and isTypedef($TypeId)) { 3493 return "Typedef"; 3494 } 3495 elsif($Qual) 3496 { # qualified types 3497 return getQualType($Qual); 3498 } 3499 3500 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) 3501 { # typedef struct { ... } name 3502 $TypeTypedef{$Version}{$TypeId} = $1; 3503 } 3504 3505 my $TypeType = getTypeTypeByTypeId($TypeId); 3506 if($TypeType eq "Struct") 3507 { 3508 if($TypeDeclId 3509 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") { 3510 return "Template"; 3511 } 3512 } 3513 return $TypeType; 3514} 3515 3516sub isTypedef($) 3517{ 3518 if($_[0]) 3519 { 3520 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") 3521 { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); 3522 return 0; 3523 } 3524 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3525 { 3526 if(my $TDid = getTypeDeclId($_[0])) 3527 { 3528 if(getTypeId($TDid) eq $_[0] 3529 and getNameByInfo($TDid)) 3530 { 3531 if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { 3532 return $1; 3533 } 3534 } 3535 } 3536 } 3537 } 3538 return 0; 3539} 3540 3541sub selectBaseType($) 3542{ 3543 my $TypeId = $_[0]; 3544 if(defined $MissedTypedef{$Version}{$TypeId}) 3545 { # add missed typedefs 3546 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) { 3547 return ($TypeId, ""); 3548 } 3549 } 3550 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3551 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId}; 3552 3553 my $MB_R = $MissedBase_R{$Version}{$TypeId}; 3554 my $MB = $MissedBase{$Version}{$TypeId}; 3555 3556 my ($Qual, $To) = getQual($TypeId); 3557 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) / 3558 and (getTypeId($1) ne $TypeId) 3559 and (not $MB_R or getTypeId($1) ne $MB_R)) 3560 { # qualified types (special) 3561 return (getTypeId($1), $Qual); 3562 } 3563 elsif($MB) 3564 { # add base 3565 return ($MB, ""); 3566 } 3567 elsif(not $MB_R and my $Bid = isTypedef($TypeId)) 3568 { # typedefs 3569 return ($Bid, ""); 3570 } 3571 elsif($Qual or $To) 3572 { # qualified types 3573 return ($To, $Qual); 3574 } 3575 elsif($InfoType eq "reference_type") 3576 { 3577 if($Info=~/refd[ ]*:[ ]*@(\d+) /) { 3578 return ($1, "&"); 3579 } 3580 } 3581 elsif($InfoType eq "array_type") 3582 { 3583 if($Info=~/elts[ ]*:[ ]*@(\d+) /) { 3584 return ($1, ""); 3585 } 3586 } 3587 elsif($InfoType eq "pointer_type") 3588 { 3589 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { 3590 return ($1, "*"); 3591 } 3592 } 3593 3594 return (0, ""); 3595} 3596 3597sub getSymbolInfo_All() 3598{ 3599 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3600 { # reverse order 3601 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") { 3602 getSymbolInfo($_); 3603 } 3604 } 3605 3606 if($ADD_TMPL_INSTANCES) 3607 { 3608 # templates 3609 foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) 3610 { 3611 my %Map = (); 3612 3613 if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) 3614 { 3615 if(defined $TemplateMap{$Version}{$ClassId}) 3616 { 3617 foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { 3618 $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; 3619 } 3620 } 3621 } 3622 3623 if(defined $TemplateMap{$Version}{$Sid}) 3624 { 3625 foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { 3626 $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; 3627 } 3628 } 3629 3630 if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) 3631 { 3632 foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) 3633 { 3634 my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; 3635 $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); 3636 } 3637 } 3638 if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { 3639 $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); 3640 } 3641 } 3642 } 3643} 3644 3645sub getVarInfo_All() 3646{ 3647 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3648 { # reverse order 3649 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") { 3650 getVarInfo($_); 3651 } 3652 } 3653} 3654 3655sub isBuiltIn($) { 3656 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./); 3657} 3658 3659sub getVarInfo($) 3660{ 3661 my $InfoId = $_[0]; 3662 if(my $NSid = getTreeAttr_Scpe($InfoId)) 3663 { 3664 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid}; 3665 if($NSInfoType and $NSInfoType eq "function_decl") { 3666 return; 3667 } 3668 } 3669 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 3670 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 3671 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { 3672 delete($SymbolInfo{$Version}{$InfoId}); 3673 return; 3674 } 3675 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId)); 3676 if(not $ShortName) { 3677 delete($SymbolInfo{$Version}{$InfoId}); 3678 return; 3679 } 3680 if($ShortName=~/\Atmp_add_class_\d+\Z/) { 3681 delete($SymbolInfo{$Version}{$InfoId}); 3682 return; 3683 } 3684 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName; 3685 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 3686 { 3687 if($OSgroup eq "windows") 3688 { # cut the offset 3689 $MnglName=~s/\@\d+\Z//g; 3690 } 3691 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 3692 } 3693 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 3694 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 3695 { # validate mangled name 3696 delete($SymbolInfo{$Version}{$InfoId}); 3697 return; 3698 } 3699 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3700 and index($ShortName, "_Z")==0) 3701 { # _ZTS, etc. 3702 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3703 } 3704 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"})) 3705 { # non-public global data 3706 delete($SymbolInfo{$Version}{$InfoId}); 3707 return; 3708 } 3709 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; 3710 if(my $Rid = getTypeId($InfoId)) 3711 { 3712 if(not defined $TypeInfo{$Version}{$Rid} 3713 or not $TypeInfo{$Version}{$Rid}{"Name"}) 3714 { 3715 delete($SymbolInfo{$Version}{$InfoId}); 3716 return; 3717 } 3718 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid; 3719 my $Val = getDataVal($InfoId, $Rid); 3720 if(defined $Val) { 3721 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val; 3722 } 3723 } 3724 set_Class_And_Namespace($InfoId); 3725 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 3726 { 3727 if(not defined $TypeInfo{$Version}{$ClassId} 3728 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 3729 { 3730 delete($SymbolInfo{$Version}{$InfoId}); 3731 return; 3732 } 3733 } 3734 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 3735 { # extern "C" 3736 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 3737 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3738 } 3739 if($UserLang and $UserLang eq "C") 3740 { # --lang=C option 3741 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3742 } 3743 if(not $CheckHeadersOnly) 3744 { 3745 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}) 3746 { 3747 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3748 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 3749 { 3750 if(link_symbol($ShortName, $Version, "-Deps")) 3751 { # "const" global data is mangled as _ZL... in the TU dump 3752 # but not mangled when compiling a C shared library 3753 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3754 } 3755 } 3756 } 3757 } 3758 if($COMMON_LANGUAGE{$Version} eq "C++") 3759 { 3760 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3761 { # for some symbols (_ZTI) the short name is the mangled name 3762 if(index($ShortName, "_Z")==0) { 3763 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3764 } 3765 } 3766 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3767 { # try to mangle symbol (link with libraries) 3768 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId); 3769 } 3770 if($OStarget eq "windows") 3771 { 3772 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 3773 { # link MS C++ symbols from library with GCC symbols from headers 3774 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 3775 } 3776 } 3777 } 3778 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { 3779 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3780 } 3781 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3782 { 3783 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 3784 { # non-target symbols 3785 delete($SymbolInfo{$Version}{$InfoId}); 3786 return; 3787 } 3788 } 3789 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 3790 { 3791 if(defined $MissedTypedef{$Version}{$Rid}) 3792 { 3793 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 3794 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 3795 } 3796 } 3797 } 3798 setFuncAccess($InfoId); 3799 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) { 3800 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 3801 } 3802 if($ShortName=~/\A(_Z|\?)/) { 3803 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"}); 3804 } 3805 3806 if($ExtraDump) { 3807 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 3808 } 3809} 3810 3811sub isConstType($$) 3812{ 3813 my ($TypeId, $LibVersion) = @_; 3814 my %Base = get_Type($TypeId, $LibVersion); 3815 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { 3816 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion}); 3817 } 3818 return ($Base{"Type"} eq "Const"); 3819} 3820 3821sub getTrivialName($$) 3822{ 3823 my ($TypeInfoId, $TypeId) = @_; 3824 my %TypeAttr = (); 3825 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId); 3826 if(not $TypeAttr{"Name"}) { 3827 $TypeAttr{"Name"} = getTreeTypeName($TypeId); 3828 } 3829 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3830 $TypeAttr{"Type"} = getTypeType($TypeId); 3831 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name 3832 if(isAnon($TypeAttr{"Name"})) 3833 { 3834 my $NameSpaceId = $TypeId; 3835 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId))) 3836 { # searching for a first not anon scope 3837 if($NSId eq $NameSpaceId) { 3838 last; 3839 } 3840 else 3841 { 3842 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId)); 3843 if(not $TypeAttr{"NameSpace"} 3844 or not isAnon($TypeAttr{"NameSpace"})) { 3845 last; 3846 } 3847 } 3848 $NameSpaceId = $NSId; 3849 } 3850 } 3851 else 3852 { 3853 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId)) 3854 { 3855 if($NameSpaceId ne $TypeId) { 3856 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId); 3857 } 3858 } 3859 } 3860 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) { 3861 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3862 } 3863 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3864 if(isAnon($TypeAttr{"Name"})) 3865 { # anon-struct-header.h-line 3866 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-"; 3867 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"}; 3868 if($TypeAttr{"NameSpace"}) { 3869 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3870 } 3871 } 3872 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId} 3873 and getTypeDeclId($TypeId) eq $TypeInfoId) 3874 { 3875 if(my @TParams = getTParams($TypeId, "Type")) { 3876 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); 3877 } 3878 else { 3879 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."<...>", "T"); 3880 } 3881 } 3882 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); 3883} 3884 3885sub getTrivialTypeAttr($) 3886{ 3887 my $TypeId = $_[0]; 3888 my $TypeInfoId = getTypeDeclId($_[0]); 3889 3890 my %TypeAttr = (); 3891 3892 if($TemplateDecl{$Version}{$TypeId}) 3893 { # template_decl 3894 $TypeAttr{"Template"} = 1; 3895 } 3896 3897 setTypeAccess($TypeId, \%TypeAttr); 3898 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3899 if(isBuiltIn($TypeAttr{"Header"})) 3900 { 3901 delete($TypeAttr{"Header"}); 3902 delete($TypeAttr{"Line"}); 3903 } 3904 3905 $TypeAttr{"Type"} = getTypeType($TypeId); 3906 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId); 3907 if(not $TypeAttr{"Name"}) { 3908 return (); 3909 } 3910 if(not $TypeAttr{"NameSpace"}) { 3911 delete($TypeAttr{"NameSpace"}); 3912 } 3913 3914 if($TypeAttr{"Type"} eq "Intrinsic") 3915 { 3916 if(defined $TypeAttr{"Header"}) 3917 { 3918 if($TypeAttr{"Header"}=~/\Adump[1-2]\.[ih]\Z/) 3919 { # support for SUSE 11.2 3920 # integer_type has srcp dump{1-2}.i 3921 delete($TypeAttr{"Header"}); 3922 } 3923 } 3924 } 3925 3926 my $Tmpl = undef; 3927 3928 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 3929 { 3930 $Tmpl = $BasicTemplate{$Version}{$TypeId}; 3931 3932 if(my @TParams = getTParams($TypeId, "Type")) 3933 { 3934 foreach my $Pos (0 .. $#TParams) 3935 { 3936 my $Val = $TParams[$Pos]; 3937 $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; 3938 3939 if(not defined $TypeAttr{"Template"}) 3940 { 3941 my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); 3942 3943 if($Base{"Type"} eq "TemplateParam" 3944 or defined $Base{"Template"}) { 3945 $TypeAttr{"Template"} = 1; 3946 } 3947 } 3948 3949 if($Tmpl) 3950 { 3951 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 3952 { 3953 $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; 3954 3955 if($Val eq $Arg) { 3956 $TypeAttr{"Template"} = 1; 3957 } 3958 } 3959 } 3960 } 3961 3962 if($Tmpl) 3963 { 3964 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 3965 { 3966 if($Pos>$#TParams) 3967 { 3968 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 3969 $TemplateMap{$Version}{$TypeId}{$Arg} = ""; 3970 } 3971 } 3972 } 3973 } 3974 3975 if($ADD_TMPL_INSTANCES) 3976 { 3977 if($Tmpl) 3978 { 3979 if(my $MainInst = getTreeAttr_Type($Tmpl)) 3980 { 3981 if(not getTreeAttr_Flds($TypeId)) 3982 { 3983 if(my $Flds = getTreeAttr_Flds($MainInst)) { 3984 $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; 3985 } 3986 } 3987 if(not getTreeAttr_Binf($TypeId)) 3988 { 3989 if(my $Binf = getTreeAttr_Binf($MainInst)) { 3990 $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; 3991 } 3992 } 3993 } 3994 } 3995 } 3996 } 3997 3998 my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); 3999 4000 if(my $Size = getSize($TypeId)) 4001 { 4002 $Size = $Size/$BYTE_SIZE; 4003 $TypeAttr{"Size"} = "$Size"; 4004 } 4005 else 4006 { 4007 if($ExtraDump) 4008 { 4009 if(not defined $TypeAttr{"Memb"} 4010 and not $Tmpl) 4011 { # declaration only 4012 $TypeAttr{"Forward"} = 1; 4013 } 4014 } 4015 } 4016 4017 if($TypeAttr{"Type"} eq "Struct" 4018 and ($StaticFields or detect_lang($TypeId))) 4019 { 4020 $TypeAttr{"Type"} = "Class"; 4021 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo() 4022 } 4023 if($TypeAttr{"Type"} eq "Struct" 4024 or $TypeAttr{"Type"} eq "Class") 4025 { 4026 my $Skip = setBaseClasses($TypeId, \%TypeAttr); 4027 if($Skip) { 4028 return (); 4029 } 4030 } 4031 if(my $Algn = getAlgn($TypeId)) { 4032 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 4033 } 4034 setSpec($TypeId, \%TypeAttr); 4035 4036 if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) 4037 { 4038 if(not $TypedefToAnon{$TypeId} 4039 and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 4040 { 4041 if(not isAnon($TypeAttr{"Name"})) { 4042 $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; 4043 } 4044 } 4045 } 4046 4047 $TypeAttr{"Tid"} = $TypeId; 4048 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}}) 4049 { 4050 my @Entries = split(/\n/, $VTable); 4051 foreach (1 .. $#Entries) 4052 { 4053 my $Entry = $Entries[$_]; 4054 if($Entry=~/\A(\d+)\s+(.+)\Z/) { 4055 $TypeAttr{"VTable"}{$1} = simplifyVTable($2); 4056 } 4057 } 4058 } 4059 4060 if($TypeAttr{"Type"} eq "Enum") 4061 { 4062 if(not $TypeAttr{"NameSpace"}) 4063 { 4064 foreach my $Pos (keys(%{$TypeAttr{"Memb"}})) 4065 { 4066 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"}; 4067 my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"}; 4068 $EnumConstants{$Version}{$MName} = { 4069 "Value"=>$MVal, 4070 "Header"=>$TypeAttr{"Header"} 4071 }; 4072 if(isAnon($TypeAttr{"Name"})) 4073 { 4074 if($ExtraDump 4075 or is_target_header($TypeAttr{"Header"}, $Version)) 4076 { 4077 %{$Constants{$Version}{$MName}} = ( 4078 "Value" => $MVal, 4079 "Header" => $TypeAttr{"Header"} 4080 ); 4081 } 4082 } 4083 } 4084 } 4085 } 4086 if($ExtraDump) 4087 { 4088 if(defined $TypedefToAnon{$TypeId}) { 4089 $TypeAttr{"AnonTypedef"} = 1; 4090 } 4091 } 4092 4093 return %TypeAttr; 4094} 4095 4096sub simplifyVTable($) 4097{ 4098 my $Content = $_[0]; 4099 if($Content=~s/ \[with (.+)]//) 4100 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>] 4101 if(my @Elems = separate_Params($1, 0, 0)) 4102 { 4103 foreach my $Elem (@Elems) 4104 { 4105 if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) 4106 { 4107 my ($Arg, $Val) = ($1, $2); 4108 4109 if(defined $DEFAULT_STD_ARGS{$Arg}) { 4110 $Content=~s/,\s*$Arg\b//g; 4111 } 4112 else { 4113 $Content=~s/\b$Arg\b/$Val/g; 4114 } 4115 } 4116 } 4117 } 4118 } 4119 4120 return $Content; 4121} 4122 4123sub detect_lang($) 4124{ 4125 my $TypeId = $_[0]; 4126 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4127 if(check_gcc($GCC_PATH, "4")) 4128 { # GCC 4 fncs-node points to only non-artificial methods 4129 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /); 4130 } 4131 else 4132 { # GCC 3 4133 my $Fncs = getTreeAttr_Fncs($TypeId); 4134 while($Fncs) 4135 { 4136 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) { 4137 return 1; 4138 } 4139 $Fncs = getTreeAttr_Chan($Fncs); 4140 } 4141 } 4142 return 0; 4143} 4144 4145sub setSpec($$) 4146{ 4147 my ($TypeId, $TypeAttr) = @_; 4148 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4149 if($Info=~/\s+spec\s+/) { 4150 $TypeAttr->{"Spec"} = 1; 4151 } 4152} 4153 4154sub setBaseClasses($$) 4155{ 4156 my ($TypeId, $TypeAttr) = @_; 4157 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4158 if(my $Binf = getTreeAttr_Binf($TypeId)) 4159 { 4160 my $Info = $LibInfo{$Version}{"info"}{$Binf}; 4161 my $Pos = 0; 4162 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) 4163 { 4164 my ($Access, $BInfoId) = ($1, $2); 4165 my $ClassId = getBinfClassId($BInfoId); 4166 4167 if($ClassId eq $TypeId) 4168 { # class A<N>:public A<N-1> 4169 next; 4170 } 4171 4172 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId}; 4173 if(not $CType or $CType eq "template_type_parm" 4174 or $CType eq "typename_type") 4175 { # skip 4176 # return 1; 4177 } 4178 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; 4179 if($Access=~/prot/) { 4180 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected"; 4181 } 4182 elsif($Access=~/priv/) { 4183 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private"; 4184 } 4185 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos"; 4186 if($BaseInfo=~/virt/) 4187 { # virtual base 4188 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1; 4189 } 4190 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1; 4191 $Pos += 1; 4192 } 4193 } 4194 return 0; 4195} 4196 4197sub getBinfClassId($) 4198{ 4199 my $Info = $LibInfo{$Version}{"info"}{$_[0]}; 4200 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 4201 return $1; 4202 } 4203 4204 return ""; 4205} 4206 4207sub unmangledFormat($$) 4208{ 4209 my ($Name, $LibVersion) = @_; 4210 $Name = uncover_typedefs($Name, $LibVersion); 4211 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){}; 4212 $Name=~s/\(\w+\)(\d)/$1/; 4213 return $Name; 4214} 4215 4216sub modelUnmangled($$) 4217{ 4218 my ($InfoId, $Compiler) = @_; 4219 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) { 4220 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}; 4221 } 4222 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 4223 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4224 $PureSignature = "~".$PureSignature; 4225 } 4226 if(not $SymbolInfo{$Version}{$InfoId}{"Data"}) 4227 { 4228 my (@Params, @ParamTypes) = (); 4229 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"} 4230 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4231 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}}); 4232 } 4233 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4234 { # checking parameters 4235 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4236 my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; 4237 my %PType = get_PureType($PId, $TypeInfo{$Version}); 4238 my $PTName = unmangledFormat($PType{"Name"}, $Version); 4239 4240 if($PName eq "this" 4241 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") 4242 { 4243 next; 4244 } 4245 4246 $PTName=~s/\b(restrict|register)\b//g; 4247 if($Compiler eq "MSVC") { 4248 $PTName=~s/\blong long\b/__int64/; 4249 } 4250 @ParamTypes = (@ParamTypes, $PTName); 4251 } 4252 if(@ParamTypes) { 4253 $PureSignature .= "(".join(", ", @ParamTypes).")"; 4254 } 4255 else 4256 { 4257 if($Compiler eq "MSVC") 4258 { 4259 $PureSignature .= "(void)"; 4260 } 4261 else 4262 { # GCC 4263 $PureSignature .= "()"; 4264 } 4265 } 4266 $PureSignature = delete_keywords($PureSignature); 4267 } 4268 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 4269 { 4270 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version); 4271 $PureSignature = $ClassName."::".$PureSignature; 4272 } 4273 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { 4274 $PureSignature = $NS."::".$PureSignature; 4275 } 4276 if($SymbolInfo{$Version}{$InfoId}{"Const"}) { 4277 $PureSignature .= " const"; 4278 } 4279 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) { 4280 $PureSignature .= " volatile"; 4281 } 4282 my $ShowReturn = 0; 4283 if($Compiler eq "MSVC" 4284 and $SymbolInfo{$Version}{$InfoId}{"Data"}) 4285 { 4286 $ShowReturn=1; 4287 } 4288 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId} 4289 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}})) 4290 { 4291 $ShowReturn=1; 4292 } 4293 if($ShowReturn) 4294 { # mangled names for template function specializations include return value 4295 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"}) 4296 { 4297 my %RType = get_PureType($ReturnId, $TypeInfo{$Version}); 4298 my $ReturnName = unmangledFormat($RType{"Name"}, $Version); 4299 $PureSignature = $ReturnName." ".$PureSignature; 4300 } 4301 } 4302 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S")); 4303} 4304 4305sub mangle_symbol($$$) 4306{ # mangling for simple methods 4307 # see gcc-4.6.0/gcc/cp/mangle.c 4308 my ($InfoId, $LibVersion, $Compiler) = @_; 4309 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) { 4310 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}; 4311 } 4312 my $Mangled = ""; 4313 if($Compiler eq "GCC") { 4314 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion); 4315 } 4316 elsif($Compiler eq "MSVC") { 4317 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion); 4318 } 4319 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled); 4320} 4321 4322sub mangle_symbol_MSVC($$) 4323{ # TODO 4324 my ($InfoId, $LibVersion) = @_; 4325 return ""; 4326} 4327 4328sub mangle_symbol_GCC($$) 4329{ # see gcc-4.6.0/gcc/cp/mangle.c 4330 my ($InfoId, $LibVersion) = @_; 4331 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, ""); 4332 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 4333 my %Repl = ();# SN_ replacements 4334 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 4335 { 4336 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl); 4337 if($MangledClass!~/\AN/) { 4338 $MangledClass = "N".$MangledClass; 4339 } 4340 else { 4341 $MangledClass=~s/E\Z//; 4342 } 4343 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) { 4344 $MangledClass=~s/\AN/NV/; 4345 } 4346 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) { 4347 $MangledClass=~s/\AN/NK/; 4348 } 4349 $Mangled .= $MangledClass; 4350 } 4351 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"}) 4352 { # mangled by name due to the absence of structured info 4353 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl); 4354 if($MangledNS!~/\AN/) { 4355 $MangledNS = "N".$MangledNS; 4356 } 4357 else { 4358 $MangledNS=~s/E\Z//; 4359 } 4360 $Mangled .= $MangledNS; 4361 } 4362 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}); 4363 my @TParams = (); 4364 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) 4365 { # parsing mode 4366 foreach (@TPos) { 4367 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"}); 4368 } 4369 } 4370 elsif($TmplParams) 4371 { # remangling mode 4372 # support for old ABI dumps 4373 @TParams = separate_Params($TmplParams, 0, 0); 4374 } 4375 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { 4376 $Mangled .= "C1"; 4377 } 4378 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4379 $Mangled .= "D0"; 4380 } 4381 elsif($ShortName) 4382 { 4383 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4384 { 4385 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 4386 and isConstType($Return, $LibVersion)) 4387 { # "const" global data is mangled as _ZL... 4388 $Mangled .= "L"; 4389 } 4390 } 4391 if($ShortName=~/\Aoperator(\W.*)\Z/) 4392 { 4393 my $Op = $1; 4394 $Op=~s/\A[ ]+//g; 4395 if(my $OpMngl = $OperatorMangling{$Op}) { 4396 $Mangled .= $OpMngl; 4397 } 4398 else { # conversion operator 4399 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl); 4400 } 4401 } 4402 else { 4403 $Mangled .= length($ShortName).$ShortName; 4404 } 4405 if(@TParams) 4406 { # templates 4407 $Mangled .= "I"; 4408 foreach my $TParam (@TParams) { 4409 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl); 4410 } 4411 $Mangled .= "E"; 4412 } 4413 if(not $ClassId and @TParams) { 4414 add_substitution($ShortName, \%Repl, 0); 4415 } 4416 } 4417 if($ClassId or $NameSpace) { 4418 $Mangled .= "E"; 4419 } 4420 if(@TParams) 4421 { 4422 if($Return) { 4423 $Mangled .= mangle_param($Return, $LibVersion, \%Repl); 4424 } 4425 } 4426 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4427 { 4428 my @Params = (); 4429 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 4430 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4431 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 4432 } 4433 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4434 { # checking parameters 4435 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4436 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl); 4437 } 4438 if(not @Params) { 4439 $Mangled .= "v"; 4440 } 4441 } 4442 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled); 4443 $Mangled = write_stdcxx_substitution($Mangled); 4444 if($Mangled eq "_Z") { 4445 return ""; 4446 } 4447 return $Mangled; 4448} 4449 4450sub correct_incharge($$$) 4451{ 4452 my ($InfoId, $LibVersion, $Mangled) = @_; 4453 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) 4454 { 4455 if($MangledNames{$LibVersion}{$Mangled}) { 4456 $Mangled=~s/C1([EI])/C2$1/; 4457 } 4458 } 4459 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 4460 { 4461 if($MangledNames{$LibVersion}{$Mangled}) { 4462 $Mangled=~s/D0([EI])/D1$1/; 4463 } 4464 if($MangledNames{$LibVersion}{$Mangled}) { 4465 $Mangled=~s/D1([EI])/D2$1/; 4466 } 4467 } 4468 return $Mangled; 4469} 4470 4471sub template_Base($) 4472{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl 4473 # NOTE: operators: >>, << 4474 my $Name = $_[0]; 4475 if($Name!~/>\Z/ or $Name!~/</) { 4476 return $Name; 4477 } 4478 my $TParams = $Name; 4479 while(my $CPos = find_center($TParams, "<")) 4480 { # search for the last <T> 4481 $TParams = substr($TParams, $CPos); 4482 } 4483 if($TParams=~s/\A<(.+)>\Z/$1/) { 4484 $Name=~s/<\Q$TParams\E>\Z//; 4485 } 4486 else 4487 { # error 4488 $TParams = ""; 4489 } 4490 return ($Name, $TParams); 4491} 4492 4493sub get_sub_ns($) 4494{ 4495 my $Name = $_[0]; 4496 my @NS = (); 4497 while(my $CPos = find_center($Name, ":")) 4498 { 4499 push(@NS, substr($Name, 0, $CPos)); 4500 $Name = substr($Name, $CPos); 4501 $Name=~s/\A:://; 4502 } 4503 return (join("::", @NS), $Name); 4504} 4505 4506sub mangle_ns($$$) 4507{ 4508 my ($Name, $LibVersion, $Repl) = @_; 4509 if(my $Tid = $TName_Tid{$LibVersion}{$Name}) 4510 { 4511 my $Mangled = mangle_param($Tid, $LibVersion, $Repl); 4512 $Mangled=~s/\AN(.+)E\Z/$1/; 4513 return $Mangled; 4514 4515 } 4516 else 4517 { 4518 my ($MangledNS, $SubNS) = ("", ""); 4519 ($SubNS, $Name) = get_sub_ns($Name); 4520 if($SubNS) { 4521 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4522 } 4523 $MangledNS .= length($Name).$Name; 4524 add_substitution($MangledNS, $Repl, 0); 4525 return $MangledNS; 4526 } 4527} 4528 4529sub mangle_param($$$) 4530{ 4531 my ($PTid, $LibVersion, $Repl) = @_; 4532 my ($MPrefix, $Mangled) = ("", ""); 4533 my %ReplCopy = %{$Repl}; 4534 my %BaseType = get_BaseType($PTid, $LibVersion); 4535 my $BaseType_Name = $BaseType{"Name"}; 4536 $BaseType_Name=~s/\A(struct|union|enum) //g; 4537 if(not $BaseType_Name) { 4538 return ""; 4539 } 4540 my ($ShortName, $TmplParams) = template_Base($BaseType_Name); 4541 my $Suffix = get_BaseTypeQual($PTid, $LibVersion); 4542 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){}; 4543 while($Suffix=~/(&|\*|const)\Z/) 4544 { 4545 if($Suffix=~s/[ ]*&\Z//) { 4546 $MPrefix .= "R"; 4547 } 4548 if($Suffix=~s/[ ]*\*\Z//) { 4549 $MPrefix .= "P"; 4550 } 4551 if($Suffix=~s/[ ]*const\Z//) 4552 { 4553 if($MPrefix=~/R|P/ 4554 or $Suffix=~/&|\*/) { 4555 $MPrefix .= "K"; 4556 } 4557 } 4558 if($Suffix=~s/[ ]*volatile\Z//) { 4559 $MPrefix .= "V"; 4560 } 4561 #if($Suffix=~s/[ ]*restrict\Z//) { 4562 #$MPrefix .= "r"; 4563 #} 4564 } 4565 if(my $Token = $IntrinsicMangling{$BaseType_Name}) { 4566 $Mangled .= $Token; 4567 } 4568 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/) 4569 { 4570 my @TParams = (); 4571 if(my @TPos = keys(%{$BaseType{"TParam"}})) 4572 { # parsing mode 4573 foreach (@TPos) { 4574 push(@TParams, $BaseType{"TParam"}{$_}{"name"}); 4575 } 4576 } 4577 elsif($TmplParams) 4578 { # remangling mode 4579 # support for old ABI dumps 4580 @TParams = separate_Params($TmplParams, 0, 0); 4581 } 4582 my $MangledNS = ""; 4583 my ($SubNS, $SName) = get_sub_ns($ShortName); 4584 if($SubNS) { 4585 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4586 } 4587 $MangledNS .= length($SName).$SName; 4588 if(@TParams) { 4589 add_substitution($MangledNS, $Repl, 0); 4590 } 4591 $Mangled .= "N".$MangledNS; 4592 if(@TParams) 4593 { # templates 4594 $Mangled .= "I"; 4595 foreach my $TParam (@TParams) { 4596 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl); 4597 } 4598 $Mangled .= "E"; 4599 } 4600 $Mangled .= "E"; 4601 } 4602 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/) 4603 { 4604 if($BaseType{"Type"} eq "MethodPtr") { 4605 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F"; 4606 } 4607 else { 4608 $Mangled .= "PF"; 4609 } 4610 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4611 my @Params = keys(%{$BaseType{"Param"}}); 4612 foreach my $Num (sort {int($a)<=>int($b)} @Params) { 4613 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl); 4614 } 4615 if(not @Params) { 4616 $Mangled .= "v"; 4617 } 4618 $Mangled .= "E"; 4619 } 4620 elsif($BaseType{"Type"} eq "FieldPtr") 4621 { 4622 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl); 4623 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4624 } 4625 $Mangled = $MPrefix.$Mangled;# add prefix (RPK) 4626 if(my $Optimized = write_substitution($Mangled, \%ReplCopy)) 4627 { 4628 if($Mangled eq $Optimized) 4629 { 4630 if($ShortName!~/::/) 4631 { # remove "N ... E" 4632 if($MPrefix) { 4633 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g; 4634 } 4635 else { 4636 $Mangled=~s/\AN(.+)E\Z/$1/g; 4637 } 4638 } 4639 } 4640 else { 4641 $Mangled = $Optimized; 4642 } 4643 } 4644 add_substitution($Mangled, $Repl, 1); 4645 return $Mangled; 4646} 4647 4648sub mangle_template_param($$$) 4649{ # types + literals 4650 my ($TParam, $LibVersion, $Repl) = @_; 4651 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) { 4652 return mangle_param($TPTid, $LibVersion, $Repl); 4653 } 4654 elsif($TParam=~/\A(\d+)(\w+)\Z/) 4655 { # class_name<1u>::method(...) 4656 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E"; 4657 } 4658 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/) 4659 { # class_name<(signed char)1>::method(...) 4660 return "L".$IntrinsicMangling{$1}.$2."E"; 4661 } 4662 elsif($TParam eq "true") 4663 { # class_name<true>::method(...) 4664 return "Lb1E"; 4665 } 4666 elsif($TParam eq "false") 4667 { # class_name<true>::method(...) 4668 return "Lb0E"; 4669 } 4670 else { # internal error 4671 return length($TParam).$TParam; 4672 } 4673} 4674 4675sub add_substitution($$$) 4676{ 4677 my ($Value, $Repl, $Rec) = @_; 4678 if($Rec) 4679 { # subtypes 4680 my @Subs = ($Value); 4681 while($Value=~s/\A(R|P|K)//) { 4682 push(@Subs, $Value); 4683 } 4684 foreach (reverse(@Subs)) { 4685 add_substitution($_, $Repl, 0); 4686 } 4687 return; 4688 } 4689 return if($Value=~/\AS(\d*)_\Z/); 4690 $Value=~s/\AN(.+)E\Z/$1/g; 4691 return if(defined $Repl->{$Value}); 4692 return if(length($Value)<=1); 4693 return if($StdcxxMangling{$Value}); 4694 # check for duplicates 4695 my $Base = $Value; 4696 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4697 { 4698 my $Num = $Repl->{$Type}; 4699 my $Replace = macro_mangle($Num); 4700 $Base=~s/\Q$Replace\E/$Type/; 4701 } 4702 if(my $OldNum = $Repl->{$Base}) 4703 { 4704 $Repl->{$Value} = $OldNum; 4705 return; 4706 } 4707 my @Repls = sort {$b<=>$a} values(%{$Repl}); 4708 if(@Repls) { 4709 $Repl->{$Value} = $Repls[0]+1; 4710 } 4711 else { 4712 $Repl->{$Value} = -1; 4713 } 4714 # register duplicates 4715 # upward 4716 $Base = $Value; 4717 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4718 { 4719 next if($Base eq $Type); 4720 my $Num = $Repl->{$Type}; 4721 my $Replace = macro_mangle($Num); 4722 $Base=~s/\Q$Type\E/$Replace/; 4723 $Repl->{$Base} = $Repl->{$Value}; 4724 } 4725} 4726 4727sub macro_mangle($) 4728{ 4729 my $Num = $_[0]; 4730 if($Num==-1) { 4731 return "S_"; 4732 } 4733 else 4734 { 4735 my $Code = ""; 4736 if($Num<10) 4737 { # S0_, S1_, S2_, ... 4738 $Code = $Num; 4739 } 4740 elsif($Num>=10 and $Num<=35) 4741 { # SA_, SB_, SC_, ... 4742 $Code = chr(55+$Num); 4743 } 4744 else 4745 { # S10_, S11_, S12_ 4746 $Code = $Num-26; # 26 is length of english alphabet 4747 } 4748 return "S".$Code."_"; 4749 } 4750} 4751 4752sub write_stdcxx_substitution($) 4753{ 4754 my $Mangled = $_[0]; 4755 if($StdcxxMangling{$Mangled}) { 4756 return $StdcxxMangling{$Mangled}; 4757 } 4758 else 4759 { 4760 my @Repls = keys(%StdcxxMangling); 4761 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4762 foreach my $MangledType (@Repls) 4763 { 4764 my $Replace = $StdcxxMangling{$MangledType}; 4765 #if($Mangled!~/$Replace/) { 4766 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4767 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4768 #} 4769 } 4770 } 4771 return $Mangled; 4772} 4773 4774sub write_substitution($$) 4775{ 4776 my ($Mangled, $Repl) = @_; 4777 if(defined $Repl->{$Mangled} 4778 and my $MnglNum = $Repl->{$Mangled}) { 4779 $Mangled = macro_mangle($MnglNum); 4780 } 4781 else 4782 { 4783 my @Repls = keys(%{$Repl}); 4784 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls; 4785 # FIXME: how to apply replacements? by num or by pos 4786 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4787 foreach my $MangledType (@Repls) 4788 { 4789 my $Replace = macro_mangle($Repl->{$MangledType}); 4790 if($Mangled!~/$Replace/) { 4791 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4792 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4793 } 4794 } 4795 } 4796 return $Mangled; 4797} 4798 4799sub delete_keywords($) 4800{ 4801 my $TypeName = $_[0]; 4802 $TypeName=~s/\b(enum|struct|union|class) //g; 4803 return $TypeName; 4804} 4805 4806sub uncover_typedefs($$) 4807{ 4808 my ($TypeName, $LibVersion) = @_; 4809 return "" if(not $TypeName); 4810 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) { 4811 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}; 4812 } 4813 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), ""); 4814 while($TypeName_New ne $TypeName_Pre) 4815 { 4816 $TypeName_Pre = $TypeName_New; 4817 my $TypeName_Copy = $TypeName_New; 4818 my %Words = (); 4819 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io) 4820 { 4821 if(not $Intrinsic_Keywords{$1}) { 4822 $Words{$1} = 1; 4823 } 4824 } 4825 foreach my $Word (keys(%Words)) 4826 { 4827 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word}; 4828 next if(not $BaseType_Name); 4829 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/); 4830 if($BaseType_Name=~/\([\*]+\)/) 4831 { # FuncPtr 4832 if($TypeName_New=~/\Q$Word\E(.*)\Z/) 4833 { 4834 my $Type_Suffix = $1; 4835 $TypeName_New = $BaseType_Name; 4836 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) { 4837 $TypeName_New = formatName($TypeName_New, "T"); 4838 } 4839 } 4840 } 4841 else 4842 { 4843 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) { 4844 $TypeName_New = formatName($TypeName_New, "T"); 4845 } 4846 } 4847 } 4848 } 4849 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New); 4850} 4851 4852sub isInternal($) 4853{ 4854 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 4855 { 4856 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) 4857 { 4858 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/) 4859 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL* 4860 return 1; 4861 } 4862 } 4863 } 4864 return 0; 4865} 4866 4867sub getDataVal($$) 4868{ 4869 my ($InfoId, $TypeId) = @_; 4870 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4871 { 4872 if($Info=~/init[ ]*:[ ]*@(\d+) /) 4873 { 4874 if(defined $LibInfo{$Version}{"info_type"}{$1} 4875 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr") 4876 { 4877 if(my $Nop = getTreeAttr_Op($1)) 4878 { 4879 if(defined $LibInfo{$Version}{"info_type"}{$Nop} 4880 and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr") 4881 { 4882 if(my $Addr = getTreeAttr_Op($1)) { 4883 return getInitVal($Addr, $TypeId); 4884 } 4885 } 4886 } 4887 } 4888 else { 4889 return getInitVal($1, $TypeId); 4890 } 4891 } 4892 } 4893 return undef; 4894} 4895 4896sub getInitVal($$) 4897{ 4898 my ($InfoId, $TypeId) = @_; 4899 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4900 { 4901 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId}) 4902 { 4903 if($InfoType eq "integer_cst") 4904 { 4905 my $Val = getNodeIntCst($InfoId); 4906 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/) 4907 { # characters 4908 $Val = chr($Val); 4909 } 4910 return $Val; 4911 } 4912 elsif($InfoType eq "string_cst") { 4913 return getNodeStrCst($InfoId); 4914 } 4915 elsif($InfoType eq "var_decl") 4916 { 4917 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) { 4918 return $Name; 4919 } 4920 } 4921 } 4922 } 4923 return undef; 4924} 4925 4926sub set_Class_And_Namespace($) 4927{ 4928 my $InfoId = $_[0]; 4929 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4930 { 4931 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) 4932 { 4933 my $NSInfoId = $1; 4934 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 4935 { 4936 if($InfoType eq "namespace_decl") { 4937 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId); 4938 } 4939 elsif($InfoType eq "record_type") { 4940 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId; 4941 } 4942 } 4943 } 4944 } 4945 if($SymbolInfo{$Version}{$InfoId}{"Class"} 4946 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) 4947 { 4948 if($COMMON_LANGUAGE{$Version} ne "C++") 4949 { # skip 4950 return 1; 4951 } 4952 } 4953 4954 return 0; 4955} 4956 4957sub debugMangling($) 4958{ 4959 my $LibVersion = $_[0]; 4960 my %Mangled = (); 4961 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 4962 { 4963 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 4964 { 4965 if($Mngl=~/\A(_Z|\?)/) { 4966 $Mangled{$Mngl}=$InfoId; 4967 } 4968 } 4969 } 4970 translateSymbols(keys(%Mangled), $LibVersion); 4971 foreach my $Mngl (keys(%Mangled)) 4972 { 4973 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC"); 4974 my $U2 = $tr_name{$Mngl}; 4975 if($U1 ne $U2) { 4976 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n"); 4977 } 4978 } 4979} 4980 4981sub linkSymbol($) 4982{ # link symbols from shared libraries 4983 # with the symbols from header files 4984 my $InfoId = $_[0]; 4985 # try to mangle symbol 4986 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"}) 4987 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 4988 or $GCC_MISSED_MNGL) 4989 { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) 4990 # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions 4991 # GCC 4.8.[012] and 6.[12].0 don't mangle anything 4992 if(not $CheckHeadersOnly) 4993 { 4994 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) { 4995 return correct_incharge($InfoId, $Version, $Mangled); 4996 } 4997 } 4998 if($CheckHeadersOnly 4999 or not $BinaryOnly 5000 or $GCC_MISSED_MNGL) 5001 { # 1. --headers-only mode 5002 # 2. not mangled src-only symbols 5003 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) { 5004 return $Mangled; 5005 } 5006 } 5007 } 5008 return ""; 5009} 5010 5011sub setLanguage($$) 5012{ 5013 my ($LibVersion, $Lang) = @_; 5014 if(not $UserLang) { 5015 $COMMON_LANGUAGE{$LibVersion} = $Lang; 5016 } 5017} 5018 5019sub getSymbolInfo($) 5020{ 5021 my $InfoId = $_[0]; 5022 if(isInternal($InfoId)) { 5023 return; 5024 } 5025 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 5026 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 5027 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) 5028 { 5029 delete($SymbolInfo{$Version}{$InfoId}); 5030 return; 5031 } 5032 setFuncAccess($InfoId); 5033 setFuncKind($InfoId); 5034 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) 5035 { 5036 delete($SymbolInfo{$Version}{$InfoId}); 5037 return; 5038 } 5039 5040 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId); 5041 if(my $Return = getFuncReturn($InfoId)) 5042 { 5043 if(not defined $TypeInfo{$Version}{$Return} 5044 or not $TypeInfo{$Version}{$Return}{"Name"}) 5045 { 5046 delete($SymbolInfo{$Version}{$InfoId}); 5047 return; 5048 } 5049 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return; 5050 } 5051 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 5052 { 5053 if(defined $MissedTypedef{$Version}{$Rid}) 5054 { 5055 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 5056 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 5057 } 5058 } 5059 } 5060 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) { 5061 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5062 } 5063 my $Orig = getFuncOrig($InfoId); 5064 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig); 5065 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1) 5066 { 5067 delete($SymbolInfo{$Version}{$InfoId}); 5068 return; 5069 } 5070 5071 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0) 5072 { 5073 delete($SymbolInfo{$Version}{$InfoId}); 5074 return; 5075 } 5076 5077 if(defined $TemplateInstance{$Version}{"Func"}{$Orig}) 5078 { 5079 my $Tmpl = $BasicTemplate{$Version}{$InfoId}; 5080 5081 my @TParams = getTParams($Orig, "Func"); 5082 if(not @TParams) 5083 { 5084 delete($SymbolInfo{$Version}{$InfoId}); 5085 return; 5086 } 5087 foreach my $Pos (0 .. $#TParams) 5088 { 5089 my $Val = $TParams[$Pos]; 5090 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val; 5091 5092 if($Tmpl) 5093 { 5094 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 5095 { 5096 $TemplateMap{$Version}{$InfoId}{$Arg} = $Val; 5097 } 5098 } 5099 } 5100 5101 if($Tmpl) 5102 { 5103 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 5104 { 5105 if($Pos>$#TParams) 5106 { 5107 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 5108 $TemplateMap{$Version}{$InfoId}{$Arg} = ""; 5109 } 5110 } 5111 } 5112 5113 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/) 5114 { # operator<< <T>, operator>> <T> 5115 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " "; 5116 } 5117 if(@TParams) { 5118 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".join(", ", @TParams).">"; 5119 } 5120 else { 5121 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<...>"; 5122 } 5123 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S"); 5124 } 5125 else 5126 { # support for GCC 3.4 5127 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5128 } 5129 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 5130 { 5131 if($OSgroup eq "windows") 5132 { # cut the offset 5133 $MnglName=~s/\@\d+\Z//g; 5134 } 5135 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 5136 5137 # NOTE: mangling of some symbols may change depending on GCC version 5138 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E 5139 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_ 5140 } 5141 5142 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 5143 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 5144 { 5145 delete($SymbolInfo{$Version}{$InfoId}); 5146 return; 5147 } 5148 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) 5149 { # destructors have an empty parameter list 5150 my $Skip = setFuncParams($InfoId); 5151 if($Skip) 5152 { 5153 delete($SymbolInfo{$Version}{$InfoId}); 5154 return; 5155 } 5156 } 5157 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) { 5158 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1; 5159 } 5160 5161 if(set_Class_And_Namespace($InfoId)) 5162 { 5163 delete($SymbolInfo{$Version}{$InfoId}); 5164 return; 5165 } 5166 5167 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5168 { 5169 if(not defined $TypeInfo{$Version}{$ClassId} 5170 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 5171 { 5172 delete($SymbolInfo{$Version}{$InfoId}); 5173 return; 5174 } 5175 } 5176 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 5177 { # extern "C" 5178 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 5179 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5180 } 5181 if($UserLang and $UserLang eq "C") 5182 { # --lang=C option 5183 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5184 } 5185 if($COMMON_LANGUAGE{$Version} eq "C++") 5186 { # correct mangled & short names 5187 # C++ or --headers-only mode 5188 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/) 5189 { # support for old GCC versions: reconstruct real names for constructors and destructors 5190 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"})); 5191 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5192 } 5193 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5194 { # try to mangle symbol (link with libraries) 5195 if(my $Mangled = linkSymbol($InfoId)) { 5196 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 5197 } 5198 } 5199 if($OStarget eq "windows") 5200 { # link MS C++ symbols from library with GCC symbols from headers 5201 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 5202 { # exported symbols 5203 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1; 5204 } 5205 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC")) 5206 { # pure virtual symbols 5207 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2; 5208 } 5209 } 5210 } 5211 else 5212 { # not mangled in C 5213 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5214 } 5215 if(not $CheckHeadersOnly 5216 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function" 5217 and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 5218 { 5219 my $Incorrect = 0; 5220 5221 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5222 { 5223 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0 5224 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 5225 { # mangled in the TU dump, but not mangled in the library 5226 $Incorrect = 1; 5227 } 5228 } 5229 else 5230 { 5231 if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C") 5232 { # all C++ functions are not mangled in the TU dump 5233 $Incorrect = 1; 5234 } 5235 } 5236 if($Incorrect) 5237 { 5238 if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) { 5239 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5240 } 5241 } 5242 } 5243 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5244 { # can't detect symbol name 5245 delete($SymbolInfo{$Version}{$InfoId}); 5246 return; 5247 } 5248 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5249 and my $Spec = getVirtSpec($Orig)) 5250 { # identify virtual and pure virtual functions 5251 # NOTE: constructors cannot be virtual 5252 # NOTE: in GCC 4.7 D1 destructors have no virtual spec 5253 # in the TU dump, so taking it from the original symbol 5254 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"} 5255 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/)) 5256 { # NOTE: D2 destructors are not present in a v-table 5257 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1; 5258 } 5259 } 5260 if(isInline($InfoId)) { 5261 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1; 5262 } 5263 if(hasThrow($InfoId)) { 5264 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1; 5265 } 5266 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5267 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5268 { 5269 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"} 5270 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"}) 5271 { # inline or auto-generated constructor 5272 delete($TypeInfo{$Version}{$ClassId}{"Copied"}); 5273 } 5274 } 5275 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5276 { 5277 if(not $ExtraDump) 5278 { 5279 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 5280 { # non-target symbols 5281 delete($SymbolInfo{$Version}{$InfoId}); 5282 return; 5283 } 5284 } 5285 } 5286 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method" 5287 or $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5288 or $SymbolInfo{$Version}{$InfoId}{"Destructor"} 5289 or $SymbolInfo{$Version}{$InfoId}{"Class"}) 5290 { 5291 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) 5292 { 5293 delete($SymbolInfo{$Version}{$InfoId}); 5294 return; 5295 } 5296 } 5297 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5298 { 5299 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5300 { # one instance for one mangled name only 5301 delete($SymbolInfo{$Version}{$InfoId}); 5302 return; 5303 } 5304 else { 5305 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1; 5306 } 5307 } 5308 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5309 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 5310 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5311 } 5312 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/ 5313 and $SymbolInfo{$Version}{$InfoId}{"Class"}) 5314 { 5315 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function") 5316 { # static methods 5317 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5318 } 5319 } 5320 if(getFuncLink($InfoId) eq "Static") { 5321 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5322 } 5323 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/) 5324 { 5325 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5326 { 5327 if($Unmangled=~/\.\_\d/) 5328 { 5329 delete($SymbolInfo{$Version}{$InfoId}); 5330 return; 5331 } 5332 } 5333 } 5334 5335 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) { 5336 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5337 } 5338 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) { 5339 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5340 } 5341 5342 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { 5343 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1; 5344 } 5345 5346 if($ExtraDump) { 5347 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 5348 } 5349} 5350 5351sub guessHeader($) 5352{ 5353 my $InfoId = $_[0]; 5354 my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5355 my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}; 5356 my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):""; 5357 my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"}; 5358 if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName}) 5359 { 5360 if(get_filename($HPath) eq $Header) 5361 { 5362 my $HDir = get_filename(get_dirname($HPath)); 5363 if($HDir ne "include" 5364 and $HDir=~/\A[a-z]+\Z/i) { 5365 return join_P($HDir, $Header); 5366 } 5367 } 5368 } 5369 return $Header; 5370} 5371 5372sub isInline($) 5373{ # "body: undefined" in the tree 5374 # -fkeep-inline-functions GCC option should be specified 5375 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5376 { 5377 if($Info=~/ undefined /i) { 5378 return 0; 5379 } 5380 } 5381 return 1; 5382} 5383 5384sub hasThrow($) 5385{ 5386 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5387 { 5388 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5389 return getTreeAttr_Unql($1, "unql"); 5390 } 5391 } 5392 return 1; 5393} 5394 5395sub getTypeId($) 5396{ 5397 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5398 { 5399 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5400 return $1; 5401 } 5402 } 5403 return ""; 5404} 5405 5406sub setTypeMemb($$) 5407{ 5408 my ($TypeId, $TypeAttr) = @_; 5409 my $TypeType = $TypeAttr->{"Type"}; 5410 my ($Pos, $UnnamedPos) = (0, 0); 5411 my $StaticFields = 0; 5412 if($TypeType eq "Enum") 5413 { 5414 my $MInfoId = getTreeAttr_Csts($TypeId); 5415 while($MInfoId) 5416 { 5417 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId); 5418 my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId)); 5419 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName; 5420 $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName; 5421 $MInfoId = getNextElem($MInfoId); 5422 $Pos += 1; 5423 } 5424 } 5425 elsif($TypeType=~/\A(Struct|Class|Union)\Z/) 5426 { 5427 my $MInfoId = getTreeAttr_Flds($TypeId); 5428 while($MInfoId) 5429 { 5430 my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId}; 5431 my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId}; 5432 if(not $IType or $IType ne "field_decl") 5433 { # search for fields, skip other stuff in the declaration 5434 5435 if($IType eq "var_decl") 5436 { # static field 5437 $StaticFields = 1; 5438 } 5439 5440 $MInfoId = getNextElem($MInfoId); 5441 next; 5442 } 5443 my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId)); 5444 if(index($StructMembName, "_vptr.")==0) 5445 { # virtual tables 5446 $StructMembName = "_vptr"; 5447 } 5448 if(not $StructMembName) 5449 { # unnamed fields 5450 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1) 5451 { 5452 my $UnnamedTid = getTreeAttr_Type($MInfoId); 5453 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid)); 5454 if(isAnon($UnnamedTName)) 5455 { # rename unnamed fields to unnamed0, unnamed1, ... 5456 $StructMembName = "unnamed".($UnnamedPos++); 5457 } 5458 } 5459 } 5460 if(not $StructMembName) 5461 { # unnamed fields and base classes 5462 $MInfoId = getNextElem($MInfoId); 5463 next; 5464 } 5465 my $MembTypeId = getTreeAttr_Type($MInfoId); 5466 if(defined $MissedTypedef{$Version}{$MembTypeId}) 5467 { 5468 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) { 5469 $MembTypeId = $AddedTid; 5470 } 5471 } 5472 5473 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId; 5474 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName; 5475 if((my $Access = getTreeAccess($MInfoId)) ne "public") 5476 { # marked only protected and private, public by default 5477 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access; 5478 } 5479 if($MInfo=~/spec:\s*mutable /) 5480 { # mutable fields 5481 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1; 5482 } 5483 if(my $Algn = getAlgn($MInfoId)) { 5484 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn; 5485 } 5486 if(my $BFSize = getBitField($MInfoId)) 5487 { # in bits 5488 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize; 5489 } 5490 else 5491 { # in bytes 5492 if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1) 5493 { # template 5494 delete($TypeAttr->{"Memb"}{$Pos}{"algn"}); 5495 } 5496 else { 5497 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; 5498 } 5499 } 5500 5501 $MInfoId = getNextElem($MInfoId); 5502 $Pos += 1; 5503 } 5504 } 5505 5506 return $StaticFields; 5507} 5508 5509sub setFuncParams($) 5510{ 5511 my $InfoId = $_[0]; 5512 my $ParamInfoId = getTreeAttr_Args($InfoId); 5513 5514 my $FType = getFuncType($InfoId); 5515 5516 if($FType eq "Method") 5517 { # check type of "this" pointer 5518 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId); 5519 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"}) 5520 { 5521 if($ObjectName=~/\bconst(| volatile)\*const\b/) { 5522 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5523 } 5524 if($ObjectName=~/\bvolatile\b/) { 5525 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5526 } 5527 } 5528 else 5529 { # skip 5530 return 1; 5531 } 5532 # skip "this"-parameter 5533 # $ParamInfoId = getNextElem($ParamInfoId); 5534 } 5535 my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1); 5536 while($ParamInfoId) 5537 { # formal args 5538 my $ParamTypeId = getTreeAttr_Type($ParamInfoId); 5539 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId)); 5540 if(not $ParamName) 5541 { # unnamed 5542 $ParamName = "p".($PPos+1); 5543 } 5544 if(defined $MissedTypedef{$Version}{$ParamTypeId}) 5545 { 5546 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) { 5547 $ParamTypeId = $AddedTid; 5548 } 5549 } 5550 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"}; 5551 if(not $PType or $PType eq "Unknown") { 5552 return 1; 5553 } 5554 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"}; 5555 if(not $PTName) { 5556 return 1; 5557 } 5558 if($PTName eq "void") { 5559 last; 5560 } 5561 if($ParamName eq "__vtt_parm" 5562 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**") 5563 { 5564 $Vtt_Pos = $Pos; 5565 $ParamInfoId = getNextElem($ParamInfoId); 5566 next; 5567 } 5568 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5569 5570 if(my %Base = get_BaseType($ParamTypeId, $Version)) 5571 { 5572 if(defined $Base{"Template"}) { 5573 return 1; 5574 } 5575 } 5576 5577 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName; 5578 if(my $Algn = getAlgn($ParamInfoId)) { 5579 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE; 5580 } 5581 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /) 5582 { # foo(register type arg) 5583 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1; 5584 } 5585 $ParamInfoId = getNextElem($ParamInfoId); 5586 $Pos += 1; 5587 if($ParamName ne "this" or $FType ne "Method") { 5588 $PPos += 1; 5589 } 5590 } 5591 if(setFuncArgs($InfoId, $Vtt_Pos)) { 5592 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1"; 5593 } 5594 return 0; 5595} 5596 5597sub setFuncArgs($$) 5598{ 5599 my ($InfoId, $Vtt_Pos) = @_; 5600 my $FuncTypeId = getFuncTypeId($InfoId); 5601 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId); 5602 my $FType = getFuncType($InfoId); 5603 5604 if($FType eq "Method") 5605 { 5606 # skip "this"-parameter 5607 # $ParamListElemId = getNextElem($ParamListElemId); 5608 } 5609 if(not $ParamListElemId) 5610 { # foo(...) 5611 return 1; 5612 } 5613 my $HaveVoid = 0; 5614 my ($Pos, $PPos) = (0, 0); 5615 while($ParamListElemId) 5616 { # actual params: may differ from formal args 5617 # formal int*const 5618 # actual: int* 5619 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos) 5620 { 5621 $Vtt_Pos=-1; 5622 $ParamListElemId = getNextElem($ParamListElemId); 5623 next; 5624 } 5625 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId); 5626 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void") 5627 { 5628 $HaveVoid = 1; 5629 last; 5630 } 5631 else 5632 { 5633 if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5634 { 5635 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5636 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) 5637 { # unnamed 5638 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1); 5639 } 5640 } 5641 elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5642 { 5643 if($Pos>0 or getFuncType($InfoId) ne "Method") 5644 { # params 5645 if($OldId ne $ParamTypeId) 5646 { 5647 my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version}); 5648 my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version}); 5649 5650 if($Old_Pure{"Name"} ne $New_Pure{"Name"}) { 5651 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5652 } 5653 } 5654 } 5655 } 5656 } 5657 if(my $PurpId = getTreeAttr_Purp($ParamListElemId)) 5658 { # default arguments 5659 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) 5660 { 5661 if($PurpType eq "nop_expr") 5662 { # func ( const char* arg = (const char*)(void*)0 ) 5663 $PurpId = getTreeAttr_Op($PurpId); 5664 } 5665 my $Val = getInitVal($PurpId, $ParamTypeId); 5666 if(defined $Val) { 5667 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val; 5668 } 5669 } 5670 } 5671 $ParamListElemId = getNextElem($ParamListElemId); 5672 if($Pos!=0 or $FType ne "Method") { 5673 $PPos += 1; 5674 } 5675 $Pos += 1; 5676 } 5677 return ($Pos>=1 and not $HaveVoid); 5678} 5679 5680sub getTreeAttr_Chan($) 5681{ 5682 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5683 { 5684 if($Info=~/chan[ ]*:[ ]*@(\d+) /) { 5685 return $1; 5686 } 5687 } 5688 return ""; 5689} 5690 5691sub getTreeAttr_Chain($) 5692{ 5693 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5694 { 5695 if($Info=~/chain[ ]*:[ ]*@(\d+) /) { 5696 return $1; 5697 } 5698 } 5699 return ""; 5700} 5701 5702sub getTreeAttr_Unql($) 5703{ 5704 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5705 { 5706 if($Info=~/unql[ ]*:[ ]*@(\d+) /) { 5707 return $1; 5708 } 5709 } 5710 return ""; 5711} 5712 5713sub getTreeAttr_Scpe($) 5714{ 5715 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5716 { 5717 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) { 5718 return $1; 5719 } 5720 } 5721 return ""; 5722} 5723 5724sub getTreeAttr_Type($) 5725{ 5726 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5727 { 5728 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5729 return $1; 5730 } 5731 } 5732 return ""; 5733} 5734 5735sub getTreeAttr_Name($) 5736{ 5737 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5738 { 5739 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 5740 return $1; 5741 } 5742 } 5743 return ""; 5744} 5745 5746sub getTreeAttr_Mngl($) 5747{ 5748 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5749 { 5750 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) { 5751 return $1; 5752 } 5753 } 5754 return ""; 5755} 5756 5757sub getTreeAttr_Prms($) 5758{ 5759 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5760 { 5761 if($Info=~/prms[ ]*:[ ]*@(\d+) /) { 5762 return $1; 5763 } 5764 } 5765 return ""; 5766} 5767 5768sub getTreeAttr_Fncs($) 5769{ 5770 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5771 { 5772 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) { 5773 return $1; 5774 } 5775 } 5776 return ""; 5777} 5778 5779sub getTreeAttr_Csts($) 5780{ 5781 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5782 { 5783 if($Info=~/csts[ ]*:[ ]*@(\d+) /) { 5784 return $1; 5785 } 5786 } 5787 return ""; 5788} 5789 5790sub getTreeAttr_Purp($) 5791{ 5792 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5793 { 5794 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 5795 return $1; 5796 } 5797 } 5798 return ""; 5799} 5800 5801sub getTreeAttr_Op($) 5802{ 5803 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5804 { 5805 if($Info=~/op 0[ ]*:[ ]*@(\d+) /) { 5806 return $1; 5807 } 5808 } 5809 return ""; 5810} 5811 5812sub getTreeAttr_Valu($) 5813{ 5814 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5815 { 5816 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 5817 return $1; 5818 } 5819 } 5820 return ""; 5821} 5822 5823sub getTreeAttr_Flds($) 5824{ 5825 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5826 { 5827 if($Info=~/flds[ ]*:[ ]*@(\d+) /) { 5828 return $1; 5829 } 5830 } 5831 return ""; 5832} 5833 5834sub getTreeAttr_Binf($) 5835{ 5836 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5837 { 5838 if($Info=~/binf[ ]*:[ ]*@(\d+) /) { 5839 return $1; 5840 } 5841 } 5842 return ""; 5843} 5844 5845sub getTreeAttr_Args($) 5846{ 5847 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5848 { 5849 if($Info=~/args[ ]*:[ ]*@(\d+) /) { 5850 return $1; 5851 } 5852 } 5853 return ""; 5854} 5855 5856sub getTreeValue($) 5857{ 5858 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5859 { 5860 if($Info=~/(low|int)[ ]*:[ ]*([^ ]+) /) { 5861 return $2; 5862 } 5863 } 5864 return ""; 5865} 5866 5867sub getTreeAccess($) 5868{ 5869 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5870 { 5871 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /) 5872 { 5873 my $Access = $1; 5874 if($Access eq "prot") { 5875 return "protected"; 5876 } 5877 elsif($Access eq "priv") { 5878 return "private"; 5879 } 5880 } 5881 elsif($Info=~/ protected /) 5882 { # support for old GCC versions 5883 return "protected"; 5884 } 5885 elsif($Info=~/ private /) 5886 { # support for old GCC versions 5887 return "private"; 5888 } 5889 } 5890 return "public"; 5891} 5892 5893sub setFuncAccess($) 5894{ 5895 my $Access = getTreeAccess($_[0]); 5896 if($Access eq "protected") { 5897 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1; 5898 } 5899 elsif($Access eq "private") { 5900 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1; 5901 } 5902} 5903 5904sub setTypeAccess($$) 5905{ 5906 my ($TypeId, $TypeAttr) = @_; 5907 my $Access = getTreeAccess($TypeId); 5908 if($Access eq "protected") { 5909 $TypeAttr->{"Protected"} = 1; 5910 } 5911 elsif($Access eq "private") { 5912 $TypeAttr->{"Private"} = 1; 5913 } 5914} 5915 5916sub setFuncKind($) 5917{ 5918 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5919 { 5920 if($Info=~/pseudo tmpl/) { 5921 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1; 5922 } 5923 elsif($Info=~/ constructor /) { 5924 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1; 5925 } 5926 elsif($Info=~/ destructor /) { 5927 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1; 5928 } 5929 } 5930} 5931 5932sub getVirtSpec($) 5933{ 5934 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5935 { 5936 if($Info=~/spec[ ]*:[ ]*pure /) { 5937 return "PureVirt"; 5938 } 5939 elsif($Info=~/spec[ ]*:[ ]*virt /) { 5940 return "Virt"; 5941 } 5942 elsif($Info=~/ pure\s+virtual /) 5943 { # support for old GCC versions 5944 return "PureVirt"; 5945 } 5946 elsif($Info=~/ virtual /) 5947 { # support for old GCC versions 5948 return "Virt"; 5949 } 5950 } 5951 return ""; 5952} 5953 5954sub getFuncLink($) 5955{ 5956 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5957 { 5958 if($Info=~/link[ ]*:[ ]*static /) { 5959 return "Static"; 5960 } 5961 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) { 5962 return $1; 5963 } 5964 } 5965 return ""; 5966} 5967 5968sub select_Symbol_NS($$) 5969{ 5970 my ($Symbol, $LibVersion) = @_; 5971 return "" if(not $Symbol or not $LibVersion); 5972 my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 5973 if(not $NS) 5974 { 5975 if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { 5976 $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"}; 5977 } 5978 } 5979 if($NS) 5980 { 5981 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5982 return $NS; 5983 } 5984 else 5985 { 5986 while($NS=~s/::[^:]+\Z//) 5987 { 5988 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5989 return $NS; 5990 } 5991 } 5992 } 5993 } 5994 5995 return ""; 5996} 5997 5998sub select_Type_NS($$) 5999{ 6000 my ($TypeName, $LibVersion) = @_; 6001 return "" if(not $TypeName or not $LibVersion); 6002 if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"}) 6003 { 6004 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 6005 return $NS; 6006 } 6007 else 6008 { 6009 while($NS=~s/::[^:]+\Z//) 6010 { 6011 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 6012 return $NS; 6013 } 6014 } 6015 } 6016 } 6017 return ""; 6018} 6019 6020sub getNameSpace($) 6021{ 6022 my $InfoId = $_[0]; 6023 if(my $NSInfoId = getTreeAttr_Scpe($InfoId)) 6024 { 6025 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 6026 { 6027 if($InfoType eq "namespace_decl") 6028 { 6029 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /) 6030 { 6031 my $NameSpace = getTreeStr($1); 6032 if($NameSpace eq "::") 6033 { # global namespace 6034 return ""; 6035 } 6036 if(my $BaseNameSpace = getNameSpace($NSInfoId)) { 6037 $NameSpace = $BaseNameSpace."::".$NameSpace; 6038 } 6039 $NestedNameSpaces{$Version}{$NameSpace} = 1; 6040 return $NameSpace; 6041 } 6042 else { 6043 return ""; 6044 } 6045 } 6046 elsif($InfoType ne "function_decl") 6047 { # inside data type 6048 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId); 6049 return $Name; 6050 } 6051 } 6052 } 6053 return ""; 6054} 6055 6056sub getEnumMembVal($) 6057{ 6058 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6059 { 6060 if($Info=~/valu[ ]*:[ ]*\@(\d+)/) 6061 { 6062 if(my $VInfo = $LibInfo{$Version}{"info"}{$1}) 6063 { 6064 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/) 6065 { # in newer versions of GCC the value is in the "const_decl->cnst" node 6066 return getTreeValue($1); 6067 } 6068 else 6069 { # some old versions of GCC (3.3) have the value in the "integer_cst" node 6070 return getTreeValue($1); 6071 } 6072 } 6073 } 6074 } 6075 return ""; 6076} 6077 6078sub getSize($) 6079{ 6080 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6081 { 6082 if($Info=~/size[ ]*:[ ]*\@(\d+)/) { 6083 return getTreeValue($1); 6084 } 6085 } 6086 return 0; 6087} 6088 6089sub getAlgn($) 6090{ 6091 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6092 { 6093 if($Info=~/algn[ ]*:[ ]*(\d+) /) { 6094 return $1; 6095 } 6096 } 6097 return ""; 6098} 6099 6100sub getBitField($) 6101{ 6102 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6103 { 6104 if($Info=~/ bitfield /) { 6105 return getSize($_[0]); 6106 } 6107 } 6108 return 0; 6109} 6110 6111sub getNextElem($) 6112{ 6113 if(my $Chan = getTreeAttr_Chan($_[0])) { 6114 return $Chan; 6115 } 6116 elsif(my $Chain = getTreeAttr_Chain($_[0])) { 6117 return $Chain; 6118 } 6119 return ""; 6120} 6121 6122sub registerHeader($$) 6123{ # input: absolute path of header, relative path or name 6124 my ($Header, $LibVersion) = @_; 6125 if(not $Header) { 6126 return ""; 6127 } 6128 if(is_abs($Header) and not -f $Header) 6129 { # incorrect absolute path 6130 exitStatus("Access_Error", "can't access \'$Header\'"); 6131 } 6132 if(skipHeader($Header, $LibVersion)) 6133 { # skip 6134 return ""; 6135 } 6136 if(my $Header_Path = identifyHeader($Header, $LibVersion)) 6137 { 6138 detect_header_includes($Header_Path, $LibVersion); 6139 6140 if(defined $Tolerance and $Tolerance=~/3/) 6141 { # 3 - skip headers that include non-Linux headers 6142 if($OSgroup ne "windows") 6143 { 6144 foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}})) 6145 { 6146 if(specificHeader($Inc, "windows")) { 6147 return ""; 6148 } 6149 } 6150 } 6151 } 6152 6153 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path}) 6154 { # redirect 6155 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"} 6156 or skipHeader($RHeader_Path, $LibVersion)) 6157 { # skip 6158 return ""; 6159 } 6160 $Header_Path = $RHeader_Path; 6161 } 6162 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) 6163 { # skip 6164 return ""; 6165 } 6166 6167 if(my $HName = get_filename($Header_Path)) 6168 { # register 6169 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName; 6170 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1; 6171 } 6172 6173 if(($Header=~/\.(\w+)\Z/ and $1 ne "h") 6174 or $Header!~/\.(\w+)\Z/) 6175 { # hpp, hh, etc. 6176 setLanguage($LibVersion, "C++"); 6177 $CPP_HEADERS = 1; 6178 } 6179 6180 if($CheckHeadersOnly 6181 and $Header=~/(\A|\/)c\+\+(\/|\Z)/) 6182 { # /usr/include/c++/4.6.1/... 6183 $STDCXX_TESTING = 1; 6184 } 6185 6186 return $Header_Path; 6187 } 6188 return ""; 6189} 6190 6191sub registerDir($$$) 6192{ 6193 my ($Dir, $WithDeps, $LibVersion) = @_; 6194 $Dir=~s/[\/\\]+\Z//g; 6195 return if(not $LibVersion or not $Dir or not -d $Dir); 6196 $Dir = get_abs_path($Dir); 6197 6198 my $Mode = "All"; 6199 if($WithDeps) 6200 { 6201 if($RegisteredDirs{$LibVersion}{$Dir}{1}) { 6202 return; 6203 } 6204 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) { 6205 $Mode = "DepsOnly"; 6206 } 6207 } 6208 else 6209 { 6210 if($RegisteredDirs{$LibVersion}{$Dir}{1} 6211 or $RegisteredDirs{$LibVersion}{$Dir}{0}) { 6212 return; 6213 } 6214 } 6215 $Header_Dependency{$LibVersion}{$Dir} = 1; 6216 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1; 6217 if($Mode eq "DepsOnly") 6218 { 6219 foreach my $Path (cmd_find($Dir,"d")) { 6220 $Header_Dependency{$LibVersion}{$Path} = 1; 6221 } 6222 return; 6223 } 6224 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f")) 6225 { 6226 if($WithDeps) 6227 { 6228 my $SubDir = $Path; 6229 while(($SubDir = get_dirname($SubDir)) ne $Dir) 6230 { # register all sub directories 6231 $Header_Dependency{$LibVersion}{$SubDir} = 1; 6232 } 6233 } 6234 next if(is_not_header($Path)); 6235 next if(ignore_path($Path)); 6236 # Neighbors 6237 foreach my $Part (get_prefixes($Path)) { 6238 $Include_Neighbors{$LibVersion}{$Part} = $Path; 6239 } 6240 } 6241 if(get_filename($Dir) eq "include") 6242 { # search for "lib/include/" directory 6243 my $LibDir = $Dir; 6244 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) { 6245 registerDir($LibDir, $WithDeps, $LibVersion); 6246 } 6247 } 6248} 6249 6250sub parse_redirect($$$) 6251{ 6252 my ($Content, $Path, $LibVersion) = @_; 6253 my @Errors = (); 6254 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) { 6255 push(@Errors, $1); 6256 } 6257 my $Redirect = ""; 6258 foreach (@Errors) 6259 { 6260 s/\s{2,}/ /g; 6261 if(/(only|must\ include 6262 |update\ to\ include 6263 |replaced\ with 6264 |replaced\ by|renamed\ to 6265 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix) 6266 { 6267 $Redirect = $2; 6268 last; 6269 } 6270 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i) 6271 { 6272 $Redirect = $2; 6273 last; 6274 } 6275 elsif(/this\ header\ should\ not\ be\ used 6276 |programs\ should\ not\ directly\ include 6277 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header)) 6278 |is\ not\ supported\ API\ for\ general\ use 6279 |do\ not\ use 6280 |should\ not\ be\ (used|using) 6281 |cannot\ be\ included\ directly/ix and not /\ from\ /i) { 6282 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6283 } 6284 } 6285 if($Redirect) 6286 { 6287 $Redirect=~s/\A<//g; 6288 $Redirect=~s/>\Z//g; 6289 } 6290 return $Redirect; 6291} 6292 6293sub parse_includes($$) 6294{ 6295 my ($Content, $Path) = @_; 6296 my %Includes = (); 6297 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m) 6298 { # C/C++: include, Objective C/C++: import directive 6299 my $Header = $2; 6300 my $Method = substr($Header, 0, 1, ""); 6301 substr($Header, length($Header)-1, 1, ""); 6302 $Header = path_format($Header, $OSgroup); 6303 if($Method eq "\"" or is_abs($Header)) 6304 { 6305 if(-e join_P(get_dirname($Path), $Header)) 6306 { # relative path exists 6307 $Includes{$Header} = -1; 6308 } 6309 else 6310 { # include "..." that doesn't exist is equal to include <...> 6311 $Includes{$Header} = 2; 6312 } 6313 } 6314 else { 6315 $Includes{$Header} = 1; 6316 } 6317 } 6318 if($ExtraInfo) 6319 { 6320 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m) 6321 { # FT_FREETYPE_H 6322 $Includes{$2} = 0; 6323 } 6324 } 6325 return \%Includes; 6326} 6327 6328sub ignore_path($) 6329{ 6330 my $Path = $_[0]; 6331 if($Path=~/\~\Z/) 6332 {# skipping system backup files 6333 return 1; 6334 } 6335 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/) 6336 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories 6337 return 1; 6338 } 6339 return 0; 6340} 6341 6342sub sortByWord($$) 6343{ 6344 my ($ArrRef, $W) = @_; 6345 return if(length($W)<2); 6346 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef}; 6347} 6348 6349sub sortHeaders($$) 6350{ 6351 my ($H1, $H2) = @_; 6352 6353 $H1=~s/\.[a-z]+\Z//ig; 6354 $H2=~s/\.[a-z]+\Z//ig; 6355 6356 my $Hname1 = get_filename($H1); 6357 my $Hname2 = get_filename($H2); 6358 my $HDir1 = get_dirname($H1); 6359 my $HDir2 = get_dirname($H2); 6360 my $Dirname1 = get_filename($HDir1); 6361 my $Dirname2 = get_filename($HDir2); 6362 6363 $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6364 $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6365 6366 if($_[0] eq $_[1] 6367 or $H1 eq $H2) { 6368 return 0; 6369 } 6370 elsif($H1=~/\A\Q$H2\E/) { 6371 return 1; 6372 } 6373 elsif($H2=~/\A\Q$H1\E/) { 6374 return -1; 6375 } 6376 elsif($HDir1=~/\Q$Hname1\E/i 6377 and $HDir2!~/\Q$Hname2\E/i) 6378 { # include/glib-2.0/glib.h 6379 return -1; 6380 } 6381 elsif($HDir2=~/\Q$Hname2\E/i 6382 and $HDir1!~/\Q$Hname1\E/i) 6383 { # include/glib-2.0/glib.h 6384 return 1; 6385 } 6386 elsif($Hname1=~/\Q$Dirname1\E/i 6387 and $Hname2!~/\Q$Dirname2\E/i) 6388 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6389 return -1; 6390 } 6391 elsif($Hname2=~/\Q$Dirname2\E/i 6392 and $Hname1!~/\Q$Dirname1\E/i) 6393 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6394 return 1; 6395 } 6396 elsif($Hname1=~/(config|lib|util)/i 6397 and $Hname2!~/(config|lib|util)/i) 6398 { # include/alsa/asoundlib.h 6399 return -1; 6400 } 6401 elsif($Hname2=~/(config|lib|util)/i 6402 and $Hname1!~/(config|lib|util)/i) 6403 { # include/alsa/asoundlib.h 6404 return 1; 6405 } 6406 else 6407 { 6408 my $R1 = checkRelevance($H1); 6409 my $R2 = checkRelevance($H2); 6410 if($R1 and not $R2) 6411 { # libebook/e-book.h 6412 return -1; 6413 } 6414 elsif($R2 and not $R1) 6415 { # libebook/e-book.h 6416 return 1; 6417 } 6418 else 6419 { 6420 return (lc($H1) cmp lc($H2)); 6421 } 6422 } 6423} 6424 6425sub searchForHeaders($) 6426{ 6427 my $LibVersion = $_[0]; 6428 6429 # gcc standard include paths 6430 registerGccHeaders(); 6431 6432 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING) 6433 { # c++ standard include paths 6434 registerCppHeaders(); 6435 } 6436 6437 # processing header paths 6438 foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}}, 6439 @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) 6440 { 6441 my $IPath = $Path; 6442 if($SystemRoot) 6443 { 6444 if(is_abs($Path)) { 6445 $Path = $SystemRoot.$Path; 6446 } 6447 } 6448 if(not -e $Path) { 6449 exitStatus("Access_Error", "can't access \'$Path\'"); 6450 } 6451 elsif(-f $Path) { 6452 exitStatus("Access_Error", "\'$Path\' - not a directory"); 6453 } 6454 elsif(-d $Path) 6455 { 6456 $Path = get_abs_path($Path); 6457 registerDir($Path, 0, $LibVersion); 6458 if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) { 6459 push(@{$Add_Include_Paths{$LibVersion}}, $Path); 6460 } 6461 else { 6462 push(@{$Include_Paths{$LibVersion}}, $Path); 6463 } 6464 } 6465 } 6466 if(@{$Include_Paths{$LibVersion}}) { 6467 $INC_PATH_AUTODETECT{$LibVersion} = 0; 6468 } 6469 6470 # registering directories 6471 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6472 { 6473 next if(not -e $Path); 6474 $Path = get_abs_path($Path); 6475 $Path = path_format($Path, $OSgroup); 6476 if(-d $Path) { 6477 registerDir($Path, 1, $LibVersion); 6478 } 6479 elsif(-f $Path) 6480 { 6481 my $Dir = get_dirname($Path); 6482 if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}}) 6483 and not $LocalIncludes{$Dir}) 6484 { 6485 registerDir($Dir, 1, $LibVersion); 6486 # if(my $OutDir = get_dirname($Dir)) 6487 # { # registering the outer directory 6488 # if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}}) 6489 # and not $LocalIncludes{$OutDir}) { 6490 # registerDir($OutDir, 0, $LibVersion); 6491 # } 6492 # } 6493 } 6494 } 6495 } 6496 6497 # clean memory 6498 %RegisteredDirs = (); 6499 6500 # registering headers 6501 my $Position = 0; 6502 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6503 { 6504 if(is_abs($Dest) and not -e $Dest) { 6505 exitStatus("Access_Error", "can't access \'$Dest\'"); 6506 } 6507 $Dest = path_format($Dest, $OSgroup); 6508 if(is_header($Dest, 1, $LibVersion)) 6509 { 6510 if(my $HPath = registerHeader($Dest, $LibVersion)) { 6511 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++; 6512 } 6513 } 6514 elsif(-d $Dest) 6515 { 6516 my @Registered = (); 6517 foreach my $Path (cmd_find($Dest,"f")) 6518 { 6519 next if(ignore_path($Path)); 6520 next if(not is_header($Path, 0, $LibVersion)); 6521 if(my $HPath = registerHeader($Path, $LibVersion)) { 6522 push(@Registered, $HPath); 6523 } 6524 } 6525 @Registered = sort {sortHeaders($a, $b)} @Registered; 6526 sortByWord(\@Registered, $TargetLibraryShortName); 6527 foreach my $Path (@Registered) { 6528 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++; 6529 } 6530 } 6531 elsif(not defined $SkipUnidentified) { 6532 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file"); 6533 } 6534 } 6535 6536 if(defined $Tolerance and $Tolerance=~/4/) 6537 { # 4 - skip headers included by others 6538 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 6539 { 6540 if(defined $Header_Includes_R{$LibVersion}{$Path}) { 6541 delete($Registered_Headers{$LibVersion}{$Path}); 6542 } 6543 } 6544 } 6545 6546 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"}) 6547 { # preparing preamble headers 6548 foreach my $Header (split(/\s*\n\s*/, $HList)) 6549 { 6550 if(is_abs($Header) and not -f $Header) { 6551 exitStatus("Access_Error", "can't access file \'$Header\'"); 6552 } 6553 $Header = path_format($Header, $OSgroup); 6554 if(my $Header_Path = is_header($Header, 1, $LibVersion)) 6555 { 6556 next if(skipHeader($Header_Path, $LibVersion)); 6557 push_U($Include_Preamble{$LibVersion}, $Header_Path); 6558 } 6559 elsif($SkipUnidentified) { 6560 exitStatus("Access_Error", "can't identify \'$Header\' as a header file"); 6561 } 6562 } 6563 } 6564 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}})) 6565 { # set relative paths (for duplicates) 6566 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2) 6567 { # search for duplicates 6568 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0]; 6569 my $Prefix = get_dirname($FirstPath); 6570 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/) 6571 { # detect a shortest distinguishing prefix 6572 my $NewPrefix = $1; 6573 my %Identity = (); 6574 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6575 { 6576 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) { 6577 $Identity{$Path} = $1; 6578 } 6579 } 6580 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6581 { # all names are different with current prefix 6582 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { 6583 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path}; 6584 } 6585 last; 6586 } 6587 $Prefix = $NewPrefix; # increase prefix 6588 } 6589 } 6590 } 6591 6592 # clean memory 6593 %HeaderName_Paths = (); 6594 6595 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}})) 6596 { # ordering headers according to descriptor 6597 my $PairName = $Include_Order{$LibVersion}{$HeaderName}; 6598 my ($Pos, $PairPos) = (-1, -1); 6599 my ($Path, $PairPath) = (); 6600 my @Paths = keys(%{$Registered_Headers{$LibVersion}}); 6601 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths; 6602 foreach my $Header_Path (@Paths) 6603 { 6604 if(get_filename($Header_Path) eq $PairName) 6605 { 6606 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6607 $PairPath = $Header_Path; 6608 } 6609 if(get_filename($Header_Path) eq $HeaderName) 6610 { 6611 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6612 $Path = $Header_Path; 6613 } 6614 } 6615 if($PairPos!=-1 and $Pos!=-1 6616 and int($PairPos)<int($Pos)) 6617 { 6618 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}}; 6619 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}}; 6620 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp; 6621 } 6622 } 6623 if(not keys(%{$Registered_Headers{$LibVersion}})) { 6624 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"}); 6625 } 6626} 6627 6628sub detect_real_includes($$) 6629{ 6630 my ($AbsPath, $LibVersion) = @_; 6631 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath); 6632 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath} 6633 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6634 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6635 } 6636 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1; 6637 6638 my $Path = callPreprocessor($AbsPath, "", $LibVersion); 6639 return () if(not $Path); 6640 open(PREPROC, $Path); 6641 while(<PREPROC>) 6642 { 6643 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/) 6644 { 6645 my $Include = path_format($1, $OSgroup); 6646 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) { 6647 next; 6648 } 6649 if($Include eq $AbsPath) { 6650 next; 6651 } 6652 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1; 6653 } 6654 } 6655 close(PREPROC); 6656 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6657} 6658 6659sub detect_header_includes($$) 6660{ 6661 my ($Path, $LibVersion) = @_; 6662 return if(not $LibVersion or not $Path); 6663 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) { 6664 return; 6665 } 6666 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1; 6667 6668 if(not -e $Path) { 6669 return; 6670 } 6671 6672 my $Content = readFile($Path); 6673 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion)) 6674 { # detect error directive in headers 6675 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion)) 6676 { 6677 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) { 6678 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion); 6679 } 6680 if($RedirectPath ne $Path) { 6681 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath; 6682 } 6683 } 6684 else 6685 { # can't find 6686 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6687 } 6688 } 6689 if(my $Inc = parse_includes($Content, $Path)) 6690 { 6691 foreach my $Include (keys(%{$Inc})) 6692 { # detect includes 6693 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include}; 6694 6695 if(defined $Tolerance and $Tolerance=~/4/) 6696 { 6697 if(my $HPath = identifyHeader($Include, $LibVersion)) 6698 { 6699 $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1; 6700 } 6701 } 6702 } 6703 } 6704} 6705 6706sub fromLibc($) 6707{ # system GLIBC header 6708 my $Path = $_[0]; 6709 my ($Dir, $Name) = separate_path($Path); 6710 if($OStarget eq "symbian") 6711 { 6712 if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name}) 6713 { # epoc32/include/libc/{stdio, ...}.h 6714 return 1; 6715 } 6716 } 6717 else 6718 { 6719 if($Dir eq "/usr/include" and $GlibcHeader{$Name}) 6720 { # /usr/include/{stdio, ...}.h 6721 return 1; 6722 } 6723 } 6724 return 0; 6725} 6726 6727sub isLibcDir($) 6728{ # system GLIBC directory 6729 my $Dir = $_[0]; 6730 my ($OutDir, $Name) = separate_path($Dir); 6731 if($OStarget eq "symbian") 6732 { 6733 if(get_filename($OutDir) eq "libc" 6734 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6735 { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h 6736 return 1; 6737 } 6738 } 6739 else 6740 { # linux 6741 if($OutDir eq "/usr/include" 6742 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6743 { # /usr/include/{sys,bits,asm,asm-*}/*.h 6744 return 1; 6745 } 6746 } 6747 return 0; 6748} 6749 6750sub detect_recursive_includes($$) 6751{ 6752 my ($AbsPath, $LibVersion) = @_; 6753 return () if(not $AbsPath); 6754 if(isCyclical(\@RecurInclude, $AbsPath)) { 6755 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6756 } 6757 my ($AbsDir, $Name) = separate_path($AbsPath); 6758 if(isLibcDir($AbsDir)) 6759 { # system GLIBC internals 6760 return () if(not $ExtraInfo); 6761 } 6762 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6763 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6764 } 6765 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i); 6766 6767 if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING) 6768 { # skip /usr/include/c++/*/ headers 6769 return () if(not $ExtraInfo); 6770 } 6771 6772 push(@RecurInclude, $AbsPath); 6773 if(grep { $AbsDir eq $_ } @DefaultGccPaths 6774 or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath))) 6775 { # check "real" (non-"model") include paths 6776 my @Paths = detect_real_includes($AbsPath, $LibVersion); 6777 pop(@RecurInclude); 6778 return @Paths; 6779 } 6780 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) { 6781 detect_header_includes($AbsPath, $LibVersion); 6782 } 6783 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) 6784 { 6785 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include}; 6786 my $HPath = ""; 6787 if($IncType<0) 6788 { # for #include "..." 6789 my $Candidate = join_P($AbsDir, $Include); 6790 if(-f $Candidate) { 6791 $HPath = realpath_F($Candidate); 6792 } 6793 } 6794 elsif($IncType>0 6795 and $Include=~/[\/\\]/) # and not find_in_defaults($Include) 6796 { # search for the nearest header 6797 # QtCore/qabstractanimation.h includes <QtCore/qobject.h> 6798 my $Candidate = join_P(get_dirname($AbsDir), $Include); 6799 if(-f $Candidate) { 6800 $HPath = $Candidate; 6801 } 6802 } 6803 if(not $HPath) { 6804 $HPath = identifyHeader($Include, $LibVersion); 6805 } 6806 next if(not $HPath); 6807 if($HPath eq $AbsPath) { 6808 next; 6809 } 6810 6811 if($Debug) 6812 { # boundary headers 6813# if($HPath=~/vtk/ and $AbsPath!~/vtk/) 6814# { 6815# print STDERR "$AbsPath -> $HPath\n"; 6816# } 6817 } 6818 6819 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType; 6820 if($IncType>0) 6821 { # only include <...>, skip include "..." prefixes 6822 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1; 6823 } 6824 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion)) 6825 { 6826 if($IncPath eq $AbsPath) { 6827 next; 6828 } 6829 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath}; 6830 if($RIncType==-1) 6831 { # include "..." 6832 $RIncType = $IncType; 6833 } 6834 elsif($RIncType==2) 6835 { 6836 if($IncType!=-1) { 6837 $RIncType = $IncType; 6838 } 6839 } 6840 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType; 6841 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) { 6842 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1; 6843 } 6844 } 6845 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}})) 6846 { 6847 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2 6848 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}) 6849 { # distinguish math.h from glibc and math.h from the tested library 6850 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}); 6851 last; 6852 } 6853 } 6854 } 6855 pop(@RecurInclude); 6856 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6857} 6858 6859sub find_in_framework($$$) 6860{ 6861 my ($Header, $Framework, $LibVersion) = @_; 6862 return "" if(not $Header or not $Framework or not $LibVersion); 6863 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) { 6864 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}; 6865 } 6866 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}})) 6867 { 6868 if(get_filename($Dependency) eq $Framework 6869 and -f get_dirname($Dependency)."/".$Header) { 6870 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency)); 6871 } 6872 } 6873 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = ""); 6874} 6875 6876sub find_in_defaults($) 6877{ 6878 my $Header = $_[0]; 6879 return "" if(not $Header); 6880 if(defined $Cache{"find_in_defaults"}{$Header}) { 6881 return $Cache{"find_in_defaults"}{$Header}; 6882 } 6883 foreach my $Dir (@DefaultIncPaths, 6884 @DefaultGccPaths, 6885 @DefaultCppPaths, 6886 @UsersIncPath) 6887 { 6888 next if(not $Dir); 6889 if(-f $Dir."/".$Header) { 6890 return ($Cache{"find_in_defaults"}{$Header}=$Dir); 6891 } 6892 } 6893 return ($Cache{"find_in_defaults"}{$Header}=""); 6894} 6895 6896sub cmp_paths($$) 6897{ 6898 my ($Path1, $Path2) = @_; 6899 my @Parts1 = split(/[\/\\]/, $Path1); 6900 my @Parts2 = split(/[\/\\]/, $Path2); 6901 foreach my $Num (0 .. $#Parts1) 6902 { 6903 my $Part1 = $Parts1[$Num]; 6904 my $Part2 = $Parts2[$Num]; 6905 if($GlibcDir{$Part1} 6906 and not $GlibcDir{$Part2}) { 6907 return 1; 6908 } 6909 elsif($GlibcDir{$Part2} 6910 and not $GlibcDir{$Part1}) { 6911 return -1; 6912 } 6913 elsif($Part1=~/glib/ 6914 and $Part2!~/glib/) { 6915 return 1; 6916 } 6917 elsif($Part1!~/glib/ 6918 and $Part2=~/glib/) { 6919 return -1; 6920 } 6921 elsif(my $CmpRes = ($Part1 cmp $Part2)) { 6922 return $CmpRes; 6923 } 6924 } 6925 return 0; 6926} 6927 6928sub checkRelevance($) 6929{ 6930 my $Path = $_[0]; 6931 return 0 if(not $Path); 6932 6933 if($SystemRoot) { 6934 $Path = cut_path_prefix($Path, $SystemRoot); 6935 } 6936 6937 my $Name = lc(get_filename($Path)); 6938 my $Dir = lc(get_dirname($Path)); 6939 6940 $Name=~s/\.\w+\Z//g; # remove extension (.h) 6941 6942 foreach my $Token (split(/[_\d\W]+/, $Name)) 6943 { 6944 my $Len = length($Token); 6945 next if($Len<=1); 6946 if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/) 6947 { # include/evolution-data-server-1.4/libebook/e-book.h 6948 return 1; 6949 } 6950 if($Len>=4 and index($Dir, $Token)!=-1) 6951 { # include/gupnp-1.0/libgupnp/gupnp-context.h 6952 return 1; 6953 } 6954 } 6955 return 0; 6956} 6957 6958sub checkFamily(@) 6959{ 6960 my @Paths = @_; 6961 return 1 if($#Paths<=0); 6962 my %Prefix = (); 6963 foreach my $Path (@Paths) 6964 { 6965 if($SystemRoot) { 6966 $Path = cut_path_prefix($Path, $SystemRoot); 6967 } 6968 if(my $Dir = get_dirname($Path)) 6969 { 6970 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix 6971 $Prefix{$Dir} += 1; 6972 $Prefix{get_dirname($Dir)} += 1; 6973 } 6974 } 6975 foreach (sort keys(%Prefix)) 6976 { 6977 if(get_depth($_)>=3 6978 and $Prefix{$_}==$#Paths+1) { 6979 return 1; 6980 } 6981 } 6982 return 0; 6983} 6984 6985sub isAcceptable($$$) 6986{ 6987 my ($Header, $Candidate, $LibVersion) = @_; 6988 my $HName = get_filename($Header); 6989 if(get_dirname($Header)) 6990 { # with prefix 6991 return 1; 6992 } 6993 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/) 6994 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/ 6995 return 1; 6996 } 6997 if(checkRelevance($Candidate)) 6998 { # allow to search for atk.h in /usr/include/atk-1.0/atk/ 6999 return 1; 7000 } 7001 if(checkFamily(getSystemHeaders($HName, $LibVersion))) 7002 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h 7003 # /usr/include/qt4/Qt/qsslconfiguration.h 7004 return 1; 7005 } 7006 if($OStarget eq "symbian") 7007 { 7008 if($Candidate=~/[\/\\]stdapis[\/\\]/) { 7009 return 1; 7010 } 7011 } 7012 return 0; 7013} 7014 7015sub isRelevant($$$) 7016{ # disallow to search for "abstract" headers in too deep directories 7017 my ($Header, $Candidate, $LibVersion) = @_; 7018 my $HName = get_filename($Header); 7019 if($OStarget eq "symbian") 7020 { 7021 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) { 7022 return 0; 7023 } 7024 } 7025 if($OStarget ne "bsd") 7026 { 7027 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/) 7028 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h 7029 return 0; 7030 } 7031 } 7032 if($OStarget ne "windows") 7033 { 7034 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/) 7035 { # skip /usr/include/wine/msvcrt 7036 return 0; 7037 } 7038 } 7039 if(not get_dirname($Header) 7040 and $Candidate=~/[\/\\]wx[\/\\]/) 7041 { # do NOT search in system /wx/ directory 7042 # for headers without a prefix: sstream.h 7043 return 0; 7044 } 7045 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR 7046 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/) 7047 { # skip ../c++/3.3.3/ if using ../c++/4.5/ 7048 return 0; 7049 } 7050 if($Candidate=~/[\/\\]asm-/ 7051 and (my $Arch = getArch($LibVersion)) ne "unknown") 7052 { # arch-specific header files 7053 if($Candidate!~/[\/\\]asm-\Q$Arch\E/) 7054 {# skip ../asm-arm/ if using x86 architecture 7055 return 0; 7056 } 7057 } 7058 my @Candidates = getSystemHeaders($HName, $LibVersion); 7059 if($#Candidates==1) 7060 { # unique header 7061 return 1; 7062 } 7063 my @SCandidates = getSystemHeaders($Header, $LibVersion); 7064 if($#SCandidates==1) 7065 { # unique name 7066 return 1; 7067 } 7068 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0; 7069 if(get_depth($Candidate)-$SystemDepth>=5) 7070 { # abstract headers in too deep directories 7071 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/ 7072 if(not isAcceptable($Header, $Candidate, $LibVersion)) { 7073 return 0; 7074 } 7075 } 7076 if($Header eq "parser.h" 7077 and $Candidate!~/\/libxml2\//) 7078 { # select parser.h from xml2 library 7079 return 0; 7080 } 7081 if(not get_dirname($Header) 7082 and keys(%{$SystemHeaders{$HName}})>=3) 7083 { # many headers with the same name 7084 # like thread.h included without a prefix 7085 if(not checkFamily(@Candidates)) { 7086 return 0; 7087 } 7088 } 7089 return 1; 7090} 7091 7092sub selectSystemHeader($$) 7093{ # cache function 7094 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) { 7095 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}; 7096 } 7097 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_)); 7098} 7099 7100sub selectSystemHeader_I($$) 7101{ 7102 my ($Header, $LibVersion) = @_; 7103 if(-f $Header) { 7104 return $Header; 7105 } 7106 if(is_abs($Header) and not -f $Header) 7107 { # incorrect absolute path 7108 return ""; 7109 } 7110 if(defined $ConfHeaders{lc($Header)}) 7111 { # too abstract configuration headers 7112 return ""; 7113 } 7114 my $HName = get_filename($Header); 7115 if($OSgroup ne "windows") 7116 { 7117 if(defined $WinHeaders{lc($HName)} 7118 or $HName=~/windows|win32|win64/i) 7119 { # windows headers 7120 return ""; 7121 } 7122 } 7123 if($OSgroup ne "macos") 7124 { 7125 if($HName eq "fp.h") 7126 { # pngconf.h includes fp.h in Mac OS 7127 return ""; 7128 } 7129 } 7130 7131 if(defined $ObsoleteHeaders{$HName}) 7132 { # obsolete headers 7133 return ""; 7134 } 7135 if($OSgroup eq "linux" or $OSgroup eq "bsd") 7136 { 7137 if(defined $AlienHeaders{$HName} 7138 or defined $AlienHeaders{$Header}) 7139 { # alien headers from other systems 7140 return ""; 7141 } 7142 } 7143 7144 foreach my $Path (@{$SystemPaths{"include"}}) 7145 { # search in default paths 7146 if(-f $Path."/".$Header) { 7147 return join_P($Path,$Header); 7148 } 7149 } 7150 if(not defined $Cache{"checkSystemFiles"}) 7151 { # register all headers in system include dirs 7152 checkSystemFiles(); 7153 } 7154 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)} 7155 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion)) 7156 { 7157 if(isRelevant($Header, $Candidate, $LibVersion)) { 7158 return $Candidate; 7159 } 7160 } 7161 # error 7162 return ""; 7163} 7164 7165sub getSystemHeaders($$) 7166{ 7167 my ($Header, $LibVersion) = @_; 7168 my @Candidates = (); 7169 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}})) 7170 { 7171 if(skipHeader($Candidate, $LibVersion)) { 7172 next; 7173 } 7174 push(@Candidates, $Candidate); 7175 } 7176 return @Candidates; 7177} 7178 7179sub cut_path_prefix($$) 7180{ 7181 my ($Path, $Prefix) = @_; 7182 return $Path if(not $Prefix); 7183 $Prefix=~s/[\/\\]+\Z//; 7184 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//; 7185 return $Path; 7186} 7187 7188sub is_default_include_dir($) 7189{ 7190 my $Dir = $_[0]; 7191 $Dir=~s/[\/\\]+\Z//; 7192 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths); 7193} 7194 7195sub identifyHeader($$) 7196{ # cache function 7197 my ($Header, $LibVersion) = @_; 7198 if(not $Header) { 7199 return ""; 7200 } 7201 $Header=~s/\A(\.\.[\\\/])+//g; 7202 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) { 7203 return $Cache{"identifyHeader"}{$LibVersion}{$Header}; 7204 } 7205 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion)); 7206} 7207 7208sub identifyHeader_I($$) 7209{ # search for header by absolute path, relative path or name 7210 my ($Header, $LibVersion) = @_; 7211 if(-f $Header) 7212 { # it's relative or absolute path 7213 return get_abs_path($Header); 7214 } 7215 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING 7216 and my $HeaderDir = find_in_defaults($Header)) 7217 { # search for libc headers in the /usr/include 7218 # for non-libc target library before searching 7219 # in the library paths 7220 return join_P($HeaderDir,$Header); 7221 } 7222 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header}) 7223 { # search in the target library paths 7224 return $Path; 7225 } 7226 elsif(defined $DefaultGccHeader{$Header}) 7227 { # search in the internal GCC include paths 7228 return $DefaultGccHeader{$Header}; 7229 } 7230 elsif(my $DefaultDir = find_in_defaults($Header)) 7231 { # search in the default GCC include paths 7232 return join_P($DefaultDir,$Header); 7233 } 7234 elsif(defined $DefaultCppHeader{$Header}) 7235 { # search in the default G++ include paths 7236 return $DefaultCppHeader{$Header}; 7237 } 7238 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion)) 7239 { # search everywhere in the system 7240 return $AnyPath; 7241 } 7242 elsif($OSgroup eq "macos") 7243 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h" 7244 if(my $Dir = get_dirname($Header)) 7245 { 7246 my $RelPath = "Headers\/".get_filename($Header); 7247 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) { 7248 return join_P($HeaderDir, $RelPath); 7249 } 7250 } 7251 } 7252 # cannot find anything 7253 return ""; 7254} 7255 7256sub getLocation($) 7257{ 7258 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7259 { 7260 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) { 7261 return (path_format($1, $OSgroup), $2); 7262 } 7263 } 7264 return (); 7265} 7266 7267sub getNameByInfo($) 7268{ 7269 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7270 { 7271 if($Info=~/name[ ]*:[ ]*@(\d+) /) 7272 { 7273 if(my $NInfo = $LibInfo{$Version}{"info"}{$1}) 7274 { 7275 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/) 7276 { # short unsigned int (may include spaces) 7277 my $Str = $1; 7278 if($CppMode{$Version} 7279 and $Str=~/\Ac99_(.+)\Z/) 7280 { 7281 if($CppKeywords_A{$1}) { 7282 $Str=$1; 7283 } 7284 } 7285 return $Str; 7286 } 7287 } 7288 } 7289 } 7290 return ""; 7291} 7292 7293sub getTreeStr($) 7294{ 7295 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7296 { 7297 if($Info=~/strg[ ]*:[ ]*([^ ]*)/) 7298 { 7299 my $Str = $1; 7300 if($CppMode{$Version} 7301 and $Str=~/\Ac99_(.+)\Z/) 7302 { 7303 if($CppKeywords_A{$1}) { 7304 $Str=$1; 7305 } 7306 } 7307 return $Str; 7308 } 7309 } 7310 return ""; 7311} 7312 7313sub getFuncShortName($) 7314{ 7315 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7316 { 7317 if(index($Info, " operator ")!=-1) 7318 { 7319 if(index($Info, " conversion ")!=-1) 7320 { 7321 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"}) 7322 { 7323 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) { 7324 return "operator ".$RName; 7325 } 7326 } 7327 } 7328 else 7329 { 7330 if($Info=~/ operator[ ]+([a-zA-Z]+) /) 7331 { 7332 if(my $Ind = $Operator_Indication{$1}) { 7333 return "operator".$Ind; 7334 } 7335 elsif(not $UnknownOperator{$1}) 7336 { 7337 printMsg("WARNING", "unknown operator $1"); 7338 $UnknownOperator{$1} = 1; 7339 } 7340 } 7341 } 7342 } 7343 else 7344 { 7345 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 7346 return getTreeStr($1); 7347 } 7348 } 7349 } 7350 return ""; 7351} 7352 7353sub getFuncReturn($) 7354{ 7355 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7356 { 7357 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7358 { 7359 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) { 7360 return $1; 7361 } 7362 } 7363 } 7364 return ""; 7365} 7366 7367sub getFuncOrig($) 7368{ 7369 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7370 { 7371 if($Info=~/orig[ ]*:[ ]*@(\d+) /) { 7372 return $1; 7373 } 7374 } 7375 return $_[0]; 7376} 7377 7378sub unmangleArray(@) 7379{ 7380 if($_[0]=~/\A\?/) 7381 { # MSVC mangling 7382 if(defined $DisabledMSVCUnmangling) { 7383 return @_; 7384 } 7385 my $UndNameCmd = get_CmdPath("undname"); 7386 if(not $UndNameCmd) 7387 { 7388 if($OSgroup eq "windows") { 7389 exitStatus("Not_Found", "can't find \"undname\""); 7390 } 7391 elsif(not defined $DisabledMSVCUnmangling) 7392 { 7393 printMsg("WARNING", "can't find \"undname\", disable MSVC unmangling"); 7394 $DisabledMSVCUnmangling = 1; 7395 return @_; 7396 } 7397 } 7398 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7399 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`); 7400 } 7401 else 7402 { # GCC mangling 7403 my $CppFiltCmd = get_CmdPath("c++filt"); 7404 if(not $CppFiltCmd) { 7405 exitStatus("Not_Found", "can't find c++filt in PATH"); 7406 } 7407 if(not defined $CPPFILT_SUPPORT_FILE) 7408 { 7409 my $Info = `$CppFiltCmd -h 2>&1`; 7410 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/; 7411 } 7412 my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":""; 7413 if($CPPFILT_SUPPORT_FILE) 7414 { # new versions of c++filt can take a file 7415 if($#_>$MAX_CPPFILT_FILE_SIZE) 7416 { # c++filt <= 2.22 may crash on large files (larger than 8mb) 7417 # this is fixed in the oncoming version of Binutils 7418 my @Half = splice(@_, 0, ($#_+1)/2); 7419 return (unmangleArray(@Half), unmangleArray(@_)) 7420 } 7421 else 7422 { 7423 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7424 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`; 7425 if($?==139) 7426 { # segmentation fault 7427 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant"); 7428 } 7429 return split(/\n/, $Res); 7430 } 7431 } 7432 else 7433 { # old-style unmangling 7434 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) 7435 { 7436 my @Half = splice(@_, 0, ($#_+1)/2); 7437 return (unmangleArray(@Half), unmangleArray(@_)) 7438 } 7439 else 7440 { 7441 my $Strings = join(" ", @_); 7442 my $Res = `$CppFiltCmd $NoStrip $Strings`; 7443 if($?==139) 7444 { # segmentation fault 7445 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant"); 7446 } 7447 return split(/\n/, $Res); 7448 } 7449 } 7450 } 7451} 7452 7453sub get_ChargeLevel($$) 7454{ 7455 my ($Symbol, $LibVersion) = @_; 7456 return "" if($Symbol!~/\A(_Z|\?)/); 7457 if(defined $CompleteSignature{$LibVersion}{$Symbol} 7458 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) 7459 { 7460 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}) 7461 { 7462 if($Symbol=~/C1[EI]/) { 7463 return "[in-charge]"; 7464 } 7465 elsif($Symbol=~/C2[EI]/) { 7466 return "[not-in-charge]"; 7467 } 7468 } 7469 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) 7470 { 7471 if($Symbol=~/D1[EI]/) { 7472 return "[in-charge]"; 7473 } 7474 elsif($Symbol=~/D2[EI]/) { 7475 return "[not-in-charge]"; 7476 } 7477 elsif($Symbol=~/D0[EI]/) { 7478 return "[in-charge-deleting]"; 7479 } 7480 } 7481 } 7482 else 7483 { 7484 if($Symbol=~/C1[EI]/) { 7485 return "[in-charge]"; 7486 } 7487 elsif($Symbol=~/C2[EI]/) { 7488 return "[not-in-charge]"; 7489 } 7490 elsif($Symbol=~/D1[EI]/) { 7491 return "[in-charge]"; 7492 } 7493 elsif($Symbol=~/D2[EI]/) { 7494 return "[not-in-charge]"; 7495 } 7496 elsif($Symbol=~/D0[EI]/) { 7497 return "[in-charge-deleting]"; 7498 } 7499 } 7500 return ""; 7501} 7502 7503sub get_Signature_M($$) 7504{ 7505 my ($Symbol, $LibVersion) = @_; 7506 my $Signature_M = $tr_name{$Symbol}; 7507 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 7508 { # add return type name 7509 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M; 7510 } 7511 return $Signature_M; 7512} 7513 7514sub get_Signature($$) 7515{ 7516 my ($Symbol, $LibVersion) = @_; 7517 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) { 7518 return $Cache{"get_Signature"}{$LibVersion}{$Symbol}; 7519 } 7520 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 7521 my ($Signature, @Param_Types_FromUnmangledName) = (); 7522 7523 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 7524 7525 if($Symbol=~/\A(_Z|\?)/) 7526 { 7527 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 7528 { 7529 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 7530 $ClassName=~s/\bstruct //g; 7531 7532 if(index($Symbol, "_ZTV")==0) { 7533 return "vtable for $ClassName [data]"; 7534 } 7535 7536 $Signature .= $ClassName."::"; 7537 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { 7538 $Signature .= "~"; 7539 } 7540 $Signature .= $ShortName; 7541 } 7542 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) { 7543 $Signature .= $NameSpace."::".$ShortName; 7544 } 7545 else { 7546 $Signature .= $ShortName; 7547 } 7548 my ($Short, $Params) = split_Signature($tr_name{$MnglName}); 7549 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1); 7550 } 7551 else 7552 { 7553 $Signature .= $MnglName; 7554 } 7555 my @ParamArray = (); 7556 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 7557 { 7558 if($Pos eq "") { 7559 next; 7560 } 7561 7562 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}; 7563 if(not $ParamTypeId) { 7564 next; 7565 } 7566 7567 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"}; 7568 if(not $ParamTypeName) { 7569 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos]; 7570 } 7571 foreach my $Typedef (keys(%ChangedTypedef)) 7572 { 7573 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 7574 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g; 7575 } 7576 } 7577 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) 7578 { 7579 if($ParamName eq "this" 7580 and $Symbol=~/\A(_Z|\?)/) 7581 { # do NOT show first hidded "this"-parameter 7582 next; 7583 } 7584 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName)); 7585 } 7586 else { 7587 push(@ParamArray, $ParamTypeName); 7588 } 7589 } 7590 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"} 7591 or $GlobalDataObject{$LibVersion}{$Symbol}) { 7592 $Signature .= " [data]"; 7593 } 7594 else 7595 { 7596 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) 7597 { # add [in-charge] 7598 $Signature .= " ".$ChargeLevel; 7599 } 7600 $Signature .= " (".join(", ", @ParamArray).")"; 7601 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"} 7602 or $Symbol=~/\A_ZN(V|)K/) { 7603 $Signature .= " const"; 7604 } 7605 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"} 7606 or $Symbol=~/\A_ZN(K|)V/) { 7607 $Signature .= " volatile"; 7608 } 7609 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"} 7610 and $Symbol=~/\A(_Z|\?)/) 7611 { # for static methods 7612 $Signature .= " [static]"; 7613 } 7614 } 7615 if(defined $ShowRetVal 7616 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { 7617 $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"}; 7618 } 7619 if($SymbolVersion) { 7620 $Signature .= $VersionSpec.$SymbolVersion; 7621 } 7622 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature); 7623} 7624 7625sub create_member_decl($$) 7626{ 7627 my ($TName, $Member) = @_; 7628 if($TName=~/\([\*]+\)/) 7629 { 7630 $TName=~s/\(([\*]+)\)/\($1$Member\)/; 7631 return $TName; 7632 } 7633 else 7634 { 7635 my @ArraySizes = (); 7636 while($TName=~s/(\[[^\[\]]*\])\Z//) { 7637 push(@ArraySizes, $1); 7638 } 7639 return $TName." ".$Member.join("", @ArraySizes); 7640 } 7641} 7642 7643sub getFuncType($) 7644{ 7645 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7646 { 7647 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7648 { 7649 if(my $Type = $LibInfo{$Version}{"info_type"}{$1}) 7650 { 7651 if($Type eq "method_type") { 7652 return "Method"; 7653 } 7654 elsif($Type eq "function_type") { 7655 return "Function"; 7656 } 7657 else { 7658 return "Other"; 7659 } 7660 } 7661 } 7662 } 7663 return ""; 7664} 7665 7666sub getFuncTypeId($) 7667{ 7668 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7669 { 7670 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) { 7671 return $1; 7672 } 7673 } 7674 return 0; 7675} 7676 7677sub isAnon($) 7678{ # "._N" or "$_N" in older GCC versions 7679 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/); 7680} 7681 7682sub formatName($$) 7683{ # type name correction 7684 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) { 7685 return $Cache{"formatName"}{$_[1]}{$_[0]}; 7686 } 7687 7688 my $N = $_[0]; 7689 7690 if($_[1] ne "S") 7691 { 7692 $N=~s/\A[ ]+//g; 7693 $N=~s/[ ]+\Z//g; 7694 $N=~s/[ ]{2,}/ /g; 7695 } 7696 7697 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const 7698 7699 $N=~s/\b(const|volatile) ([\w\:]+)([\*&,>]|\Z)/$2 $1$3/g; # "const void" to "void const" 7700 7701 $N=~s/\bvolatile const\b/const volatile/g; 7702 7703 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g; 7704 $N=~s/\b(short|long) int\b/$1/g; 7705 7706 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g; 7707 7708 while($N=~s/>>/> >/g) {}; 7709 7710 if($_[1] eq "S") 7711 { 7712 if(index($N, "operator")!=-1) { 7713 $N=~s/\b(operator[ ]*)> >/$1>>/; 7714 } 7715 } 7716 7717 $N=~s/,([^ ])/, $1/g; 7718 7719 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N); 7720} 7721 7722sub get_HeaderDeps($$) 7723{ 7724 my ($AbsPath, $LibVersion) = @_; 7725 return () if(not $AbsPath or not $LibVersion); 7726 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) { 7727 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7728 } 7729 my %IncDir = (); 7730 detect_recursive_includes($AbsPath, $LibVersion); 7731 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) 7732 { 7733 next if(not $HeaderPath); 7734 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/); 7735 my $Dir = get_dirname($HeaderPath); 7736 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}})) 7737 { 7738 my $Dep = $Dir; 7739 if($Prefix) 7740 { 7741 if($OSgroup eq "windows") 7742 { # case insensitive seach on windows 7743 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) { 7744 next; 7745 } 7746 } 7747 elsif($OSgroup eq "macos") 7748 { # seach in frameworks 7749 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7750 { 7751 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/) 7752 {# frameworks 7753 my ($HFramework, $HName) = ($1, $2); 7754 $Dep = $HFramework; 7755 } 7756 else 7757 {# mismatch 7758 next; 7759 } 7760 } 7761 } 7762 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7763 { # Linux, FreeBSD 7764 next; 7765 } 7766 } 7767 if(not $Dep) 7768 { # nothing to include 7769 next; 7770 } 7771 if(is_default_include_dir($Dep)) 7772 { # included by the compiler 7773 next; 7774 } 7775 if(get_depth($Dep)==1) 7776 { # too short 7777 next; 7778 } 7779 if(isLibcDir($Dep)) 7780 { # do NOT include /usr/include/{sys,bits} 7781 next; 7782 } 7783 $IncDir{$Dep} = 1; 7784 } 7785 } 7786 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion); 7787 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7788} 7789 7790sub sortIncPaths($$) 7791{ 7792 my ($ArrRef, $LibVersion) = @_; 7793 if(not $ArrRef or $#{$ArrRef}<0) { 7794 return $ArrRef; 7795 } 7796 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef}; 7797 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef}; 7798 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef}; 7799 return $ArrRef; 7800} 7801 7802sub sortDeps($$$) 7803{ 7804 if($Header_Dependency{$_[2]}{$_[0]} 7805 and not $Header_Dependency{$_[2]}{$_[1]}) { 7806 return 1; 7807 } 7808 elsif(not $Header_Dependency{$_[2]}{$_[0]} 7809 and $Header_Dependency{$_[2]}{$_[1]}) { 7810 return -1; 7811 } 7812 return 0; 7813} 7814 7815sub join_P($$) 7816{ 7817 my $S = "/"; 7818 if($OSgroup eq "windows") { 7819 $S = "\\"; 7820 } 7821 return join($S, @_); 7822} 7823 7824sub get_namespace_additions($) 7825{ 7826 my $NameSpaces = $_[0]; 7827 my ($Additions, $AddNameSpaceId) = ("", 1); 7828 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces})) 7829 { 7830 next if($SkipNameSpaces{$Version}{$NS}); 7831 next if(not $NS or $NameSpaces->{$NS}==-1); 7832 next if($NS=~/(\A|::)iterator(::|\Z)/i); 7833 next if($NS=~/\A__/i); 7834 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING); 7835 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports 7836 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = (); 7837 my @NS_Parts = split(/::/, $NS); 7838 next if($#NS_Parts==-1); 7839 next if($NS_Parts[0]=~/\A(random|or)\Z/); 7840 foreach my $NS_Part (@NS_Parts) 7841 { 7842 $TypeDecl_Prefix .= "namespace $NS_Part\{"; 7843 $TypeDecl_Suffix .= "}"; 7844 } 7845 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix; 7846 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};"; 7847 $Additions.=" $TypeDecl\n $FuncDecl\n"; 7848 $AddNameSpaceId+=1; 7849 } 7850 return $Additions; 7851} 7852 7853sub path_format($$) 7854{ 7855 my ($Path, $Fmt) = @_; 7856 $Path=~s/[\/\\]+\.?\Z//g; 7857 if($Fmt eq "windows") 7858 { 7859 $Path=~s/\//\\/g; 7860 $Path=lc($Path); 7861 } 7862 else 7863 { # forward slash to pass into MinGW GCC 7864 $Path=~s/\\/\//g; 7865 } 7866 return $Path; 7867} 7868 7869sub inc_opt($$) 7870{ 7871 my ($Path, $Style) = @_; 7872 if($Style eq "GCC") 7873 { # GCC options 7874 if($OSgroup eq "windows") 7875 { # to MinGW GCC 7876 return "-I\"".path_format($Path, "unix")."\""; 7877 } 7878 elsif($OSgroup eq "macos" 7879 and $Path=~/\.framework\Z/) 7880 { # to Apple's GCC 7881 return "-F".esc(get_dirname($Path)); 7882 } 7883 else { 7884 return "-I".esc($Path); 7885 } 7886 } 7887 elsif($Style eq "CL") { 7888 return "/I \"".$Path."\""; 7889 } 7890 return ""; 7891} 7892 7893sub platformSpecs($) 7894{ 7895 my $LibVersion = $_[0]; 7896 my $Arch = getArch($LibVersion); 7897 if($OStarget eq "symbian") 7898 { # options for GCCE compiler 7899 my %Symbian_Opts = map {$_=>1} ( 7900 "-D__GCCE__", 7901 "-DUNICODE", 7902 "-fexceptions", 7903 "-D__SYMBIAN32__", 7904 "-D__MARM_INTERWORK__", 7905 "-D_UNICODE", 7906 "-D__S60_50__", 7907 "-D__S60_3X__", 7908 "-D__SERIES60_3X__", 7909 "-D__EPOC32__", 7910 "-D__MARM__", 7911 "-D__EABI__", 7912 "-D__MARM_ARMV5__", 7913 "-D__SUPPORT_CPP_EXCEPTIONS__", 7914 "-march=armv5t", 7915 "-mapcs", 7916 "-mthumb-interwork", 7917 "-DEKA2", 7918 "-DSYMBIAN_ENABLE_SPLIT_HEADERS" 7919 ); 7920 return join(" ", keys(%Symbian_Opts)); 7921 } 7922 elsif($OSgroup eq "windows" 7923 and get_dumpmachine($GCC_PATH)=~/mingw/i) 7924 { # add options to MinGW compiler 7925 # to simulate the MSVC compiler 7926 my %MinGW_Opts = map {$_=>1} ( 7927 "-D__unaligned=\" \"", 7928 "-D__nullptr=\"nullptr\"", 7929 "-D_WIN32", 7930 "-D_STDCALL_SUPPORTED", 7931 "-D__int64=\"long long\"", 7932 "-D__int32=int", 7933 "-D__int16=short", 7934 "-D__int8=char", 7935 "-D__possibly_notnullterminated=\" \"", 7936 "-D__nullterminated=\" \"", 7937 "-D__nullnullterminated=\" \"", 7938 "-D__assume=\" \"", 7939 "-D__w64=\" \"", 7940 "-D__ptr32=\" \"", 7941 "-D__ptr64=\" \"", 7942 "-D__forceinline=inline", 7943 "-D__inline=inline", 7944 "-D__uuidof(x)=IID()", 7945 "-D__try=", 7946 "-D__except(x)=", 7947 "-D__declspec(x)=__attribute__((x))", 7948 "-D__pragma(x)=", 7949 "-D_inline=inline", 7950 "-D__forceinline=__inline", 7951 "-D__stdcall=__attribute__((__stdcall__))", 7952 "-D__cdecl=__attribute__((__cdecl__))", 7953 "-D__fastcall=__attribute__((__fastcall__))", 7954 "-D__thiscall=__attribute__((__thiscall__))", 7955 "-D_stdcall=__attribute__((__stdcall__))", 7956 "-D_cdecl=__attribute__((__cdecl__))", 7957 "-D_fastcall=__attribute__((__fastcall__))", 7958 "-D_thiscall=__attribute__((__thiscall__))", 7959 "-DSHSTDAPI_(x)=x", 7960 "-D_MSC_EXTENSIONS", 7961 "-DSECURITY_WIN32", 7962 "-D_MSC_VER=1500", 7963 "-D_USE_DECLSPECS_FOR_SAL", 7964 "-D__noop=\" \"", 7965 "-DDECLSPEC_DEPRECATED=\" \"", 7966 "-D__builtin_alignof(x)=__alignof__(x)", 7967 "-DSORTPP_PASS"); 7968 if($Arch eq "x86") 7969 { 7970 $MinGW_Opts{"-D_X86_=300"}=1; 7971 $MinGW_Opts{"-D_M_IX86=300"}=1; 7972 } 7973 elsif($Arch eq "x86_64") 7974 { 7975 $MinGW_Opts{"-D_AMD64_=300"}=1; 7976 $MinGW_Opts{"-D_M_AMD64=300"}=1; 7977 $MinGW_Opts{"-D_M_X64=300"}=1; 7978 } 7979 elsif($Arch eq "ia64") 7980 { 7981 $MinGW_Opts{"-D_IA64_=300"}=1; 7982 $MinGW_Opts{"-D_M_IA64=300"}=1; 7983 } 7984 return join(" ", sort keys(%MinGW_Opts)); 7985 } 7986 return ""; 7987} 7988 7989my %C_Structure = map {$_=>1} ( 7990# FIXME: Can't separate union and struct data types before dumping, 7991# so it sometimes cause compilation errors for unknown reason 7992# when trying to declare TYPE* tmp_add_class_N 7993# This is a list of such structures + list of other C structures 7994 "sigval", 7995 "sigevent", 7996 "sigaction", 7997 "sigvec", 7998 "sigstack", 7999 "timeval", 8000 "timezone", 8001 "rusage", 8002 "rlimit", 8003 "wait", 8004 "flock", 8005 "stat", 8006 "_stat", 8007 "stat32", 8008 "_stat32", 8009 "stat64", 8010 "_stat64", 8011 "_stati64", 8012 "if_nameindex", 8013 "usb_device", 8014 "sigaltstack", 8015 "sysinfo", 8016 "timeLocale", 8017 "tcp_debug", 8018 "rpc_createerr", 8019 # Other 8020 "timespec", 8021 "random_data", 8022 "drand48_data", 8023 "_IO_marker", 8024 "_IO_FILE", 8025 "lconv", 8026 "sched_param", 8027 "tm", 8028 "itimerspec", 8029 "_pthread_cleanup_buffer", 8030 "fd_set", 8031 "siginfo", 8032 "mallinfo", 8033 "timex", 8034 "sigcontext", 8035 "ucontext", 8036 # Mac 8037 "_timex", 8038 "_class_t", 8039 "_category_t", 8040 "_class_ro_t", 8041 "_protocol_t", 8042 "_message_ref_t", 8043 "_super_message_ref_t", 8044 "_ivar_t", 8045 "_ivar_list_t" 8046); 8047 8048sub getCompileCmd($$$) 8049{ 8050 my ($Path, $Opt, $Inc) = @_; 8051 my $GccCall = $GCC_PATH; 8052 if($Opt) { 8053 $GccCall .= " ".$Opt; 8054 } 8055 $GccCall .= " -x "; 8056 if($OSgroup eq "macos") { 8057 $GccCall .= "objective-"; 8058 } 8059 8060 if($GCC_MISSED_MNGL) 8061 { # workaround for GCC 4.8 (C only) 8062 $GccCall .= "c++"; 8063 } 8064 elsif(check_gcc($GCC_PATH, "4")) 8065 { # compile as "C++" header 8066 # to obtain complete dump using GCC 4.0 8067 $GccCall .= "c++-header"; 8068 } 8069 else 8070 { # compile as "C++" source 8071 # GCC 3.3 cannot compile headers 8072 $GccCall .= "c++"; 8073 } 8074 if(my $Opts = platformSpecs($Version)) 8075 { # platform-specific options 8076 $GccCall .= " ".$Opts; 8077 } 8078 # allow extra qualifications 8079 # and other nonconformant code 8080 $GccCall .= " -fpermissive"; 8081 $GccCall .= " -w"; 8082 if($NoStdInc) 8083 { 8084 $GccCall .= " -nostdinc"; 8085 $GccCall .= " -nostdinc++"; 8086 } 8087 if(my $Opts_GCC = getGCC_Opts($Version)) 8088 { # user-defined options 8089 $GccCall .= " ".$Opts_GCC; 8090 } 8091 $GccCall .= " \"$Path\""; 8092 if($Inc) 8093 { # include paths 8094 $GccCall .= " ".$Inc; 8095 } 8096 return $GccCall; 8097} 8098 8099sub detectPreamble($$) 8100{ 8101 my ($Content, $LibVersion) = @_; 8102 my %HeaderElems = ( 8103 # Types 8104 "stdio.h" => ["FILE", "va_list"], 8105 "stddef.h" => ["NULL", "ptrdiff_t"], 8106 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t", 8107 "int8_t", "int16_t", "int32_t", "int64_t"], 8108 "time.h" => ["time_t"], 8109 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char", 8110 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"], 8111 "unistd.h" => ["gid_t", "uid_t", "socklen_t"], 8112 "stdbool.h" => ["_Bool"], 8113 "rpc/xdr.h" => ["bool_t"], 8114 "in_systm.h" => ["n_long", "n_short"], 8115 # Fields 8116 "arpa/inet.h" => ["fw_src", "ip_src"], 8117 # Functions 8118 "stdlib.h" => ["free", "malloc", "size_t"], 8119 "string.h" => ["memmove", "strcmp"] 8120 ); 8121 my %AutoPreamble = (); 8122 foreach (keys(%HeaderElems)) 8123 { 8124 foreach my $Elem (@{$HeaderElems{$_}}) { 8125 $AutoPreamble{$Elem} = $_; 8126 } 8127 } 8128 my %Types = (); 8129 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//) 8130 { # error: 'FILE' has not been declared 8131 $Types{$2} = 1; 8132 } 8133 if(keys(%Types)) 8134 { 8135 my %AddHeaders = (); 8136 foreach my $Type (keys(%Types)) 8137 { 8138 if(my $Header = $AutoPreamble{$Type}) 8139 { 8140 if(my $Path = identifyHeader($Header, $LibVersion)) 8141 { 8142 if(skipHeader($Path, $LibVersion)) { 8143 next; 8144 } 8145 $Path = path_format($Path, $OSgroup); 8146 $AddHeaders{$Path}{"Type"} = $Type; 8147 $AddHeaders{$Path}{"Header"} = $Header; 8148 } 8149 } 8150 } 8151 if(keys(%AddHeaders)) { 8152 return \%AddHeaders; 8153 } 8154 } 8155 return undef; 8156} 8157 8158sub checkCTags($) 8159{ 8160 my $Path = $_[0]; 8161 if(not $Path) { 8162 return; 8163 } 8164 my $CTags = undef; 8165 8166 if($OSgroup eq "bsd") 8167 { # use ectags on BSD 8168 $CTags = get_CmdPath("ectags"); 8169 if(not $CTags) { 8170 printMsg("WARNING", "can't find \'ectags\' program"); 8171 } 8172 } 8173 if(not $CTags) { 8174 $CTags = get_CmdPath("ctags"); 8175 } 8176 if(not $CTags) 8177 { 8178 printMsg("WARNING", "can't find \'ctags\' program"); 8179 return; 8180 } 8181 8182 if($OSgroup ne "linux") 8183 { # macos, freebsd, etc. 8184 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`; 8185 if($Info!~/universal|exuberant/i) 8186 { 8187 printMsg("WARNING", "incompatible version of \'ctags\' program"); 8188 return; 8189 } 8190 } 8191 8192 my $Out = $TMP_DIR."/ctags.txt"; 8193 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\""); 8194 if($Debug) { 8195 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt"); 8196 } 8197 open(CTAGS, "<", $Out); 8198 while(my $Line = <CTAGS>) 8199 { 8200 chomp($Line); 8201 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line); 8202 if(defined $Intrinsic_Keywords{$Name}) 8203 { # noise 8204 next; 8205 } 8206 if($Type eq "n") 8207 { 8208 if(index($Scpe, "class:")==0) { 8209 next; 8210 } 8211 if(index($Scpe, "struct:")==0) { 8212 next; 8213 } 8214 if(index($Scpe, "namespace:")==0) 8215 { 8216 if($Scpe=~s/\Anamespace://) { 8217 $Name = $Scpe."::".$Name; 8218 } 8219 } 8220 $TUnit_NameSpaces{$Version}{$Name} = 1; 8221 } 8222 elsif($Type eq "p") 8223 { 8224 if(not $Scpe or index($Scpe, "namespace:")==0) { 8225 $TUnit_Funcs{$Version}{$Name} = 1; 8226 } 8227 } 8228 elsif($Type eq "x") 8229 { 8230 if(not $Scpe or index($Scpe, "namespace:")==0) { 8231 $TUnit_Vars{$Version}{$Name} = 1; 8232 } 8233 } 8234 } 8235 close(CTAGS); 8236} 8237 8238sub preChange($$) 8239{ 8240 my ($HeaderPath, $IncStr) = @_; 8241 8242 my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr); 8243 my $Content = undef; 8244 8245 if(not defined $MinGWCompat and $OStarget eq "windows" 8246 and get_dumpmachine($GCC_PATH)=~/mingw/i 8247 and $MinGWMode{$Version}!=-1) 8248 { # modify headers to compile by MinGW 8249 if(not $Content) 8250 { # preprocessing 8251 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8252 } 8253 if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g) 8254 { # __asm { ... } 8255 $MinGWMode{$Version}=1; 8256 } 8257 if($Content=~s/\s+(\/ \/.*?)\n/\n/g) 8258 { # comments after preprocessing 8259 $MinGWMode{$Version}=1; 8260 } 8261 if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g) 8262 { # 0xffui8 8263 $MinGWMode{$Version}=1; 8264 } 8265 8266 if($MinGWMode{$Version}) { 8267 printMsg("INFO", "Using MinGW compatibility mode"); 8268 } 8269 } 8270 8271 if(defined $CxxIncompat and ($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly) 8272 and $CppMode{$Version}!=-1 and not $CPP_HEADERS) 8273 { # rename C++ keywords in C code 8274 printMsg("INFO", "Checking the code for C++ keywords"); 8275 if(not $Content) 8276 { # preprocessing 8277 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8278 } 8279 8280 my $RegExp_C = join("|", keys(%CppKeywords_C)); 8281 my $RegExp_F = join("|", keys(%CppKeywords_F)); 8282 my $RegExp_O = join("|", keys(%CppKeywords_O)); 8283 8284 my $Detected = undef; 8285 my $Sentence_O = undef; 8286 my $Sentence_N = undef; 8287 my $Regex = undef; 8288 8289 $Regex = qr/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/; 8290 while($Content=~/$Regex/) 8291 { # MATCH: 8292 # int foo(int new, int class, int (*new)(int)); 8293 # int foo(char template[], char*); 8294 # unsigned private: 8; 8295 # DO NOT MATCH: 8296 # #pragma GCC visibility push(default) 8297 $Sentence_O = "$1$2$3$4"; 8298 $Sentence_N = "$1$2c99_$3$4"; 8299 8300 if($Sentence_O=~/\s+decltype\(/) 8301 { # C++ 8302 # decltype(nullptr) 8303 last; 8304 } 8305 else 8306 { 8307 $Content=~s/$Regex/$Sentence_N/g; 8308 $CppMode{$Version} = 1; 8309 if(not defined $Detected) { 8310 $Detected = $Sentence_O; 8311 } 8312 } 8313 } 8314 if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g) 8315 { # MATCH: 8316 # int delete(...); 8317 # int explicit(...); 8318 # DO NOT MATCH: 8319 # void operator delete(...) 8320 $CppMode{$Version} = 1; 8321 $Detected = "$1$2$3" if(not defined $Detected); 8322 } 8323 if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g) 8324 { # MATCH: 8325 # int bool; 8326 # DO NOT MATCH: 8327 # bool X; 8328 # return *this; 8329 # throw; 8330 $CppMode{$Version} = 1; 8331 $Detected = "$1$2$3" if(not defined $Detected); 8332 } 8333 if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g) 8334 { # MATCH: 8335 # int operator(...); 8336 # DO NOT MATCH: 8337 # int operator()(...); 8338 $CppMode{$Version} = 1; 8339 $Detected = "$1$2$3" if(not defined $Detected); 8340 } 8341 if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g) 8342 { # MATCH: 8343 # int foo(int operator); 8344 # int foo(int operator, int other); 8345 # DO NOT MATCH: 8346 # int operator,(...); 8347 $CppMode{$Version} = 1; 8348 $Detected = "$1$2$3" if(not defined $Detected); 8349 } 8350 if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g) 8351 { # MATCH: 8352 # int foo(gboolean *bool); 8353 # DO NOT MATCH: 8354 # void setTabEnabled(int index, bool); 8355 $CppMode{$Version} = 1; 8356 $Detected = "$1$2$3" if(not defined $Detected); 8357 } 8358 if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g) 8359 { # MATCH: 8360 # int foo(int* this); 8361 # int bar(int this); 8362 # int baz(int throw); 8363 # DO NOT MATCH: 8364 # foo(X, this); 8365 $CppMode{$Version} = 1; 8366 $Detected = "$1$2$3$4" if(not defined $Detected); 8367 } 8368 if($Content=~s/(struct |extern )(template) /$1c99_$2 /g) 8369 { # MATCH: 8370 # struct template {...}; 8371 # extern template foo(...); 8372 $CppMode{$Version} = 1; 8373 $Detected = "$1$2" if(not defined $Detected); 8374 } 8375 8376 if($CppMode{$Version} == 1) 8377 { 8378 if($Debug) 8379 { 8380 $Detected=~s/\A\s+//g; 8381 printMsg("INFO", "Detected code: \"$Detected\""); 8382 } 8383 } 8384 8385 # remove typedef enum NAME NAME; 8386 my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g; 8387 my $N = 0; 8388 while($N<=$#FwdTypedefs-1) 8389 { 8390 my $S = $FwdTypedefs[$N]; 8391 if($S eq $FwdTypedefs[$N+1]) 8392 { 8393 $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g; 8394 $CppMode{$Version} = 1; 8395 8396 if($Debug) { 8397 printMsg("INFO", "Detected code: \"typedef enum $S $S;\""); 8398 } 8399 } 8400 $N+=2; 8401 } 8402 8403 if($CppMode{$Version}==1) { 8404 printMsg("INFO", "Using C++ compatibility mode"); 8405 } 8406 else { 8407 printMsg("INFO", "C++ keywords in the C code are not found"); 8408 } 8409 } 8410 8411 if($CppMode{$Version}==1 8412 or $MinGWMode{$Version}==1) 8413 { 8414 my $IPath = $TMP_DIR."/dump$Version.i"; 8415 writeFile($IPath, $Content); 8416 return $IPath; 8417 } 8418 8419 return undef; 8420} 8421 8422sub getDump() 8423{ 8424 if(not $GCC_PATH) { 8425 exitStatus("Error", "internal error - GCC path is not set"); 8426 } 8427 8428 my @Headers = keys(%{$Registered_Headers{$Version}}); 8429 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers; 8430 8431 my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC"); 8432 8433 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h"; 8434 my $HeaderPath = $TmpHeaderPath; 8435 8436 # write tmp-header 8437 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n"); 8438 if(my $AddDefines = $Descriptor{$Version}{"Defines"}) 8439 { 8440 $AddDefines=~s/\n\s+/\n /g; 8441 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n"; 8442 } 8443 print TMP_HEADER "\n // add includes\n"; 8444 foreach my $HPath (@{$Include_Preamble{$Version}}) { 8445 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8446 } 8447 foreach my $HPath (@Headers) 8448 { 8449 if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) { 8450 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8451 } 8452 } 8453 close(TMP_HEADER); 8454 8455 if($ExtraInfo) 8456 { # extra information for other tools 8457 if($IncludeString) { 8458 writeFile($ExtraInfo."/include-string", $IncludeString); 8459 } 8460 writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version})); 8461 writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version})); 8462 8463 if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}})) 8464 { 8465 my $REDIR = ""; 8466 foreach my $P1 (sort @Redirects) { 8467 $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n"; 8468 } 8469 writeFile($ExtraInfo."/include-redirect", $REDIR); 8470 } 8471 } 8472 8473 if(not keys(%{$TargetHeaders{$Version}})) 8474 { # Target headers 8475 addTargetHeaders($Version); 8476 } 8477 8478 # clean memory 8479 %RecursiveIncludes = (); 8480 %Header_Include_Prefix = (); 8481 %Header_Includes = (); 8482 8483 # clean cache 8484 delete($Cache{"identifyHeader"}); 8485 delete($Cache{"detect_header_includes"}); 8486 delete($Cache{"selectSystemHeader"}); 8487 8488 # preprocessing stage 8489 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version); 8490 checkPreprocessedUnit($Pre); 8491 8492 if($ExtraInfo) 8493 { # extra information for other tools 8494 writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}}))); 8495 } 8496 8497 # clean memory 8498 delete($Include_Neighbors{$Version}); 8499 delete($PreprocessedHeaders{$Version}); 8500 8501 if($COMMON_LANGUAGE{$Version} eq "C++") { 8502 checkCTags($Pre); 8503 } 8504 8505 if(my $PrePath = preChange($TmpHeaderPath, $IncludeString)) 8506 { # try to correct the preprocessor output 8507 $HeaderPath = $PrePath; 8508 } 8509 8510 if($COMMON_LANGUAGE{$Version} eq "C++") 8511 { # add classes and namespaces to the dump 8512 my $CHdump = "-fdump-class-hierarchy -c"; 8513 if($CppMode{$Version}==1 8514 or $MinGWMode{$Version}==1) { 8515 $CHdump .= " -fpreprocessed"; 8516 } 8517 my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString); 8518 chdir($TMP_DIR); 8519 system($ClassHierarchyCmd." >null 2>&1"); 8520 chdir($ORIG_DIR); 8521 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0]) 8522 { 8523 my $Content = readFile($ClassDump); 8524 foreach my $ClassInfo (split(/\n\n/, $Content)) 8525 { 8526 if($ClassInfo=~/\AClass\s+(.+)\s*/i) 8527 { 8528 my $CName = $1; 8529 next if($CName=~/\A(__|_objc_|_opaque_)/); 8530 $TUnit_NameSpaces{$Version}{$CName} = -1; 8531 if($CName=~/\A[\w:]+\Z/) 8532 { # classes 8533 $TUnit_Classes{$Version}{$CName} = 1; 8534 } 8535 if($CName=~/(\w[\w:]*)::/) 8536 { # namespaces 8537 my $NS = $1; 8538 if(not defined $TUnit_NameSpaces{$Version}{$NS}) { 8539 $TUnit_NameSpaces{$Version}{$NS} = 1; 8540 } 8541 } 8542 } 8543 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i) 8544 { # read v-tables (advanced approach) 8545 my ($CName, $VTable) = ($1, $2); 8546 $ClassVTable_Content{$Version}{$CName} = $VTable; 8547 } 8548 } 8549 foreach my $NS (keys(%{$AddNameSpaces{$Version}})) 8550 { # add user-defined namespaces 8551 $TUnit_NameSpaces{$Version}{$NS} = 1; 8552 } 8553 if($Debug) 8554 { # debug mode 8555 mkpath($DEBUG_PATH{$Version}); 8556 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt"); 8557 } 8558 unlink($ClassDump); 8559 } 8560 8561 # add namespaces and classes 8562 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version})) 8563 { # GCC on all supported platforms does not include namespaces to the dump by default 8564 appendFile($HeaderPath, "\n // add namespaces\n".$NS_Add); 8565 } 8566 # some GCC versions don't include class methods to the TU dump by default 8567 my ($AddClass, $ClassNum) = ("", 0); 8568 my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions 8569 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}})) 8570 { 8571 next if($C_Structure{$CName}); 8572 next if(not $STDCXX_TESTING and $CName=~/\Astd::/); 8573 next if($SkipTypes{$Version}{$CName}); 8574 if(not $Force and $GCC_44 8575 and $OSgroup eq "linux") 8576 { # optimization for linux with GCC >= 4.4 8577 # disable this code by -force option 8578 if(index($CName, "::")!=-1) 8579 { # should be added by name space 8580 next; 8581 } 8582 } 8583 else 8584 { 8585 if($CName=~/\A(.+)::[^:]+\Z/ 8586 and $TUnit_Classes{$Version}{$1}) 8587 { # classes inside other classes 8588 next; 8589 } 8590 } 8591 if(defined $TUnit_Funcs{$Version}{$CName}) 8592 { # the same name for a function and type 8593 next; 8594 } 8595 if(defined $TUnit_Vars{$Version}{$CName}) 8596 { # the same name for a variable and type 8597 next; 8598 } 8599 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n"; 8600 } 8601 if($AddClass) { 8602 appendFile($HeaderPath, "\n // add classes\n".$AddClass); 8603 } 8604 } 8605 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n"); 8606 # create TU dump 8607 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c"; 8608 if($UserLang eq "C") { 8609 $TUdump .= " -U__cplusplus -D_Bool=\"bool\""; 8610 } 8611 if($CppMode{$Version}==1 8612 or $MinGWMode{$Version}==1) { 8613 $TUdump .= " -fpreprocessed"; 8614 } 8615 my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString); 8616 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n"); 8617 chdir($TMP_DIR); 8618 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1"); 8619 my $Errors = ""; 8620 if($?) 8621 { # failed to compile, but the TU dump still can be created 8622 if($Errors = readFile($TMP_DIR."/tu_errors")) 8623 { # try to recompile 8624 # FIXME: handle errors and try to recompile 8625 if($AutoPreambleMode{$Version}!=-1 8626 and my $AddHeaders = detectPreamble($Errors, $Version)) 8627 { # add auto preamble headers and try again 8628 $AutoPreambleMode{$Version}=-1; 8629 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first 8630 foreach my $Num (0 .. $#Headers) 8631 { 8632 my $Path = $Headers[$Num]; 8633 if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}})) 8634 { 8635 push_U($Include_Preamble{$Version}, $Path); 8636 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'"); 8637 } 8638 } 8639 resetLogging($Version); 8640 $TMP_DIR = tempdir(CLEANUP=>1); 8641 return getDump(); 8642 } 8643 elsif($Cpp0xMode{$Version}!=-1 8644 and ($Errors=~/\Q-std=c++0x\E/ 8645 or $Errors=~/is not a class or namespace/)) 8646 { # c++0x: enum class 8647 if(check_gcc($GCC_PATH, "4.6")) 8648 { 8649 $Cpp0xMode{$Version}=-1; 8650 printMsg("INFO", "Enabling c++0x mode"); 8651 resetLogging($Version); 8652 $TMP_DIR = tempdir(CLEANUP=>1); 8653 $CompilerOptions{$Version} .= " -std=c++0x"; 8654 return getDump(); 8655 } 8656 else { 8657 printMsg("WARNING", "Probably c++0x element detected"); 8658 } 8659 8660 } 8661 #elsif($MinGWMode{$Version}==1) 8662 #{ # disable MinGW mode and try again 8663 # $MinGWMode{$Version}=-1; 8664 # resetLogging($Version); 8665 # $TMP_DIR = tempdir(CLEANUP=>1); 8666 # return getDump(); 8667 #} 8668 writeLog($Version, $Errors); 8669 } 8670 else { 8671 writeLog($Version, "$!: $?\n"); 8672 } 8673 printMsg("ERROR", "some errors occurred when compiling headers"); 8674 printErrorLog($Version); 8675 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"}; 8676 writeLog($Version, "\n"); # new line 8677 } 8678 chdir($ORIG_DIR); 8679 unlink($TmpHeaderPath); 8680 unlink($HeaderPath); 8681 8682 if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) { 8683 return $TUs[0]; 8684 } 8685 else 8686 { 8687 my $Msg = "can't compile header(s)"; 8688 if($Errors=~/error trying to exec \W+cc1plus\W+/) { 8689 $Msg .= "\nDid you install G++?"; 8690 } 8691 exitStatus("Cannot_Compile", $Msg); 8692 } 8693} 8694 8695sub cmd_file($) 8696{ 8697 my $Path = $_[0]; 8698 return "" if(not $Path or not -e $Path); 8699 if(my $CmdPath = get_CmdPath("file")) { 8700 return `$CmdPath -b \"$Path\"`; 8701 } 8702 return ""; 8703} 8704 8705sub getIncString($$) 8706{ 8707 my ($ArrRef, $Style) = @_; 8708 return "" if(not $ArrRef or $#{$ArrRef}<0); 8709 my $String = ""; 8710 foreach (@{$ArrRef}) { 8711 $String .= " ".inc_opt($_, $Style); 8712 } 8713 return $String; 8714} 8715 8716sub getIncPaths(@) 8717{ 8718 my @HeaderPaths = @_; 8719 my @IncPaths = @{$Add_Include_Paths{$Version}}; 8720 if($INC_PATH_AUTODETECT{$Version}) 8721 { # auto-detecting dependencies 8722 my %Includes = (); 8723 foreach my $HPath (@HeaderPaths) 8724 { 8725 foreach my $Dir (get_HeaderDeps($HPath, $Version)) 8726 { 8727 if($Skip_Include_Paths{$Version}{$Dir}) { 8728 next; 8729 } 8730 if($SystemRoot) 8731 { 8732 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) { 8733 next; 8734 } 8735 } 8736 $Includes{$Dir} = 1; 8737 } 8738 } 8739 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) { 8740 push_U(\@IncPaths, $Dir); 8741 } 8742 } 8743 else 8744 { # user-defined paths 8745 @IncPaths = @{$Include_Paths{$Version}}; 8746 } 8747 return \@IncPaths; 8748} 8749 8750sub push_U($@) 8751{ # push unique 8752 if(my $Array = shift @_) 8753 { 8754 if(@_) 8755 { 8756 my %Exist = map {$_=>1} @{$Array}; 8757 foreach my $Elem (@_) 8758 { 8759 if(not defined $Exist{$Elem}) 8760 { 8761 push(@{$Array}, $Elem); 8762 $Exist{$Elem} = 1; 8763 } 8764 } 8765 } 8766 } 8767} 8768 8769sub callPreprocessor($$$) 8770{ 8771 my ($Path, $Inc, $LibVersion) = @_; 8772 return "" if(not $Path or not -f $Path); 8773 my $IncludeString=$Inc; 8774 if(not $Inc) { 8775 $IncludeString = getIncString(getIncPaths($Path), "GCC"); 8776 } 8777 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString); 8778 my $Out = $TMP_DIR."/preprocessed.h"; 8779 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\""); 8780 return $Out; 8781} 8782 8783sub cmd_find($;$$$$) 8784{ # native "find" is much faster than File::Find (~6x) 8785 # also the File::Find doesn't support --maxdepth N option 8786 # so using the cross-platform wrapper for the native one 8787 my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_; 8788 return () if(not $Path or not -e $Path); 8789 if($OSgroup eq "windows") 8790 { 8791 $Path = get_abs_path($Path); 8792 $Path = path_format($Path, $OSgroup); 8793 my $Cmd = "dir \"$Path\" /B /O"; 8794 if($MaxDepth!=1) { 8795 $Cmd .= " /S"; 8796 } 8797 if($Type eq "d") { 8798 $Cmd .= " /AD"; 8799 } 8800 elsif($Type eq "f") { 8801 $Cmd .= " /A-D"; 8802 } 8803 my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`); 8804 if($Name) 8805 { 8806 if(not $UseRegex) 8807 { # FIXME: how to search file names in MS shell? 8808 # wildcard to regexp 8809 $Name=~s/\*/.*/g; 8810 $Name='\A'.$Name.'\Z'; 8811 } 8812 @Files = grep { /$Name/i } @Files; 8813 } 8814 my @AbsPaths = (); 8815 foreach my $File (@Files) 8816 { 8817 if(not is_abs($File)) { 8818 $File = join_P($Path, $File); 8819 } 8820 if($Type eq "f" and not -f $File) 8821 { # skip dirs 8822 next; 8823 } 8824 push(@AbsPaths, path_format($File, $OSgroup)); 8825 } 8826 if($Type eq "d") { 8827 push(@AbsPaths, $Path); 8828 } 8829 return @AbsPaths; 8830 } 8831 else 8832 { 8833 my $FindCmd = get_CmdPath("find"); 8834 if(not $FindCmd) { 8835 exitStatus("Not_Found", "can't find a \"find\" command"); 8836 } 8837 $Path = get_abs_path($Path); 8838 if(-d $Path and -l $Path 8839 and $Path!~/\/\Z/) 8840 { # for directories that are symlinks 8841 $Path.="/"; 8842 } 8843 my $Cmd = $FindCmd." \"$Path\""; 8844 if($MaxDepth) { 8845 $Cmd .= " -maxdepth $MaxDepth"; 8846 } 8847 if($Type) { 8848 $Cmd .= " -type $Type"; 8849 } 8850 if($Name and not $UseRegex) 8851 { # wildcards 8852 $Cmd .= " -name \"$Name\""; 8853 } 8854 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`; 8855 if($? and $!) { 8856 printMsg("ERROR", "problem with \'find\' utility ($?): $!"); 8857 } 8858 my @Files = split(/\n/, $Res); 8859 if($Name and $UseRegex) 8860 { # regex 8861 @Files = grep { /$Name/ } @Files; 8862 } 8863 return @Files; 8864 } 8865} 8866 8867sub unpackDump($) 8868{ 8869 my $Path = $_[0]; 8870 return "" if(not $Path or not -e $Path); 8871 8872 $Path = get_abs_path($Path); 8873 $Path = path_format($Path, $OSgroup); 8874 my ($Dir, $FileName) = separate_path($Path); 8875 my $UnpackDir = $TMP_DIR."/unpack"; 8876 rmtree($UnpackDir); 8877 mkpath($UnpackDir); 8878 8879 if($FileName=~s/\Q.zip\E\Z//g) 8880 { # *.zip 8881 my $UnzipCmd = get_CmdPath("unzip"); 8882 if(not $UnzipCmd) { 8883 exitStatus("Not_Found", "can't find \"unzip\" command"); 8884 } 8885 chdir($UnpackDir); 8886 system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\""); 8887 if($?) { 8888 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8889 } 8890 chdir($ORIG_DIR); 8891 my @Contents = cmd_find($UnpackDir, "f"); 8892 if(not @Contents) { 8893 exitStatus("Error", "can't extract \'$Path\'"); 8894 } 8895 return $Contents[0]; 8896 } 8897 elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g) 8898 { # *.tar.gz 8899 # *.tar.gz.amd64 (dh & cdbs) 8900 if($OSgroup eq "windows") 8901 { # -xvzf option is not implemented in tar.exe (2003) 8902 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead 8903 my $TarCmd = get_CmdPath("tar"); 8904 if(not $TarCmd) { 8905 exitStatus("Not_Found", "can't find \"tar\" command"); 8906 } 8907 my $GzipCmd = get_CmdPath("gzip"); 8908 if(not $GzipCmd) { 8909 exitStatus("Not_Found", "can't find \"gzip\" command"); 8910 } 8911 chdir($UnpackDir); 8912 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k) 8913 if($?) { 8914 exitStatus("Error", "can't extract \'$Path\'"); 8915 } 8916 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\""); 8917 if($?) { 8918 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8919 } 8920 chdir($ORIG_DIR); 8921 unlink($Dir."/".$FileName.".tar"); 8922 my @Contents = cmd_find($UnpackDir, "f"); 8923 if(not @Contents) { 8924 exitStatus("Error", "can't extract \'$Path\'"); 8925 } 8926 return $Contents[0]; 8927 } 8928 else 8929 { # Unix, Mac 8930 my $TarCmd = get_CmdPath("tar"); 8931 if(not $TarCmd) { 8932 exitStatus("Not_Found", "can't find \"tar\" command"); 8933 } 8934 chdir($UnpackDir); 8935 system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\""); 8936 if($?) { 8937 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8938 } 8939 chdir($ORIG_DIR); 8940 my @Contents = cmd_find($UnpackDir, "f"); 8941 if(not @Contents) { 8942 exitStatus("Error", "can't extract \'$Path\'"); 8943 } 8944 return $Contents[0]; 8945 } 8946 } 8947} 8948 8949sub createArchive($$) 8950{ 8951 my ($Path, $To) = @_; 8952 if(not $To) { 8953 $To = "."; 8954 } 8955 if(not $Path or not -e $Path 8956 or not -d $To) { 8957 return ""; 8958 } 8959 my ($From, $Name) = separate_path($Path); 8960 if($OSgroup eq "windows") 8961 { # *.zip 8962 my $ZipCmd = get_CmdPath("zip"); 8963 if(not $ZipCmd) { 8964 exitStatus("Not_Found", "can't find \"zip\""); 8965 } 8966 my $Pkg = $To."/".$Name.".zip"; 8967 unlink($Pkg); 8968 chdir($To); 8969 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\""); 8970 if($?) 8971 { # cannot allocate memory (or other problems with "zip") 8972 unlink($Path); 8973 exitStatus("Error", "can't pack the ABI dump: ".$!); 8974 } 8975 chdir($ORIG_DIR); 8976 unlink($Path); 8977 return $Pkg; 8978 } 8979 else 8980 { # *.tar.gz 8981 my $TarCmd = get_CmdPath("tar"); 8982 if(not $TarCmd) { 8983 exitStatus("Not_Found", "can't find \"tar\""); 8984 } 8985 my $GzipCmd = get_CmdPath("gzip"); 8986 if(not $GzipCmd) { 8987 exitStatus("Not_Found", "can't find \"gzip\""); 8988 } 8989 my $Pkg = abs_path($To)."/".$Name.".tar.gz"; 8990 unlink($Pkg); 8991 chdir($From); 8992 system($TarCmd, "-czf", $Pkg, $Name); 8993 if($?) 8994 { # cannot allocate memory (or other problems with "tar") 8995 unlink($Path); 8996 exitStatus("Error", "can't pack the ABI dump: ".$!); 8997 } 8998 chdir($ORIG_DIR); 8999 unlink($Path); 9000 return $To."/".$Name.".tar.gz"; 9001 } 9002} 9003 9004sub is_header_file($) 9005{ 9006 if($_[0]=~/\.($HEADER_EXT)\Z/i) { 9007 return $_[0]; 9008 } 9009 return 0; 9010} 9011 9012sub is_not_header($) 9013{ 9014 if($_[0]=~/\.\w+\Z/ 9015 and $_[0]!~/\.($HEADER_EXT)\Z/i) { 9016 return 1; 9017 } 9018 return 0; 9019} 9020 9021sub is_header($$$) 9022{ 9023 my ($Header, $UserDefined, $LibVersion) = @_; 9024 return 0 if(-d $Header); 9025 if(-f $Header) { 9026 $Header = get_abs_path($Header); 9027 } 9028 else 9029 { 9030 if(is_abs($Header)) 9031 { # incorrect absolute path 9032 return 0; 9033 } 9034 if(my $HPath = identifyHeader($Header, $LibVersion)) { 9035 $Header = $HPath; 9036 } 9037 else 9038 { # can't find header 9039 return 0; 9040 } 9041 } 9042 if($Header=~/\.\w+\Z/) 9043 { # have an extension 9044 return is_header_file($Header); 9045 } 9046 else 9047 { 9048 if($UserDefined==2) 9049 { # specified on the command line 9050 if(cmd_file($Header)!~/HTML|XML/i) { 9051 return $Header; 9052 } 9053 } 9054 elsif($UserDefined) 9055 { # specified in the XML-descriptor 9056 # header file without an extension 9057 return $Header; 9058 } 9059 else 9060 { 9061 if(index($Header, "/include/")!=-1 9062 or cmd_file($Header)=~/C[\+]*\s+program/i) 9063 { # !~/HTML|XML|shared|dynamic/i 9064 return $Header; 9065 } 9066 } 9067 } 9068 return 0; 9069} 9070 9071sub addTargetHeaders($) 9072{ 9073 my $LibVersion = $_[0]; 9074 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}})) 9075 { 9076 my $RegDir = get_dirname($RegHeader); 9077 $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1; 9078 9079 if(not $INC_PATH_AUTODETECT{$LibVersion}) { 9080 detect_recursive_includes($RegHeader, $LibVersion); 9081 } 9082 9083 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}})) 9084 { 9085 my $Dir = get_dirname($RecInc); 9086 9087 if(familiarDirs($RegDir, $Dir) 9088 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1) 9089 { # in the same directory or included by #include "..." 9090 $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1; 9091 } 9092 } 9093 } 9094} 9095 9096sub familiarDirs($$) 9097{ 9098 my ($D1, $D2) = @_; 9099 if($D1 eq $D2) { 9100 return 1; 9101 } 9102 9103 my $U1 = index($D1, "/usr/"); 9104 my $U2 = index($D2, "/usr/"); 9105 9106 if($U1==0 and $U2!=0) { 9107 return 0; 9108 } 9109 9110 if($U2==0 and $U1!=0) { 9111 return 0; 9112 } 9113 9114 if(index($D2, $D1."/")==0) { 9115 return 1; 9116 } 9117 9118 # /usr/include/DIR 9119 # /home/user/DIR 9120 9121 my $DL = get_depth($D1); 9122 9123 my @Dirs1 = ($D1); 9124 while($DL - get_depth($D1)<=2 9125 and get_depth($D1)>=4 9126 and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { 9127 push(@Dirs1, $D1); 9128 } 9129 9130 my @Dirs2 = ($D2); 9131 while(get_depth($D2)>=4 9132 and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { 9133 push(@Dirs2, $D2); 9134 } 9135 9136 foreach my $P1 (@Dirs1) 9137 { 9138 foreach my $P2 (@Dirs2) 9139 { 9140 9141 if($P1 eq $P2) { 9142 return 1; 9143 } 9144 } 9145 } 9146 return 0; 9147} 9148 9149sub readHeaders($) 9150{ 9151 $Version = $_[0]; 9152 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ..."); 9153 my $DumpPath = getDump(); 9154 if($Debug) 9155 { # debug mode 9156 mkpath($DEBUG_PATH{$Version}); 9157 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt"); 9158 } 9159 getInfo($DumpPath); 9160} 9161 9162sub prepareTypes($) 9163{ 9164 my $LibVersion = $_[0]; 9165 if(not checkDump($LibVersion, "2.0")) 9166 { # support for old ABI dumps 9167 # type names have been corrected in ACC 1.22 (dump 2.0 format) 9168 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9169 { 9170 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9171 if($TName=~/\A(\w+)::(\w+)/) { 9172 my ($P1, $P2) = ($1, $2); 9173 if($P1 eq $P2) { 9174 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/; 9175 } 9176 else { 9177 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/; 9178 } 9179 } 9180 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName; 9181 } 9182 } 9183 if(not checkDump($LibVersion, "2.5")) 9184 { # support for old ABI dumps 9185 # V < 2.5: array size == "number of elements" 9186 # V >= 2.5: array size in bytes 9187 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9188 { 9189 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9190 if($Type{"Type"} eq "Array") 9191 { 9192 if(my $Size = $Type{"Size"}) 9193 { # array[N] 9194 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion}); 9195 $Size *= $Base{"Size"}; 9196 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size"; 9197 } 9198 else 9199 { # array[] is a pointer 9200 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion}; 9201 } 9202 } 9203 } 9204 } 9205 my $V2 = ($LibVersion==1)?2:1; 9206 if(not checkDump($LibVersion, "2.7")) 9207 { # support for old ABI dumps 9208 # size of "method ptr" corrected in 2.7 9209 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9210 { 9211 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9212 if($PureType{"Type"} eq "MethodPtr") 9213 { 9214 my %Type = get_Type($TypeId, $LibVersion); 9215 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2); 9216 my %Type2 = get_Type($TypeId_2, $V2); 9217 if($Type{"Size"} ne $Type2{"Size"}) { 9218 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"}; 9219 } 9220 } 9221 } 9222 } 9223} 9224 9225sub prepareSymbols($) 9226{ 9227 my $LibVersion = $_[0]; 9228 9229 if(not keys(%{$SymbolInfo{$LibVersion}})) 9230 { # check if input is valid 9231 if(not $ExtendedCheck) 9232 { 9233 if($CheckHeadersOnly) { 9234 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")"); 9235 } 9236 else { 9237 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")"); 9238 } 9239 } 9240 } 9241 9242 my $Remangle = 0; 9243 if(not checkDump(1, "2.10") 9244 or not checkDump(2, "2.10")) 9245 { # different formats 9246 $Remangle = 1; 9247 } 9248 if($CheckHeadersOnly) 9249 { # different languages 9250 if($UserLang) 9251 { # --lang=LANG for both versions 9252 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"}) 9253 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"})) 9254 { 9255 if($UserLang eq "C++") 9256 { # remangle symbols 9257 $Remangle = 1; 9258 } 9259 elsif($UserLang eq "C") 9260 { # remove mangling 9261 $Remangle = -1; 9262 } 9263 } 9264 } 9265 } 9266 9267 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}})) 9268 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2 9269 if(not checkDump($LibVersion, "2.13")) 9270 { # support for old ABI dumps 9271 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 9272 { 9273 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) 9274 { 9275 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"}; 9276 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"}; 9277 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9278 if(defined $DVal and $DVal ne "") 9279 { 9280 if($TName eq "char") { 9281 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal); 9282 } 9283 elsif($TName eq "bool") { 9284 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false"; 9285 } 9286 } 9287 } 9288 } 9289 } 9290 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 9291 { 9292 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 9293 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}) 9294 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 9295 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg) 9296 # + support for old ABI dumps 9297 next; 9298 } 9299 } 9300 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9301 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9302 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}; 9303 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 9304 9305 my $SRemangle = 0; 9306 if(not checkDump(1, "2.12") 9307 or not checkDump(2, "2.12")) 9308 { # support for old ABI dumps 9309 if($ShortName eq "operator>>") 9310 { 9311 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9312 { # corrected mangling of operator>> 9313 $SRemangle = 1; 9314 } 9315 } 9316 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9317 { 9318 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 9319 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/) 9320 { # corrected mangling of const global data 9321 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8) 9322 # and incorrectly mangled by old ACC versions 9323 $SRemangle = 1; 9324 } 9325 } 9326 } 9327 if(not $CheckHeadersOnly) 9328 { # support for old ABI dumps 9329 if(not checkDump(1, "2.17") 9330 or not checkDump(2, "2.17")) 9331 { 9332 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9333 { 9334 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9335 { 9336 if(link_symbol($ShortName, $LibVersion, "-Deps")) 9337 { 9338 $MnglName = $ShortName; 9339 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9340 } 9341 } 9342 } 9343 } 9344 } 9345 if($Remangle==1 or $SRemangle==1) 9346 { # support for old ABI dumps: some symbols are not mangled in old dumps 9347 # mangle both sets of symbols (old and new) 9348 # NOTE: remangling all symbols by the same mangler 9349 if($MnglName=~/\A_ZN(V|)K/) 9350 { # mangling may be incorrect on old ABI dumps 9351 # because of absent "Const" attribute 9352 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1; 9353 } 9354 if($MnglName=~/\A_ZN(K|)V/) 9355 { # mangling may be incorrect on old ABI dumps 9356 # because of absent "Volatile" attribute 9357 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1; 9358 } 9359 if(($ClassID and $MnglName!~/\A(_Z|\?)/) 9360 or (not $ClassID and $CheckHeadersOnly) 9361 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps"))) 9362 { # support for old ABI dumps, GCC >= 4.0 9363 # remangling all manually mangled symbols 9364 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC")) 9365 { 9366 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9367 $MangledNames{$LibVersion}{$MnglName} = 1; 9368 } 9369 } 9370 } 9371 elsif($Remangle==-1) 9372 { # remove mangling 9373 $MnglName = ""; 9374 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = ""; 9375 } 9376 if(not $MnglName) { 9377 next; 9378 } 9379 9380 # NOTE: duplicated entries in the ABI Dump 9381 if(defined $CompleteSignature{$LibVersion}{$MnglName}) 9382 { 9383 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 9384 { 9385 if($SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} eq "p1") 9386 { 9387 next; 9388 } 9389 } 9390 } 9391 9392 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"}) 9393 { # NOTE: global data may enter here twice 9394 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9395 9396 } 9397 if(not checkDump($LibVersion, "2.6")) 9398 { # support for old dumps 9399 # add "Volatile" attribute 9400 if($MnglName=~/_Z(K|)V/) { 9401 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1; 9402 } 9403 } 9404 # symbol and its symlink have same signatures 9405 if($SymVer{$LibVersion}{$MnglName}) { 9406 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9407 } 9408 9409 if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"}) 9410 { 9411 %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9412 9413 if($SymVer{$LibVersion}{$Alias}) { 9414 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9415 } 9416 } 9417 9418 # clean memory 9419 delete($SymbolInfo{$LibVersion}{$InfoId}); 9420 } 9421 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") { 9422 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion); 9423 } 9424 if($ExtendedCheck) 9425 { # --ext option 9426 addExtension($LibVersion); 9427 } 9428 9429 # clean memory 9430 delete($SymbolInfo{$LibVersion}); 9431 9432 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 9433 { # detect allocable classes with public exported constructors 9434 # or classes with auto-generated or inline-only constructors 9435 # and other temp info 9436 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 9437 { 9438 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 9439 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"} 9440 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}) 9441 { # Class() { ... } will not be exported 9442 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9443 { 9444 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) { 9445 $AllocableClass{$LibVersion}{$ClassName} = 1; 9446 } 9447 } 9448 } 9449 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9450 { # all imported class methods 9451 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary")) 9452 { 9453 if($CheckHeadersOnly) 9454 { 9455 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 9456 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 9457 { # all symbols except non-virtual inline 9458 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9459 } 9460 } 9461 else { 9462 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9463 } 9464 } 9465 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) { 9466 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9467 } 9468 } 9469 $ClassNames{$LibVersion}{$ClassName} = 1; 9470 } 9471 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 9472 { 9473 my %Base = get_BaseType($RetId, $LibVersion); 9474 if(defined $Base{"Type"} 9475 and $Base{"Type"}=~/Struct|Class/) 9476 { 9477 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"}; 9478 if($Name=~/<([^<>\s]+)>/) 9479 { 9480 if(my $Tid = getTypeIdByName($1, $LibVersion)) { 9481 $ReturnedClass{$LibVersion}{$Tid} = 1; 9482 } 9483 } 9484 else { 9485 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1; 9486 } 9487 } 9488 } 9489 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 9490 { 9491 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"}; 9492 if(get_PLevel($PId, $LibVersion)>=1) 9493 { 9494 if(my %Base = get_BaseType($PId, $LibVersion)) 9495 { 9496 if($Base{"Type"}=~/Struct|Class/) 9497 { 9498 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1; 9499 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1)) 9500 { # mark all derived classes 9501 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1; 9502 } 9503 } 9504 } 9505 } 9506 } 9507 9508 # mapping {short name => symbols} 9509 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1; 9510 } 9511 foreach my $MnglName (keys(%VTableClass)) 9512 { # reconstruct attributes of v-tables 9513 if(index($MnglName, "_ZTV")==0) 9514 { 9515 if(my $ClassName = $VTableClass{$MnglName}) 9516 { 9517 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 9518 { 9519 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"}; 9520 $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId; 9521 } 9522 } 9523 } 9524 } 9525 9526 # types 9527 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9528 { 9529 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}) 9530 { 9531 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) { 9532 $ClassNames{$LibVersion}{$TName} = 1; 9533 } 9534 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"}) 9535 { 9536 $ClassNames{$LibVersion}{$TName} = 1; 9537 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}})) 9538 { 9539 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) { 9540 $ClassNames{$LibVersion}{$BName} = 1; 9541 } 9542 } 9543 } 9544 } 9545 } 9546} 9547 9548sub getFirst($$) 9549{ 9550 my ($Tid, $LibVersion) = @_; 9551 if(not $Tid) { 9552 return $Tid; 9553 } 9554 9555 if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9556 { 9557 if($TName_Tid{$LibVersion}{$Name}) { 9558 return $TName_Tid{$LibVersion}{$Name}; 9559 } 9560 } 9561 9562 return $Tid; 9563} 9564 9565sub register_SymbolUsage($$$) 9566{ 9567 my ($InfoId, $UsedType, $LibVersion) = @_; 9568 9569 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9570 if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion)) 9571 { 9572 register_TypeUsage($RTid, $UsedType, $LibVersion); 9573 $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid; 9574 } 9575 if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion)) 9576 { 9577 register_TypeUsage($FCid, $UsedType, $LibVersion); 9578 $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid; 9579 9580 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) 9581 { # register "this" pointer 9582 register_TypeUsage($ThisId, $UsedType, $LibVersion); 9583 } 9584 if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion)) 9585 { # register "this" pointer (const method) 9586 register_TypeUsage($ThisId_C, $UsedType, $LibVersion); 9587 } 9588 } 9589 foreach my $PPos (keys(%{$FuncInfo{"Param"}})) 9590 { 9591 if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion)) 9592 { 9593 register_TypeUsage($PTid, $UsedType, $LibVersion); 9594 $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; 9595 } 9596 } 9597 foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) 9598 { 9599 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; 9600 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9601 register_TypeUsage($TTid, $UsedType, $LibVersion); 9602 } 9603 } 9604} 9605 9606sub register_TypeUsage($$$) 9607{ 9608 my ($TypeId, $UsedType, $LibVersion) = @_; 9609 if(not $TypeId) { 9610 return; 9611 } 9612 if($UsedType->{$TypeId}) 9613 { # already registered 9614 return; 9615 } 9616 9617 my %TInfo = get_Type($TypeId, $LibVersion); 9618 if($TInfo{"Type"}) 9619 { 9620 if(my $NS = $TInfo{"NameSpace"}) 9621 { 9622 if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) { 9623 register_TypeUsage($NSTid, $UsedType, $LibVersion); 9624 } 9625 } 9626 9627 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) 9628 { 9629 $UsedType->{$TypeId} = 1; 9630 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) 9631 { 9632 foreach my $BaseId (keys(%{$TInfo{"Base"}})) { 9633 register_TypeUsage($BaseId, $UsedType, $LibVersion); 9634 } 9635 foreach my $TPos (keys(%{$TInfo{"TParam"}})) 9636 { 9637 my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; 9638 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9639 register_TypeUsage($TTid, $UsedType, $LibVersion); 9640 } 9641 } 9642 } 9643 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}})) 9644 { 9645 if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion)) 9646 { 9647 register_TypeUsage($MTid, $UsedType, $LibVersion); 9648 $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; 9649 } 9650 } 9651 if($TInfo{"Type"} eq "FuncPtr" 9652 or $TInfo{"Type"} eq "MethodPtr" 9653 or $TInfo{"Type"} eq "Func") 9654 { 9655 if(my $RTid = $TInfo{"Return"}) { 9656 register_TypeUsage($RTid, $UsedType, $LibVersion); 9657 } 9658 foreach my $PPos (keys(%{$TInfo{"Param"}})) 9659 { 9660 if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { 9661 register_TypeUsage($PTid, $UsedType, $LibVersion); 9662 } 9663 } 9664 } 9665 if($TInfo{"Type"} eq "FieldPtr") 9666 { 9667 if(my $RTid = $TInfo{"Return"}) { 9668 register_TypeUsage($RTid, $UsedType, $LibVersion); 9669 } 9670 if(my $CTid = $TInfo{"Class"}) { 9671 register_TypeUsage($CTid, $UsedType, $LibVersion); 9672 } 9673 } 9674 if($TInfo{"Type"} eq "MethodPtr") 9675 { 9676 if(my $CTid = $TInfo{"Class"}) { 9677 register_TypeUsage($CTid, $UsedType, $LibVersion); 9678 } 9679 } 9680 } 9681 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) 9682 { 9683 $UsedType->{$TypeId} = 1; 9684 if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion)) 9685 { 9686 register_TypeUsage($BTid, $UsedType, $LibVersion); 9687 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid; 9688 } 9689 } 9690 else 9691 { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. 9692 $UsedType->{$TypeId} = 1; 9693 } 9694 } 9695} 9696 9697sub selectSymbol($$$$) 9698{ # select symbol to check or to dump 9699 my ($Symbol, $SInfo, $Level, $LibVersion) = @_; 9700 9701 if($Level eq "Dump") 9702 { 9703 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"}) 9704 { # TODO: check if this symbol is from 9705 # base classes of other target symbols 9706 return 1; 9707 } 9708 } 9709 9710 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/) 9711 { # stdc++ interfaces 9712 return 0; 9713 } 9714 9715 my $Target = 0; 9716 if(my $Header = $SInfo->{"Header"}) { 9717 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2)); 9718 } 9719 if($ExtendedCheck) 9720 { 9721 if(index($Symbol, "external_func_")==0) { 9722 $Target = 1; 9723 } 9724 } 9725 if($CheckHeadersOnly or $Level eq "Source") 9726 { 9727 if($Target) 9728 { 9729 if($Level eq "Dump") 9730 { # dumped 9731 if($BinaryOnly) 9732 { 9733 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) { 9734 return 1; 9735 } 9736 } 9737 else { 9738 return 1; 9739 } 9740 } 9741 elsif($Level eq "Source") 9742 { # checked 9743 return 1; 9744 } 9745 elsif($Level eq "Binary") 9746 { # checked 9747 if(not $SInfo->{"InLine"} or $SInfo->{"Data"} 9748 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) { 9749 return 1; 9750 } 9751 } 9752 } 9753 } 9754 else 9755 { # library is available 9756 if(link_symbol($Symbol, $LibVersion, "-Deps")) 9757 { # exported symbols 9758 return 1; 9759 } 9760 if($Level eq "Dump") 9761 { # dumped 9762 if($BinaryOnly) 9763 { 9764 if($SInfo->{"Data"}) 9765 { 9766 if($Target) { 9767 return 1; 9768 } 9769 } 9770 } 9771 else 9772 { # SrcBin 9773 if($Target) { 9774 return 1; 9775 } 9776 } 9777 } 9778 elsif($Level eq "Source") 9779 { # checked 9780 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"} 9781 or isInLineInst($SInfo, $LibVersion)) 9782 { # skip LOCAL symbols 9783 if($Target) { 9784 return 1; 9785 } 9786 } 9787 } 9788 elsif($Level eq "Binary") 9789 { # checked 9790 if($SInfo->{"PureVirt"} or $SInfo->{"Data"}) 9791 { 9792 if($Target) { 9793 return 1; 9794 } 9795 } 9796 } 9797 } 9798 return 0; 9799} 9800 9801sub cleanDump($) 9802{ # clean data 9803 my $LibVersion = $_[0]; 9804 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 9805 { 9806 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}})) 9807 { 9808 delete($SymbolInfo{$LibVersion}{$InfoId}); 9809 next; 9810 } 9811 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9812 if(not $MnglName) 9813 { 9814 delete($SymbolInfo{$LibVersion}{$InfoId}); 9815 next; 9816 } 9817 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9818 if(not $ShortName) 9819 { 9820 delete($SymbolInfo{$LibVersion}{$InfoId}); 9821 next; 9822 } 9823 if($MnglName eq $ShortName) 9824 { # remove duplicate data 9825 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}); 9826 } 9827 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) { 9828 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"}); 9829 } 9830 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { 9831 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"}); 9832 } 9833 delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"}); 9834 } 9835 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 9836 { 9837 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}})) 9838 { 9839 delete($TypeInfo{$LibVersion}{$Tid}); 9840 next; 9841 } 9842 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"}); 9843 foreach my $Attr ("Header", "Line", "Size", "NameSpace") 9844 { 9845 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) { 9846 delete($TypeInfo{$LibVersion}{$Tid}{$Attr}); 9847 } 9848 } 9849 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) { 9850 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"}); 9851 } 9852 } 9853} 9854 9855sub pickType($$) 9856{ 9857 my ($Tid, $LibVersion) = @_; 9858 9859 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid}) 9860 { 9861 if(defined $TypeInfo{$LibVersion}{$Dupl}) 9862 { 9863 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9864 { # duplicate 9865 return 0; 9866 } 9867 } 9868 } 9869 9870 my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}; 9871 9872 if(isBuiltIn($THeader)) { 9873 return 0; 9874 } 9875 9876 if($TypeInfo{$LibVersion}{$Tid}{"Type"}!~/Class|Struct|Union|Enum|Typedef/) { 9877 return 0; 9878 } 9879 9880 if(isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"})) { 9881 return 0; 9882 } 9883 9884 if(selfTypedef($Tid, $LibVersion)) { 9885 return 0; 9886 } 9887 9888 if(not isTargetType($Tid, $LibVersion)) { 9889 return 0; 9890 } 9891 9892 return 0; 9893} 9894 9895sub isTargetType($$) 9896{ 9897 my ($Tid, $LibVersion) = @_; 9898 9899 if($TypeInfo{$LibVersion}{$Tid}{"Type"}!~/Class|Struct|Union|Enum|Typedef/) 9900 { # derived 9901 return 1; 9902 } 9903 9904 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}) 9905 { # NOTE: header is defined to source if undefined (DWARF dumps) 9906 if(not is_target_header($THeader, $LibVersion)) 9907 { # from target headers 9908 return 0; 9909 } 9910 } 9911 else 9912 { # NOTE: if type is defined in source 9913 if($UsedDump{$LibVersion}{"Public"}) 9914 { 9915 if(isPrivateABI($Tid, $LibVersion)) { 9916 return 0; 9917 } 9918 else { 9919 return 1; 9920 } 9921 } 9922 else { 9923 return 0; 9924 } 9925 } 9926 9927 if($SkipInternalTypes) 9928 { 9929 if($TypeInfo{$LibVersion}{$Tid}{"Name"}=~/($SkipInternalTypes)/) 9930 { 9931 return 0; 9932 } 9933 } 9934 9935 return 1; 9936} 9937 9938sub remove_Unused($$) 9939{ # remove unused data types from the ABI dump 9940 my ($LibVersion, $Kind) = @_; 9941 9942 my %UsedType = (); 9943 9944 foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}})) 9945 { 9946 register_SymbolUsage($InfoId, \%UsedType, $LibVersion); 9947 } 9948 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9949 { 9950 if($UsedType{$Tid}) 9951 { # All & Extended 9952 next; 9953 } 9954 9955 if($Kind eq "Extended") 9956 { 9957 if(pickType($Tid, $LibVersion)) 9958 { 9959 my %Tree = (); 9960 register_TypeUsage($Tid, \%Tree, $LibVersion); 9961 9962 my $Tmpl = 0; 9963 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9964 { 9965 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9966 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 9967 { 9968 $Tmpl = 1; 9969 last; 9970 } 9971 } 9972 if(not $Tmpl) 9973 { 9974 foreach (keys(%Tree)) { 9975 $UsedType{$_} = 1; 9976 } 9977 } 9978 } 9979 } 9980 } 9981 9982 my %Delete = (); 9983 9984 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9985 { # remove unused types 9986 if($UsedType{$Tid}) 9987 { # All & Extended 9988 next; 9989 } 9990 9991 if($Kind eq "Extra") 9992 { 9993 my %Tree = (); 9994 register_TypeUsage($Tid, \%Tree, $LibVersion); 9995 9996 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9997 { 9998 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9999 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 10000 { 10001 $Delete{$Tid} = 1; 10002 last; 10003 } 10004 } 10005 } 10006 else 10007 { 10008 # remove type 10009 delete($TypeInfo{$LibVersion}{$Tid}); 10010 } 10011 } 10012 10013 if($Kind eq "Extra") 10014 { # remove duplicates 10015 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 10016 { 10017 if($UsedType{$Tid}) 10018 { # All & Extended 10019 next; 10020 } 10021 10022 my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 10023 10024 if($TName_Tid{$LibVersion}{$Name} ne $Tid) { 10025 delete($TypeInfo{$LibVersion}{$Tid}); 10026 } 10027 } 10028 } 10029 10030 foreach my $Tid (keys(%Delete)) 10031 { 10032 delete($TypeInfo{$LibVersion}{$Tid}); 10033 } 10034} 10035 10036sub check_Completeness($$) 10037{ 10038 my ($Info, $LibVersion) = @_; 10039 10040 # data types 10041 if(defined $Info->{"Memb"}) 10042 { 10043 foreach my $Pos (keys(%{$Info->{"Memb"}})) 10044 { 10045 if(defined $Info->{"Memb"}{$Pos}{"type"}) { 10046 check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion); 10047 } 10048 } 10049 } 10050 if(defined $Info->{"Base"}) 10051 { 10052 foreach my $Bid (keys(%{$Info->{"Base"}})) { 10053 check_TypeInfo($Bid, $LibVersion); 10054 } 10055 } 10056 if(defined $Info->{"BaseType"}) { 10057 check_TypeInfo($Info->{"BaseType"}, $LibVersion); 10058 } 10059 if(defined $Info->{"TParam"}) 10060 { 10061 foreach my $Pos (keys(%{$Info->{"TParam"}})) 10062 { 10063 my $TName = $Info->{"TParam"}{$Pos}{"name"}; 10064 if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) { 10065 next; 10066 } 10067 if($TName eq "_BoolType") { 10068 next; 10069 } 10070 if($TName=~/\Asizeof\(/) { 10071 next; 10072 } 10073 if(my $Tid = $TName_Tid{$LibVersion}{$TName}) { 10074 check_TypeInfo($Tid, $LibVersion); 10075 } 10076 else 10077 { 10078 if(defined $Debug) { 10079 printMsg("WARNING", "missed type $TName"); 10080 } 10081 } 10082 } 10083 } 10084 10085 # symbols 10086 if(defined $Info->{"Param"}) 10087 { 10088 foreach my $Pos (keys(%{$Info->{"Param"}})) 10089 { 10090 if(defined $Info->{"Param"}{$Pos}{"type"}) { 10091 check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion); 10092 } 10093 } 10094 } 10095 if(defined $Info->{"Return"}) { 10096 check_TypeInfo($Info->{"Return"}, $LibVersion); 10097 } 10098 if(defined $Info->{"Class"}) { 10099 check_TypeInfo($Info->{"Class"}, $LibVersion); 10100 } 10101} 10102 10103sub check_TypeInfo($$) 10104{ 10105 my ($Tid, $LibVersion) = @_; 10106 10107 if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) { 10108 return; 10109 } 10110 $CheckedTypeInfo{$LibVersion}{$Tid} = 1; 10111 10112 if(defined $TypeInfo{$LibVersion}{$Tid}) 10113 { 10114 if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) { 10115 printMsg("ERROR", "missed type name ($Tid)"); 10116 } 10117 check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion); 10118 } 10119 else { 10120 printMsg("ERROR", "missed type id $Tid"); 10121 } 10122} 10123 10124sub selfTypedef($$) 10125{ 10126 my ($TypeId, $LibVersion) = @_; 10127 my %Type = get_Type($TypeId, $LibVersion); 10128 if($Type{"Type"} eq "Typedef") 10129 { 10130 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion}); 10131 if($Base{"Type"}=~/Class|Struct/) 10132 { 10133 if($Type{"Name"} eq $Base{"Name"}) { 10134 return 1; 10135 } 10136 elsif($Type{"Name"}=~/::(\w+)\Z/) 10137 { 10138 if($Type{"Name"} eq $Base{"Name"}."::".$1) 10139 { # QPointer<QWidget>::QPointer 10140 return 1; 10141 } 10142 } 10143 } 10144 } 10145 return 0; 10146} 10147 10148sub addExtension($) 10149{ 10150 my $LibVersion = $_[0]; 10151 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 10152 { 10153 if(pickType($Tid, $LibVersion)) 10154 { 10155 my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 10156 $TName=~s/\A(struct|union|class|enum) //; 10157 my $Symbol = "external_func_".$TName; 10158 10159 %{$CompleteSignature{$LibVersion}{$Symbol}} = ( 10160 "Header" => "extended.h", 10161 "ShortName" => $Symbol, 10162 "MnglName" => $Symbol, 10163 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } } 10164 ); 10165 10166 $ExtendedSymbols{$Symbol} = 1; 10167 $CheckedSymbols{"Binary"}{$Symbol} = 1; 10168 $CheckedSymbols{"Source"}{$Symbol} = 1; 10169 } 10170 } 10171 $ExtendedSymbols{"external_func_0"} = 1; 10172 $CheckedSymbols{"Binary"}{"external_func_0"} = 1; 10173 $CheckedSymbols{"Source"}{"external_func_0"} = 1; 10174} 10175 10176sub findMethod($$$) 10177{ 10178 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10179 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}})) 10180 { 10181 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) { 10182 return $VirtMethodInClass; 10183 } 10184 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) { 10185 return $VirtMethodInBaseClasses; 10186 } 10187 } 10188 return ""; 10189} 10190 10191sub findMethod_Class($$$) 10192{ 10193 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10194 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 10195 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName}); 10196 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1); 10197 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"}; 10198 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10199 { # search for interface with the same parameters suffix (overridden) 10200 if($TargetSuffix eq get_symbol_suffix($Candidate, 1)) 10201 { 10202 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) 10203 { 10204 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) 10205 { 10206 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/) 10207 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/) 10208 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) { 10209 return $Candidate; 10210 } 10211 } 10212 } 10213 else 10214 { 10215 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) { 10216 return $Candidate; 10217 } 10218 } 10219 } 10220 } 10221 return ""; 10222} 10223 10224sub registerVTable($) 10225{ 10226 my $LibVersion = $_[0]; 10227 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 10228 { 10229 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"} 10230 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"}) 10231 { 10232 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"}; 10233 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/); 10234 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"} 10235 and $Symbol=~/D2E/) 10236 { # pure virtual D2-destructors are marked as "virt" in the dump 10237 # virtual D2-destructors are NOT marked as "virt" in the dump 10238 # both destructors are not presented in the v-table 10239 next; 10240 } 10241 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 10242 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1; 10243 } 10244 } 10245} 10246 10247sub registerOverriding($) 10248{ 10249 my $LibVersion = $_[0]; 10250 my @Classes = keys(%{$VirtualTable{$LibVersion}}); 10251 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes; 10252 foreach my $ClassName (@Classes) 10253 { 10254 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10255 { 10256 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"}) 10257 { # pure virtuals 10258 next; 10259 } 10260 my $ClassId = $TName_Tid{$LibVersion}{$ClassName}; 10261 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion)) 10262 { 10263 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"} 10264 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"}) 10265 { # both overridden virtual methods 10266 # and implemented pure virtual methods 10267 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden; 10268 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1; 10269 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model 10270 } 10271 } 10272 } 10273 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { 10274 delete($VirtualTable{$LibVersion}{$ClassName}); 10275 } 10276 } 10277} 10278 10279sub setVirtFuncPositions($) 10280{ 10281 my $LibVersion = $_[0]; 10282 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}})) 10283 { 10284 my ($Num, $Rel) = (1, 0); 10285 10286 if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10287 { 10288 if($UsedDump{$LibVersion}{"DWARF"}) { 10289 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs; 10290 } 10291 else { 10292 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs; 10293 } 10294 foreach my $VirtFunc (@Funcs) 10295 { 10296 if($UsedDump{$LibVersion}{"DWARF"}) { 10297 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"}; 10298 } 10299 else { 10300 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++; 10301 } 10302 10303 # set relative positions 10304 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc} 10305 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc}) 10306 { # relative position excluding added and removed virtual functions 10307 if(not $CompleteSignature{1}{$VirtFunc}{"Override"} 10308 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) { 10309 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++; 10310 } 10311 } 10312 } 10313 } 10314 } 10315 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}})) 10316 { 10317 my $AbsNum = 1; 10318 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) { 10319 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++; 10320 } 10321 } 10322} 10323 10324sub get_sub_classes($$$) 10325{ 10326 my ($ClassId, $LibVersion, $Recursive) = @_; 10327 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId}); 10328 my @Subs = (); 10329 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 10330 { 10331 if($Recursive) 10332 { 10333 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) { 10334 push(@Subs, $SubSubId); 10335 } 10336 } 10337 push(@Subs, $SubId); 10338 } 10339 return @Subs; 10340} 10341 10342sub get_base_classes($$$) 10343{ 10344 my ($ClassId, $LibVersion, $Recursive) = @_; 10345 my %ClassType = get_Type($ClassId, $LibVersion); 10346 return () if(not defined $ClassType{"Base"}); 10347 my @Bases = (); 10348 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})} 10349 keys(%{$ClassType{"Base"}})) 10350 { 10351 if($Recursive) 10352 { 10353 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) { 10354 push(@Bases, $SubBaseId); 10355 } 10356 } 10357 push(@Bases, $BaseId); 10358 } 10359 return @Bases; 10360} 10361 10362sub getVTable_Model($$) 10363{ # return an ordered list of v-table elements 10364 my ($ClassId, $LibVersion) = @_; 10365 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10366 my @Elements = (); 10367 foreach my $BaseId (@Bases, $ClassId) 10368 { 10369 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10370 { 10371 if(defined $VirtualTable{$LibVersion}{$BName}) 10372 { 10373 my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}}); 10374 if($UsedDump{$LibVersion}{"DWARF"}) { 10375 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs; 10376 } 10377 else { 10378 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs; 10379 } 10380 foreach my $VFunc (@VFuncs) { 10381 push(@Elements, $VFunc); 10382 } 10383 } 10384 } 10385 } 10386 return @Elements; 10387} 10388 10389sub getVShift($$) 10390{ 10391 my ($ClassId, $LibVersion) = @_; 10392 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10393 my $VShift = 0; 10394 foreach my $BaseId (@Bases) 10395 { 10396 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10397 { 10398 if(defined $VirtualTable{$LibVersion}{$BName}) { 10399 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}}); 10400 } 10401 } 10402 } 10403 return $VShift; 10404} 10405 10406sub getShift($$) 10407{ 10408 my ($ClassId, $LibVersion) = @_; 10409 my @Bases = get_base_classes($ClassId, $LibVersion, 0); 10410 my $Shift = 0; 10411 foreach my $BaseId (@Bases) 10412 { 10413 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"}) 10414 { 10415 if($Size!=1) 10416 { # not empty base class 10417 $Shift+=$Size; 10418 } 10419 } 10420 } 10421 return $Shift; 10422} 10423 10424sub getVTable_Size($$) 10425{ # number of v-table elements 10426 my ($ClassName, $LibVersion) = @_; 10427 my $Size = 0; 10428 # three approaches 10429 if(not $Size) 10430 { # real size 10431 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) { 10432 $Size = keys(%VTable); 10433 } 10434 } 10435 if(not $Size) 10436 { # shared library symbol size 10437 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) { 10438 $Size /= $WORD_SIZE{$LibVersion}; 10439 } 10440 } 10441 if(not $Size) 10442 { # model size 10443 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) { 10444 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2; 10445 } 10446 } 10447 return $Size; 10448} 10449 10450sub isCopyingClass($$) 10451{ 10452 my ($TypeId, $LibVersion) = @_; 10453 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"}; 10454} 10455 10456sub isLeafClass($$) 10457{ 10458 my ($ClassId, $LibVersion) = @_; 10459 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})); 10460} 10461 10462sub havePubFields($) 10463{ # check structured type for public fields 10464 return isAccessible($_[0], {}, 0, -1); 10465} 10466 10467sub isAccessible($$$$) 10468{ # check interval in structured type for public fields 10469 my ($TypePtr, $Skip, $Start, $End) = @_; 10470 return 0 if(not $TypePtr); 10471 if($End==-1) { 10472 $End = keys(%{$TypePtr->{"Memb"}})-1; 10473 } 10474 foreach my $MemPos (sort {int($a)<=>int($b)} keys(%{$TypePtr->{"Memb"}})) 10475 { 10476 if($Skip and $Skip->{$MemPos}) 10477 { # skip removed/added fields 10478 next; 10479 } 10480 if(int($MemPos)>=$Start and int($MemPos)<=$End) 10481 { 10482 if(isPublic($TypePtr, $MemPos)) { 10483 return ($MemPos+1); 10484 } 10485 } 10486 } 10487 return 0; 10488} 10489 10490sub isReserved($) 10491{ # reserved fields == private 10492 my $MName = $_[0]; 10493 if($MName=~/reserved|padding|f_spare/i) { 10494 return 1; 10495 } 10496 if($MName=~/\A[_]*(spare|pad|unused|dummy)[_\d]*\Z/i) { 10497 return 1; 10498 } 10499 if($MName=~/(pad\d+)/i) { 10500 return 1; 10501 } 10502 return 0; 10503} 10504 10505sub isPublic($$) 10506{ 10507 my ($TypePtr, $FieldPos) = @_; 10508 10509 return 0 if(not $TypePtr); 10510 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}); 10511 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"}); 10512 10513 my $Access = $TypePtr->{"Memb"}{$FieldPos}{"access"}; 10514 if($Access eq "private") 10515 { # by access in C++ language 10516 return 0; 10517 } 10518 10519 # by name in C language 10520 # TODO: add other methods to detect private members 10521 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"}; 10522 if($MName=~/priv|abidata|parent_object|impl/i) 10523 { # C-styled private data 10524 return 0; 10525 } 10526 if(lc($MName) eq "abi") 10527 { # ABI information/reserved field 10528 return 0; 10529 } 10530 if(isReserved($MName)) 10531 { # reserved fields 10532 return 0; 10533 } 10534 10535 return 1; 10536} 10537 10538sub getVTable_Real($$) 10539{ 10540 my ($ClassName, $LibVersion) = @_; 10541 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 10542 { 10543 my %Type = get_Type($ClassId, $LibVersion); 10544 if(defined $Type{"VTable"}) { 10545 return %{$Type{"VTable"}}; 10546 } 10547 } 10548 return (); 10549} 10550 10551sub cmpVTables($) 10552{ 10553 my $ClassName = $_[0]; 10554 my $Res = cmpVTables_Real($ClassName, 1); 10555 if($Res==-1) { 10556 $Res = cmpVTables_Model($ClassName); 10557 } 10558 return $Res; 10559} 10560 10561sub cmpVTables_Model($) 10562{ 10563 my $ClassName = $_[0]; 10564 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}})) 10565 { 10566 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) { 10567 return 1; 10568 } 10569 } 10570 return 0; 10571} 10572 10573sub cmpVTables_Real($$) 10574{ 10575 my ($ClassName, $Strong) = @_; 10576 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) { 10577 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}; 10578 } 10579 my %VTable_Old = getVTable_Real($ClassName, 1); 10580 my %VTable_New = getVTable_Real($ClassName, 2); 10581 if(not %VTable_Old or not %VTable_New) 10582 { # old ABI dumps 10583 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1); 10584 } 10585 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New)); 10586 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes)) 10587 { 10588 if(not defined $VTable_Old{$Offset}) 10589 { # v-table v.1 < v-table v.2 10590 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong); 10591 } 10592 my $Entry1 = $VTable_Old{$Offset}; 10593 if(not defined $VTable_New{$Offset}) 10594 { # v-table v.1 > v-table v.2 10595 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/)); 10596 } 10597 my $Entry2 = $VTable_New{$Offset}; 10598 10599 $Entry1 = simpleVEntry($Entry1); 10600 $Entry2 = simpleVEntry($Entry2); 10601 10602 if($Entry1=~/ 0x/ or $Entry2=~/ 0x/) 10603 { # NOTE: problem with vtable-dumper 10604 next; 10605 } 10606 10607 if($Entry1 ne $Entry2) 10608 { # register as changed 10609 if($Entry1=~/::([^:]+)\Z/) 10610 { 10611 my $M1 = $1; 10612 if($Entry2=~/::([^:]+)\Z/) 10613 { 10614 my $M2 = $1; 10615 if($M1 eq $M2) 10616 { # overridden 10617 next; 10618 } 10619 } 10620 } 10621 if(differentDumps("G")) 10622 { 10623 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/) 10624 { 10625 # GCC 4.6.1: -0x00000000000000010 10626 # GCC 4.7.0: -16 10627 next; 10628 } 10629 } 10630 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1); 10631 } 10632 } 10633 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0); 10634} 10635 10636sub mergeVTables($) 10637{ # merging v-tables without diagnostics 10638 my $Level = $_[0]; 10639 foreach my $ClassName (keys(%{$VirtualTable{1}})) 10640 { 10641 my $ClassId = $TName_Tid{1}{$ClassName}; 10642 if(isPrivateABI($ClassId, 1)) { 10643 next; 10644 } 10645 10646 if($VTableChanged_M{$ClassName}) 10647 { # already registered 10648 next; 10649 } 10650 if(cmpVTables_Real($ClassName, 0)==1) 10651 { 10652 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10653 foreach my $Symbol (@Affected) 10654 { 10655 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=( 10656 "Type_Name"=>$ClassName, 10657 "Target"=>$ClassName); 10658 } 10659 } 10660 } 10661} 10662 10663sub mergeBases($) 10664{ 10665 my $Level = $_[0]; 10666 foreach my $ClassName (keys(%{$ClassNames{1}})) 10667 { # detect added and removed virtual functions 10668 my $ClassId = $TName_Tid{1}{$ClassName}; 10669 next if(not $ClassId); 10670 10671 if(isPrivateABI($ClassId, 1)) { 10672 next; 10673 } 10674 10675 if(defined $VirtualTable{2}{$ClassName}) 10676 { 10677 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}})) 10678 { 10679 if($TName_Tid{1}{$ClassName} 10680 and not defined $VirtualTable{1}{$ClassName}{$Symbol}) 10681 { # added to v-table 10682 if(defined $CompleteSignature{1}{$Symbol} 10683 and $CompleteSignature{1}{$Symbol}{"Virt"}) 10684 { # override some method in v.1 10685 next; 10686 } 10687 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10688 } 10689 } 10690 } 10691 if(defined $VirtualTable{1}{$ClassName}) 10692 { 10693 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}})) 10694 { 10695 if($TName_Tid{2}{$ClassName} 10696 and not defined $VirtualTable{2}{$ClassName}{$Symbol}) 10697 { # removed from v-table 10698 if(defined $CompleteSignature{2}{$Symbol} 10699 and $CompleteSignature{2}{$Symbol}{"Virt"}) 10700 { # override some method in v.2 10701 next; 10702 } 10703 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10704 } 10705 } 10706 } 10707 if($Level eq "Binary") 10708 { # Binary-level 10709 my %Class_Type = get_Type($ClassId, 1); 10710 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}})) 10711 { # check replacements, including pure virtual methods 10712 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc}; 10713 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}})) 10714 { 10715 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc}; 10716 if($AddedPos==$RemovedPos) 10717 { 10718 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc; 10719 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc; 10720 last; # other methods will be reported as "added" or "removed" 10721 } 10722 } 10723 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc}) 10724 { 10725 if(lc($AddedVFunc) eq lc($RemovedVFunc)) 10726 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0) 10727 next; 10728 } 10729 my $ProblemType = "Virtual_Replacement"; 10730 my @Affected = ($RemovedVFunc); 10731 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 10732 { # pure methods 10733 if(not isUsedClass($ClassId, 1, $Level)) 10734 { # not a parameter of some exported method 10735 next; 10736 } 10737 $ProblemType = "Pure_Virtual_Replacement"; 10738 10739 # affected all methods (both virtual and non-virtual ones) 10740 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10741 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}})); 10742 } 10743 $VTableChanged_M{$ClassName}=1; 10744 foreach my $AffectedInt (@Affected) 10745 { 10746 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"}) 10747 { # affected exported methods only 10748 next; 10749 } 10750 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) { 10751 next; 10752 } 10753 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 10754 "Type_Name"=>$Class_Type{"Name"}, 10755 "Target"=>get_Signature($AddedVFunc, 2), 10756 "Old_Value"=>get_Signature($RemovedVFunc, 1)); 10757 } 10758 } 10759 } 10760 } 10761 } 10762 if(not checkDump(1, "2.0") 10763 or not checkDump(2, "2.0")) 10764 { # support for old ABI dumps 10765 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format) 10766 return; 10767 } 10768 foreach my $ClassName (sort keys(%{$ClassNames{1}})) 10769 { 10770 my $ClassId_Old = $TName_Tid{1}{$ClassName}; 10771 next if(not $ClassId_Old); 10772 10773 if(isPrivateABI($ClassId_Old, 1)) { 10774 next; 10775 } 10776 10777 if(not isCreatable($ClassId_Old, 1)) 10778 { # skip classes without public constructors (including auto-generated) 10779 # example: class has only a private exported or private inline constructor 10780 next; 10781 } 10782 if($ClassName=~/>/) 10783 { # skip affected template instances 10784 next; 10785 } 10786 my %Class_Old = get_Type($ClassId_Old, 1); 10787 my $ClassId_New = $TName_Tid{2}{$ClassName}; 10788 if(not $ClassId_New) { 10789 next; 10790 } 10791 my %Class_New = get_Type($ClassId_New, 2); 10792 if($Class_New{"Type"}!~/Class|Struct/) 10793 { # became typedef 10794 if($Level eq "Binary") { 10795 next; 10796 } 10797 if($Level eq "Source") 10798 { 10799 %Class_New = get_PureType($ClassId_New, $TypeInfo{2}); 10800 if($Class_New{"Type"}!~/Class|Struct/) { 10801 next; 10802 } 10803 $ClassId_New = $Class_New{"Tid"}; 10804 } 10805 } 10806 10807 if(not $Class_New{"Size"} or not $Class_Old{"Size"}) 10808 { # incomplete info in the ABI dump 10809 next; 10810 } 10811 10812 10813 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}}); 10814 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}}); 10815 10816 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old; 10817 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New; 10818 10819 my ($BNum1, $BNum2) = (1, 1); 10820 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old; 10821 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New; 10822 my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old; 10823 my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New; 10824 my $Shift_Old = getShift($ClassId_Old, 1); 10825 my $Shift_New = getShift($ClassId_New, 2); 10826 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New; 10827 my ($Added, $Removed) = (0, 0); 10828 my @StableBases_Old = (); 10829 foreach my $BaseId (@Bases_Old) 10830 { 10831 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10832 if($BasePos_New{$Tr_Old{$BaseName}}) { 10833 push(@StableBases_Old, $BaseId); 10834 } 10835 elsif(not $ShortBase_New{$Tr_Old{$BaseName}} 10836 and not $ShortBase_New{get_ShortClass($BaseId, 1)}) 10837 { # removed base 10838 # excluding namespace::SomeClass to SomeClass renaming 10839 my $ProblemKind = "Removed_Base_Class"; 10840 if($Level eq "Binary") 10841 { # Binary-level 10842 if($Shift_Old ne $Shift_New) 10843 { # affected fields 10844 if(havePubFields(\%Class_Old)) { 10845 $ProblemKind .= "_And_Shift"; 10846 } 10847 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10848 $ProblemKind .= "_And_Size"; 10849 } 10850 } 10851 if(keys(%{$VirtualTable_Model{1}{$BaseName}}) 10852 and cmpVTables($ClassName)==1) 10853 { # affected v-table 10854 $ProblemKind .= "_And_VTable"; 10855 $VTableChanged_M{$ClassName}=1; 10856 } 10857 } 10858 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10859 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10860 { 10861 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10862 { 10863 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10864 if($ProblemKind=~/VTable/) { 10865 $VTableChanged_M{$SubName}=1; 10866 } 10867 } 10868 } 10869 foreach my $Interface (@Affected) 10870 { 10871 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10872 next; 10873 } 10874 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10875 "Type_Name"=>$ClassName, 10876 "Target"=>$BaseName, 10877 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10878 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10879 "Shift"=>abs($Shift_New-$Shift_Old) ); 10880 } 10881 $Removed+=1; 10882 } 10883 } 10884 my @StableBases_New = (); 10885 foreach my $BaseId (@Bases_New) 10886 { 10887 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"}; 10888 if($BasePos_Old{$Tr_New{$BaseName}}) { 10889 push(@StableBases_New, $BaseId); 10890 } 10891 elsif(not $ShortBase_Old{$Tr_New{$BaseName}} 10892 and not $ShortBase_Old{get_ShortClass($BaseId, 2)}) 10893 { # added base 10894 # excluding namespace::SomeClass to SomeClass renaming 10895 my $ProblemKind = "Added_Base_Class"; 10896 if($Level eq "Binary") 10897 { # Binary-level 10898 if($Shift_Old ne $Shift_New) 10899 { # affected fields 10900 if(havePubFields(\%Class_Old)) { 10901 $ProblemKind .= "_And_Shift"; 10902 } 10903 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10904 $ProblemKind .= "_And_Size"; 10905 } 10906 } 10907 if(keys(%{$VirtualTable_Model{2}{$BaseName}}) 10908 and cmpVTables($ClassName)==1) 10909 { # affected v-table 10910 $ProblemKind .= "_And_VTable"; 10911 $VTableChanged_M{$ClassName}=1; 10912 } 10913 } 10914 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10915 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10916 { 10917 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10918 { 10919 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10920 if($ProblemKind=~/VTable/) { 10921 $VTableChanged_M{$SubName}=1; 10922 } 10923 } 10924 } 10925 foreach my $Interface (@Affected) 10926 { 10927 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10928 next; 10929 } 10930 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10931 "Type_Name"=>$ClassName, 10932 "Target"=>$BaseName, 10933 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10934 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10935 "Shift"=>abs($Shift_New-$Shift_Old) ); 10936 } 10937 $Added+=1; 10938 } 10939 } 10940 if($Level eq "Binary") 10941 { # Binary-level 10942 ($BNum1, $BNum2) = (1, 1); 10943 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old; 10944 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New; 10945 foreach my $BaseId (@Bases_Old) 10946 { 10947 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10948 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}}) 10949 { 10950 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}}; 10951 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}}; 10952 if($NewPos!=$OldPos) 10953 { # changed position of the base class 10954 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10955 { 10956 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10957 next; 10958 } 10959 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=( 10960 "Type_Name"=>$ClassName, 10961 "Target"=>$BaseName, 10962 "Old_Value"=>$OldPos-1, 10963 "New_Value"=>$NewPos-1 ); 10964 } 10965 } 10966 if($Class_Old{"Base"}{$BaseId}{"virtual"} 10967 and not $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10968 { # became non-virtual base 10969 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10970 { 10971 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10972 next; 10973 } 10974 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=( 10975 "Type_Name"=>$ClassName, 10976 "Target"=>$BaseName ); 10977 } 10978 } 10979 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"} 10980 and $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10981 { # became virtual base 10982 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10983 { 10984 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10985 next; 10986 } 10987 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=( 10988 "Type_Name"=>$ClassName, 10989 "Target"=>$BaseName ); 10990 } 10991 } 10992 } 10993 } 10994 # detect size changes in base classes 10995 if($Shift_Old!=$Shift_New) 10996 { # size of allocable class 10997 foreach my $BaseId (@StableBases_Old) 10998 { # search for changed base 10999 my %BaseType = get_Type($BaseId, 1); 11000 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"}; 11001 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"}; 11002 if($Size_Old ne $Size_New 11003 and $Size_Old and $Size_New) 11004 { 11005 my $ProblemType = undef; 11006 if(isCopyingClass($BaseId, 1)) { 11007 $ProblemType = "Size_Of_Copying_Class"; 11008 } 11009 elsif($AllocableClass{1}{$BaseType{"Name"}}) 11010 { 11011 if($Size_New>$Size_Old) 11012 { # increased size 11013 $ProblemType = "Size_Of_Allocable_Class_Increased"; 11014 } 11015 else 11016 { # decreased size 11017 $ProblemType = "Size_Of_Allocable_Class_Decreased"; 11018 if(not havePubFields(\%Class_Old)) 11019 { # affected class has no public members 11020 next; 11021 } 11022 } 11023 } 11024 next if(not $ProblemType); 11025 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 11026 { # base class size changes affecting current class 11027 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 11028 next; 11029 } 11030 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=( 11031 "Type_Name"=>$BaseType{"Name"}, 11032 "Target"=>$BaseType{"Name"}, 11033 "Old_Size"=>$Size_Old*$BYTE_SIZE, 11034 "New_Size"=>$Size_New*$BYTE_SIZE ); 11035 } 11036 } 11037 } 11038 } 11039 if(defined $VirtualTable_Model{1}{$ClassName} 11040 and cmpVTables_Real($ClassName, 1)==1 11041 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}})) 11042 { # compare virtual tables size in base classes 11043 my $VShift_Old = getVShift($ClassId_Old, 1); 11044 my $VShift_New = getVShift($ClassId_New, 2); 11045 if($VShift_Old ne $VShift_New) 11046 { # changes in the base class or changes in the list of base classes 11047 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1); 11048 my @AllBases_New = get_base_classes($ClassId_New, 2, 1); 11049 ($BNum1, $BNum2) = (1, 1); 11050 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New; 11051 foreach my $BaseId (@AllBases_Old) 11052 { 11053 my %BaseType = get_Type($BaseId, 1); 11054 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}}) 11055 { # lost base 11056 next; 11057 } 11058 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1); 11059 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2); 11060 if($VSize_Old!=$VSize_New) 11061 { 11062 foreach my $Symbol (@VFunctions) 11063 { # TODO: affected non-virtual methods? 11064 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) 11065 { # Removed_Virtual_Method, will be registered in mergeVirtualTables() 11066 next; 11067 } 11068 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0) 11069 { # skip interfaces that have not changed the absolute virtual position 11070 next; 11071 } 11072 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 11073 next; 11074 } 11075 $VTableChanged_M{$BaseType{"Name"}} = 1; 11076 $VTableChanged_M{$ClassName} = 1; 11077 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}})) 11078 { # the reason of the layout change: added virtual functions 11079 next if($VirtualReplacement{$VirtFunc}); 11080 my $ProblemType = "Added_Virtual_Method"; 11081 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) { 11082 $ProblemType = "Added_Pure_Virtual_Method"; 11083 } 11084 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=( 11085 "Type_Name"=>$BaseType{"Name"}, 11086 "Target"=>get_Signature($VirtFunc, 2) ); 11087 } 11088 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}})) 11089 { # the reason of the layout change: removed virtual functions 11090 next if($VirtualReplacement{$VirtFunc}); 11091 my $ProblemType = "Removed_Virtual_Method"; 11092 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) { 11093 $ProblemType = "Removed_Pure_Virtual_Method"; 11094 } 11095 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=( 11096 "Type_Name"=>$BaseType{"Name"}, 11097 "Target"=>get_Signature($VirtFunc, 1) ); 11098 } 11099 } 11100 } 11101 } 11102 } 11103 } 11104 } 11105 } 11106} 11107 11108sub isCreatable($$) 11109{ 11110 my ($ClassId, $LibVersion) = @_; 11111 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}} 11112 or isCopyingClass($ClassId, $LibVersion)) { 11113 return 1; 11114 } 11115 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 11116 { # Fix for incomplete data: if this class has 11117 # a base class then it should also has a constructor 11118 return 1; 11119 } 11120 if($ReturnedClass{$LibVersion}{$ClassId}) 11121 { # returned by some method of this class 11122 # or any other class 11123 return 1; 11124 } 11125 return 0; 11126} 11127 11128sub isUsedClass($$$) 11129{ 11130 my ($ClassId, $LibVersion, $Level) = @_; 11131 if(keys(%{$ParamClass{$LibVersion}{$ClassId}})) 11132 { # parameter of some exported method 11133 return 1; 11134 } 11135 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 11136 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}})) 11137 { # method from target class 11138 return 1; 11139 } 11140 return 0; 11141} 11142 11143sub mergeVirtualTables($$) 11144{ # check for changes in the virtual table 11145 my ($Interface, $Level) = @_; 11146 # affected methods: 11147 # - virtual 11148 # - pure-virtual 11149 # - non-virtual 11150 if($CompleteSignature{1}{$Interface}{"Data"}) 11151 { # global data is not affected 11152 return; 11153 } 11154 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"}; 11155 if(not $Class_Id) { 11156 return; 11157 } 11158 my $CName = $TypeInfo{1}{$Class_Id}{"Name"}; 11159 if(cmpVTables_Real($CName, 1)==0) 11160 { # no changes 11161 return; 11162 } 11163 $CheckedTypes{$Level}{$CName} = 1; 11164 if($Level eq "Binary") 11165 { # Binary-level 11166 if($CompleteSignature{1}{$Interface}{"PureVirt"} 11167 and not isUsedClass($Class_Id, 1, $Level)) 11168 { # pure virtuals should not be affected 11169 # if there are no exported methods using this class 11170 return; 11171 } 11172 } 11173 foreach my $Func (keys(%{$VirtualTable{1}{$CName}})) 11174 { 11175 if(defined $VirtualTable{2}{$CName}{$Func} 11176 and defined $CompleteSignature{2}{$Func}) 11177 { 11178 if(not $CompleteSignature{1}{$Func}{"PureVirt"} 11179 and $CompleteSignature{2}{$Func}{"PureVirt"}) 11180 { # became pure virtual 11181 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=( 11182 "Type_Name"=>$CName, 11183 "Target"=>get_Signature_M($Func, 1) ); 11184 $VTableChanged_M{$CName} = 1; 11185 } 11186 elsif($CompleteSignature{1}{$Func}{"PureVirt"} 11187 and not $CompleteSignature{2}{$Func}{"PureVirt"}) 11188 { # became non-pure virtual 11189 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=( 11190 "Type_Name"=>$CName, 11191 "Target"=>get_Signature_M($Func, 1) ); 11192 $VTableChanged_M{$CName} = 1; 11193 } 11194 } 11195 } 11196 if($Level eq "Binary") 11197 { # Binary-level 11198 # check virtual table structure 11199 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11200 { 11201 next if($Interface eq $AddedVFunc); 11202 next if($VirtualReplacement{$AddedVFunc}); 11203 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc}; 11204 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11205 { # pure virtual methods affect all others (virtual and non-virtual) 11206 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11207 "Type_Name"=>$CName, 11208 "Target"=>get_Signature($AddedVFunc, 2) ); 11209 $VTableChanged_M{$CName} = 1; 11210 } 11211 elsif(not defined $VirtualTable{1}{$CName} 11212 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}})) 11213 { # added virtual function at the end of v-table 11214 if(not keys(%{$VirtualTable_Model{1}{$CName}})) 11215 { # became polymorphous class, added v-table pointer 11216 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11217 "Type_Name"=>$CName, 11218 "Target"=>get_Signature($AddedVFunc, 2) ); 11219 $VTableChanged_M{$CName} = 1; 11220 } 11221 else 11222 { 11223 my $VSize_Old = getVTable_Size($CName, 1); 11224 my $VSize_New = getVTable_Size($CName, 2); 11225 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method 11226 if(isCopyingClass($Class_Id, 1)) 11227 { # class has no constructors and v-table will be copied by applications, this may affect all methods 11228 my $ProblemType = "Added_Virtual_Method"; 11229 if(isLeafClass($Class_Id, 1)) { 11230 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class"; 11231 } 11232 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11233 "Type_Name"=>$CName, 11234 "Target"=>get_Signature($AddedVFunc, 2) ); 11235 $VTableChanged_M{$CName} = 1; 11236 } 11237 else 11238 { 11239 my $ProblemType = "Added_Virtual_Method"; 11240 if(isLeafClass($Class_Id, 1)) { 11241 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class"; 11242 } 11243 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11244 "Type_Name"=>$CName, 11245 "Target"=>get_Signature($AddedVFunc, 2) ); 11246 $VTableChanged_M{$CName} = 1; 11247 } 11248 } 11249 } 11250 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11251 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11252 { 11253 if(defined $VirtualTable{1}{$CName} 11254 and defined $VirtualTable{2}{$CName}) 11255 { 11256 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11257 my $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11258 11259 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New) 11260 { 11261 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11262 foreach my $ASymbol (@Affected) 11263 { 11264 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11265 { 11266 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11267 next; 11268 } 11269 } 11270 $CheckedSymbols{$Level}{$ASymbol} = 1; 11271 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11272 "Type_Name"=>$CName, 11273 "Target"=>get_Signature($AddedVFunc, 2) ); 11274 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11275 } 11276 } 11277 } 11278 } 11279 else { 11280 # safe 11281 } 11282 } 11283 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11284 { 11285 next if($VirtualReplacement{$RemovedVFunc}); 11286 if($RemovedVFunc eq $Interface 11287 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11288 { # This case is for removed virtual methods 11289 # implemented in both versions of a library 11290 next; 11291 } 11292 if(not keys(%{$VirtualTable_Model{2}{$CName}})) 11293 { # became non-polymorphous class, removed v-table pointer 11294 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11295 "Type_Name"=>$CName, 11296 "Target"=>get_Signature($RemovedVFunc, 1) ); 11297 $VTableChanged_M{$CName} = 1; 11298 } 11299 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11300 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11301 { 11302 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName}) 11303 { 11304 if(not defined $VirtualTable{1}{$CName}{$Interface}) { 11305 next; 11306 } 11307 my $VPos_New = -1; 11308 if(defined $VirtualTable{2}{$CName}{$Interface}) 11309 { 11310 $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11311 } 11312 else 11313 { 11314 if($Interface ne $RemovedVFunc) { 11315 next; 11316 } 11317 } 11318 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc}; 11319 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11320 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New) 11321 { 11322 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11323 foreach my $ASymbol (@Affected) 11324 { 11325 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11326 { 11327 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11328 next; 11329 } 11330 } 11331 my $ProblemType = "Removed_Virtual_Method"; 11332 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { 11333 $ProblemType = "Removed_Pure_Virtual_Method"; 11334 } 11335 $CheckedSymbols{$Level}{$ASymbol} = 1; 11336 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=( 11337 "Type_Name"=>$CName, 11338 "Target"=>get_Signature($RemovedVFunc, 1) ); 11339 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11340 } 11341 } 11342 } 11343 } 11344 } 11345 } 11346 else 11347 { # Source-level 11348 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11349 { 11350 next if($Interface eq $AddedVFunc); 11351 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11352 { 11353 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11354 "Type_Name"=>$CName, 11355 "Target"=>get_Signature($AddedVFunc, 2) ); 11356 } 11357 } 11358 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11359 { 11360 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11361 { 11362 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11363 "Type_Name"=>$CName, 11364 "Target"=>get_Signature($RemovedVFunc, 1) ); 11365 } 11366 } 11367 } 11368} 11369 11370sub find_MemberPair_Pos_byName($$) 11371{ 11372 my ($Member_Name, $Pair_Type) = @_; 11373 $Member_Name=~s/\A[_]+|[_]+\Z//g; 11374 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11375 { 11376 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}) 11377 { 11378 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"}; 11379 $Name=~s/\A[_]+|[_]+\Z//g; 11380 if($Name eq $Member_Name) { 11381 return $MemberPair_Pos; 11382 } 11383 } 11384 } 11385 return "lost"; 11386} 11387 11388sub find_MemberPair_Pos_byVal($$) 11389{ 11390 my ($Member_Value, $Pair_Type) = @_; 11391 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11392 { 11393 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos} 11394 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) { 11395 return $MemberPair_Pos; 11396 } 11397 } 11398 return "lost"; 11399} 11400 11401sub isRecurType($$$) 11402{ 11403 foreach (@{$_[2]}) 11404 { 11405 if( $_->{"T1"} eq $_[0] 11406 and $_->{"T2"} eq $_[1] ) 11407 { 11408 return 1; 11409 } 11410 } 11411 return 0; 11412} 11413 11414sub pushType($$$) 11415{ 11416 my %IDs = ( 11417 "T1" => $_[0], 11418 "T2" => $_[1] 11419 ); 11420 push(@{$_[2]}, \%IDs); 11421} 11422 11423sub isRenamed($$$$$) 11424{ 11425 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_; 11426 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"}; 11427 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"}; 11428 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1}); 11429 if(not defined $Type2->{"Memb"}{$MemPos}) { 11430 return ""; 11431 } 11432 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"}; 11433 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2}); 11434 11435 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"}; 11436 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1); 11437 if($MemberPair_Pos_Rev eq "lost") 11438 { 11439 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"}) 11440 { # base type match 11441 return $Pair_Name; 11442 } 11443 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"}) 11444 { # exact type match 11445 return $Pair_Name; 11446 } 11447 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"}) 11448 { # size match 11449 return $Pair_Name; 11450 } 11451 if(isReserved($Pair_Name)) 11452 { # reserved fields 11453 return $Pair_Name; 11454 } 11455 } 11456 return ""; 11457} 11458 11459sub isLastElem($$) 11460{ 11461 my ($Pos, $TypeRef) = @_; 11462 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"}; 11463 if($Name=~/last|count|max|total|num/i) 11464 { # GST_LEVEL_COUNT, GST_RTSP_ELAST 11465 return 1; 11466 } 11467 elsif($Name=~/END|NLIMITS\Z/) 11468 { # __RLIMIT_NLIMITS 11469 return 1; 11470 } 11471 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/ 11472 and $Pos+1==keys(%{$TypeRef->{"Memb"}})) 11473 { # NImageFormats, NColorRoles 11474 return 1; 11475 } 11476 return 0; 11477} 11478 11479sub nonComparable($$) 11480{ 11481 my ($T1, $T2) = @_; 11482 11483 my $N1 = $T1->{"Name"}; 11484 my $N2 = $T2->{"Name"}; 11485 11486 $N1=~s/\A(struct|union|enum) //; 11487 $N2=~s/\A(struct|union|enum) //; 11488 11489 if($N1 ne $N2 11490 and not isAnon($N1) 11491 and not isAnon($N2)) 11492 { # different names 11493 if($T1->{"Type"} ne "Pointer" 11494 or $T2->{"Type"} ne "Pointer") 11495 { # compare base types 11496 return 1; 11497 } 11498 if($N1!~/\Avoid\s*\*/ 11499 and $N2=~/\Avoid\s*\*/) 11500 { 11501 return 1; 11502 } 11503 } 11504 elsif($T1->{"Type"} ne $T2->{"Type"}) 11505 { # different types 11506 if($T1->{"Type"} eq "Class" 11507 and $T2->{"Type"} eq "Struct") 11508 { # "class" to "struct" 11509 return 0; 11510 } 11511 elsif($T2->{"Type"} eq "Class" 11512 and $T1->{"Type"} eq "Struct") 11513 { # "struct" to "class" 11514 return 0; 11515 } 11516 else 11517 { # "class" to "enum" 11518 # "union" to "class" 11519 # ... 11520 return 1; 11521 } 11522 } 11523 return 0; 11524} 11525 11526sub isOpaque($) 11527{ 11528 my $T = $_[0]; 11529 if(not defined $T->{"Memb"}) 11530 { 11531 return 1; 11532 } 11533 return 0; 11534} 11535 11536sub removeVPtr($) 11537{ # support for old ABI dumps 11538 my $TPtr = $_[0]; 11539 my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}}); 11540 if($#Pos>=1) 11541 { 11542 foreach my $Pos (0 .. $#Pos-1) 11543 { 11544 %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}}; 11545 } 11546 delete($TPtr->{"Memb"}{$#Pos}); 11547 } 11548} 11549 11550sub isPrivateABI($$) 11551{ 11552 my ($TypeId, $LibVersion) = @_; 11553 11554 if($CheckPrivateABI) { 11555 return 0; 11556 } 11557 11558 if(defined $TypeInfo{$LibVersion}{$TypeId}{"PrivateABI"}) { 11559 return 1; 11560 } 11561 11562 return 0; 11563} 11564 11565sub mergeTypes($$$) 11566{ 11567 my ($Type1_Id, $Type2_Id, $Level) = @_; 11568 return {} if(not $Type1_Id or not $Type2_Id); 11569 11570 if(defined $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}) 11571 { # already merged 11572 return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}; 11573 } 11574 11575 my %Type1 = get_Type($Type1_Id, 1); 11576 my %Type2 = get_Type($Type2_Id, 2); 11577 if(not $Type1{"Name"} or not $Type2{"Name"}) { 11578 return {}; 11579 } 11580 11581 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 11582 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 11583 11584 if(defined $UsedDump{1}{"DWARF"}) 11585 { 11586 if($Type1_Pure{"Name"} eq "__unknown__" 11587 or $Type2_Pure{"Name"} eq "__unknown__") 11588 { # Error ABI dump 11589 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = {}); 11590 } 11591 } 11592 11593 if(isPrivateABI($Type1_Id, 1)) { 11594 return {}; 11595 } 11596 11597 $CheckedTypes{$Level}{$Type1{"Name"}} = 1; 11598 $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1; 11599 11600 my %SubProblems = (); 11601 11602 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 11603 { 11604 if($Type1_Pure{"Type"}=~/Struct|Union/ 11605 and $Type2_Pure{"Type"}=~/Struct|Union/) 11606 { 11607 if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure)) 11608 { 11609 if(not defined $UsedDump{1}{"DWARF"} 11610 and not defined $UsedDump{2}{"DWARF"}) 11611 { 11612 %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=( 11613 "Target"=>$Type1_Pure{"Name"}, 11614 "Type_Name"=>$Type1_Pure{"Name"} ); 11615 } 11616 11617 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11618 } 11619 } 11620 } 11621 11622 if(not $Type1_Pure{"Size"} 11623 or not $Type2_Pure{"Size"}) 11624 { # including a case when "class Class { ... };" changed to "class Class;" 11625 if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"} 11626 or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1) 11627 { # NOTE: template instances have no size 11628 return {}; 11629 } 11630 } 11631 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes)) 11632 { # skip recursive declarations 11633 return {}; 11634 } 11635 return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); 11636 return {} if($SkipTypes{1}{$Type1_Pure{"Name"}}); 11637 return {} if($SkipTypes{1}{$Type1{"Name"}}); 11638 11639 if(not isTargetType($Type1_Pure{"Tid"}, 1)) { 11640 return {}; 11641 } 11642 11643 if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/) 11644 { # support for old ABI dumps 11645 # _vptr field added in 3.0 11646 if(not checkDump(1, "3.0") and checkDump(2, "3.0")) 11647 { 11648 if(defined $Type2_Pure{"Memb"} 11649 and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr") 11650 { 11651 if(keys(%{$Type2_Pure{"Memb"}})==1) { 11652 delete($Type2_Pure{"Memb"}{0}); 11653 } 11654 else { 11655 removeVPtr(\%Type2_Pure); 11656 } 11657 } 11658 } 11659 if(checkDump(1, "3.0") and not checkDump(2, "3.0")) 11660 { 11661 if(defined $Type1_Pure{"Memb"} 11662 and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr") 11663 { 11664 if(keys(%{$Type1_Pure{"Memb"}})==1) { 11665 delete($Type1_Pure{"Memb"}{0}); 11666 } 11667 else { 11668 removeVPtr(\%Type1_Pure); 11669 } 11670 } 11671 } 11672 } 11673 11674 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 11675 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 11676 11677 if(%Typedef_1 and %Typedef_2 11678 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef" 11679 and $Typedef_1{"Name"} eq $Typedef_2{"Name"}) 11680 { 11681 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1}); 11682 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2}); 11683 if($Base_1{"Name"} ne $Base_2{"Name"}) 11684 { 11685 if(differentDumps("G") 11686 or differentDumps("V") 11687 or $SkipTypedefUncover) 11688 { # different GCC versions or different dumps 11689 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1); 11690 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2); 11691 # std::__va_list and __va_list 11692 $Base_1{"Name"}=~s/\A(\w+::)+//; 11693 $Base_2{"Name"}=~s/\A(\w+::)+//; 11694 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T"); 11695 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T"); 11696 } 11697 } 11698 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/ 11699 and $Base_1{"Name"} ne $Base_2{"Name"}) 11700 { 11701 if($Level eq "Binary" 11702 and $Type1{"Size"} and $Type2{"Size"} 11703 and $Type1{"Size"} ne $Type2{"Size"}) 11704 { 11705 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=( 11706 "Target"=>$Typedef_1{"Name"}, 11707 "Type_Name"=>$Typedef_1{"Name"}, 11708 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 11709 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE ); 11710 } 11711 my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1}); 11712 my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2}); 11713 11714 if(defined $UsedDump{1}{"DWARF"}) 11715 { 11716 if($Base1_Pure{"Name"}=~/\b__unknown__\b/ 11717 or $Base2_Pure{"Name"}=~/\b__unknown__\b/) 11718 { # Error ABI dump 11719 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = {}); 11720 } 11721 } 11722 11723 if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"})) 11724 { 11725 if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level)) 11726 { 11727 %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=( 11728 "Target"=>$Typedef_1{"Name"}, 11729 "Type_Name"=>$Typedef_1{"Name"}, 11730 "Old_Value"=>$Base_1{"Name"}, 11731 "New_Value"=>$Base_2{"Name"} ); 11732 } 11733 else 11734 { 11735 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=( 11736 "Target"=>$Typedef_1{"Name"}, 11737 "Type_Name"=>$Typedef_1{"Name"}, 11738 "Old_Value"=>$Base_1{"Name"}, 11739 "New_Value"=>$Base_2{"Name"} ); 11740 } 11741 } 11742 } 11743 } 11744 if(nonComparable(\%Type1_Pure, \%Type2_Pure)) 11745 { # different types (reported in detectTypeChange(...)) 11746 my $TT1 = $Type1_Pure{"Type"}; 11747 my $TT2 = $Type2_Pure{"Type"}; 11748 11749 if($TT1 ne $TT2 11750 and $TT1!~/Intrinsic|Pointer|Ref|Typedef/) 11751 { # different type of the type 11752 my $Short1 = $Type1_Pure{"Name"}; 11753 my $Short2 = $Type2_Pure{"Name"}; 11754 11755 $Short1=~s/\A\Q$TT1\E //ig; 11756 $Short2=~s/\A\Q$TT2\E //ig; 11757 11758 if($Short1 eq $Short2) 11759 { 11760 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=( 11761 "Target"=>$Type1_Pure{"Name"}, 11762 "Type_Name"=>$Type1_Pure{"Name"}, 11763 "Old_Value"=>lc($Type1_Pure{"Type"}), 11764 "New_Value"=>lc($Type2_Pure{"Type"}) ); 11765 } 11766 } 11767 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11768 } 11769 11770 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes); 11771 11772 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"} 11773 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"}))) 11774 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11775 { # checking size 11776 if($Level eq "Binary" 11777 and $Type1_Pure{"Size"} and $Type2_Pure{"Size"} 11778 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11779 { 11780 my $ProblemKind = "DataType_Size"; 11781 if($Type1_Pure{"Type"} eq "Class" 11782 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}})) 11783 { 11784 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) { 11785 $ProblemKind = "Size_Of_Copying_Class"; 11786 } 11787 elsif($AllocableClass{1}{$Type1_Pure{"Name"}}) 11788 { 11789 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) { 11790 $ProblemKind = "Size_Of_Allocable_Class_Increased"; 11791 } 11792 else 11793 { 11794 # descreased size of allocable class 11795 # it has no special effects 11796 } 11797 } 11798 } 11799 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=( 11800 "Target"=>$Type1_Pure{"Name"}, 11801 "Type_Name"=>$Type1_Pure{"Name"}, 11802 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE, 11803 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE); 11804 } 11805 } 11806 if(defined $Type1_Pure{"BaseType"} 11807 and defined $Type2_Pure{"BaseType"}) 11808 { # checking base types 11809 my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); 11810 foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) 11811 { 11812 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { 11813 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 11814 } 11815 } 11816 } 11817 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = (); 11818 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}}); 11819 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}}); 11820 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11821 { # detect removed and renamed fields 11822 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11823 next if(not $Member_Name); 11824 my $MemberPair_Pos = (defined $Type2_Pure{"Memb"}{$Member_Pos} and $Type2_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type2_Pure); 11825 if($MemberPair_Pos eq "lost") 11826 { 11827 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11828 { 11829 if(isUnnamed($Member_Name)) 11830 { # support for old-version dumps 11831 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11832 if(not checkDump(2, "2.1")) { 11833 next; 11834 } 11835 } 11836 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2)) 11837 { # renamed 11838 $RenamedField{$Member_Pos} = $RenamedTo; 11839 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11840 } 11841 else 11842 { # removed 11843 $RemovedField{$Member_Pos} = 1; 11844 } 11845 } 11846 elsif($Type1_Pure{"Type"} eq "Enum") 11847 { 11848 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 11849 next if($Member_Value1 eq ""); 11850 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure); 11851 if($MemberPair_Pos ne "lost") 11852 { # renamed 11853 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"}; 11854 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure); 11855 if($MemberPair_Pos_Rev eq "lost") 11856 { 11857 $RenamedField{$Member_Pos} = $RenamedTo; 11858 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11859 } 11860 else { 11861 $RemovedField{$Member_Pos} = 1; 11862 } 11863 } 11864 else 11865 { # removed 11866 $RemovedField{$Member_Pos} = 1; 11867 } 11868 } 11869 } 11870 else 11871 { # related 11872 $RelatedField{$Member_Pos} = $MemberPair_Pos; 11873 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos; 11874 } 11875 } 11876 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11877 { # detect added fields 11878 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11879 next if(not $Member_Name); 11880 my $MemberPair_Pos = (defined $Type1_Pure{"Memb"}{$Member_Pos} and $Type1_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type1_Pure); 11881 if($MemberPair_Pos eq "lost") 11882 { 11883 if(isUnnamed($Member_Name)) 11884 { # support for old-version dumps 11885 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11886 if(not checkDump(1, "2.1")) { 11887 next; 11888 } 11889 } 11890 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/) 11891 { 11892 if(not $RenamedField_Rev{$Member_Pos}) 11893 { # added 11894 $AddedField{$Member_Pos}=1; 11895 } 11896 } 11897 } 11898 } 11899 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 11900 { # detect moved fields 11901 my (%RelPos, %RelPosName, %AbsPos) = (); 11902 my $Pos = 0; 11903 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11904 { # relative positions in 1st version 11905 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11906 next if(not $Member_Name); 11907 if(not $RemovedField{$Member_Pos}) 11908 { # old type without removed fields 11909 $RelPos{1}{$Member_Name} = $Pos; 11910 $RelPosName{1}{$Pos} = $Member_Name; 11911 $AbsPos{1}{$Pos++} = $Member_Pos; 11912 } 11913 } 11914 $Pos = 0; 11915 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11916 { # relative positions in 2nd version 11917 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11918 next if(not $Member_Name); 11919 if(not $AddedField{$Member_Pos}) 11920 { # new type without added fields 11921 $RelPos{2}{$Member_Name} = $Pos; 11922 $RelPosName{2}{$Pos} = $Member_Name; 11923 $AbsPos{2}{$Pos++} = $Member_Pos; 11924 } 11925 } 11926 foreach my $Member_Name (keys(%{$RelPos{1}})) 11927 { 11928 my $RPos1 = $RelPos{1}{$Member_Name}; 11929 my $AbsPos1 = $NameToPosA{$Member_Name}; 11930 my $Member_Name2 = $Member_Name; 11931 if(my $RenamedTo = $RenamedField{$AbsPos1}) 11932 { # renamed 11933 $Member_Name2 = $RenamedTo; 11934 } 11935 my $RPos2 = $RelPos{2}{$Member_Name2}; 11936 if($RPos2 ne "" and $RPos1 ne $RPos2) 11937 { # different relative positions 11938 my $AbsPos2 = $NameToPosB{$Member_Name2}; 11939 if($AbsPos1 ne $AbsPos2) 11940 { # different absolute positions 11941 my $ProblemType = "Moved_Field"; 11942 if(not isPublic(\%Type1_Pure, $AbsPos1)) 11943 { # may change layout and size of type 11944 if($Level eq "Source") { 11945 next; 11946 } 11947 $ProblemType = "Moved_Private_Field"; 11948 } 11949 if($Level eq "Binary" 11950 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11951 { # affected size 11952 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"}; 11953 my $MovedAbsPos = $AbsPos{1}{$RPos2}; 11954 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"}; 11955 if($MemSize1 ne $MemSize2) { 11956 $ProblemType .= "_And_Size"; 11957 } 11958 } 11959 if($ProblemType eq "Moved_Private_Field") { 11960 next; 11961 } 11962 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11963 "Target"=>$Member_Name, 11964 "Type_Name"=>$Type1_Pure{"Name"}, 11965 "Old_Value"=>$RPos1, 11966 "New_Value"=>$RPos2 ); 11967 } 11968 } 11969 } 11970 } 11971 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11972 { # check older fields, public and private 11973 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11974 next if(not $Member_Name); 11975 next if($Member_Name eq "_vptr"); 11976 if(my $RenamedTo = $RenamedField{$Member_Pos}) 11977 { # renamed 11978 if(defined $Constants{2}{$Member_Name}) 11979 { 11980 if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo) 11981 { # define OLD NEW 11982 next; # Safe 11983 } 11984 } 11985 11986 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11987 { 11988 if(isPublic(\%Type1_Pure, $Member_Pos)) 11989 { 11990 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=( 11991 "Target"=>$Member_Name, 11992 "Type_Name"=>$Type1_Pure{"Name"}, 11993 "Old_Value"=>$Member_Name, 11994 "New_Value"=>$RenamedTo ); 11995 } 11996 elsif(isReserved($Member_Name)) 11997 { 11998 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=( 11999 "Target"=>$Member_Name, 12000 "Type_Name"=>$Type1_Pure{"Name"}, 12001 "Old_Value"=>$Member_Name, 12002 "New_Value"=>$RenamedTo ); 12003 } 12004 } 12005 elsif($Type1_Pure{"Type"} eq "Enum") 12006 { 12007 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=( 12008 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"}, 12009 "Type_Name"=>$Type1_Pure{"Name"}, 12010 "Old_Value"=>$Member_Name, 12011 "New_Value"=>$RenamedTo ); 12012 } 12013 } 12014 elsif($RemovedField{$Member_Pos}) 12015 { # removed 12016 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 12017 { 12018 my $ProblemType = "Removed_Field"; 12019 if(not isPublic(\%Type1_Pure, $Member_Pos) 12020 or isUnnamed($Member_Name)) 12021 { 12022 if($Level eq "Source") { 12023 next; 12024 } 12025 $ProblemType = "Removed_Private_Field"; 12026 } 12027 if($Level eq "Binary" 12028 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12029 { 12030 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12031 { # affected fields 12032 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12033 { # changed offset 12034 $ProblemType .= "_And_Layout"; 12035 } 12036 } 12037 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 12038 { # affected size 12039 $ProblemType .= "_And_Size"; 12040 } 12041 } 12042 if($ProblemType eq "Removed_Private_Field") { 12043 next; 12044 } 12045 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12046 "Target"=>$Member_Name, 12047 "Type_Name"=>$Type1_Pure{"Name"} ); 12048 } 12049 elsif($Type2_Pure{"Type"} eq "Union") 12050 { 12051 if($Level eq "Binary" 12052 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 12053 { 12054 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=( 12055 "Target"=>$Member_Name, 12056 "Type_Name"=>$Type1_Pure{"Name"} ); 12057 } 12058 else 12059 { 12060 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=( 12061 "Target"=>$Member_Name, 12062 "Type_Name"=>$Type1_Pure{"Name"} ); 12063 } 12064 } 12065 elsif($Type1_Pure{"Type"} eq "Enum") 12066 { 12067 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=( 12068 "Target"=>$Member_Name, 12069 "Type_Name"=>$Type1_Pure{"Name"}, 12070 "Old_Value"=>$Member_Name ); 12071 } 12072 } 12073 else 12074 { # changed 12075 my $MemberPair_Pos = $RelatedField{$Member_Pos}; 12076 if($Type1_Pure{"Type"} eq "Enum") 12077 { 12078 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 12079 next if($Member_Value1 eq ""); 12080 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"}; 12081 next if($Member_Value2 eq ""); 12082 if($Member_Value1 ne $Member_Value2) 12083 { 12084 my $ProblemType = "Enum_Member_Value"; 12085 if(isLastElem($Member_Pos, \%Type1_Pure)) { 12086 $ProblemType = "Enum_Last_Member_Value"; 12087 } 12088 if($SkipConstants{1}{$Member_Name}) { 12089 $ProblemType = "Enum_Private_Member_Value"; 12090 } 12091 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12092 "Target"=>$Member_Name, 12093 "Type_Name"=>$Type1_Pure{"Name"}, 12094 "Old_Value"=>$Member_Value1, 12095 "New_Value"=>$Member_Value2 ); 12096 } 12097 } 12098 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 12099 { 12100 my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"}; 12101 my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"}; 12102 12103 if($Access1 ne "private" 12104 and $Access2 eq "private") 12105 { 12106 %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=( 12107 "Target"=>$Member_Name, 12108 "Type_Name"=>$Type1_Pure{"Name"}); 12109 } 12110 elsif($Access1 ne "protected" 12111 and $Access1 ne "private" 12112 and $Access2 eq "protected") 12113 { 12114 %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=( 12115 "Target"=>$Member_Name, 12116 "Type_Name"=>$Type1_Pure{"Name"}); 12117 } 12118 12119 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"}; 12120 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"}; 12121 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE; 12122 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) { 12123 $SizeV1 = $BSize1; 12124 } 12125 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE; 12126 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) { 12127 $SizeV2 = $BSize2; 12128 } 12129 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"}; 12130 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"}; 12131 if($Level eq "Binary" 12132 and $SizeV1 and $SizeV2 12133 and $SizeV1 ne $SizeV2) 12134 { 12135 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name)) 12136 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})) 12137 { # field size change (including anon-structures and unions) 12138 # - same types 12139 # - unnamed types 12140 # - bitfields 12141 my $ProblemType = "Field_Size"; 12142 if(not isPublic(\%Type1_Pure, $Member_Pos) 12143 or isUnnamed($Member_Name)) 12144 { # should not be accessed by applications, goes to "Low Severity" 12145 # example: "abidata" members in GStreamer types 12146 $ProblemType = "Private_".$ProblemType; 12147 } 12148 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12149 { # check an effect 12150 if($Type2_Pure{"Type"} ne "Union" 12151 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12152 { # public fields after the current 12153 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12154 { # changed offset 12155 $ProblemType .= "_And_Layout"; 12156 } 12157 } 12158 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12159 $ProblemType .= "_And_Type_Size"; 12160 } 12161 } 12162 if($ProblemType eq "Private_Field_Size") 12163 { # private field size with no effect 12164 } 12165 if($ProblemType eq "Field_Size") 12166 { 12167 if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2) 12168 { # Low severity 12169 $ProblemType = "Struct_Field_Size_Increased"; 12170 } 12171 } 12172 if($ProblemType) 12173 { # register a problem 12174 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12175 "Target"=>$Member_Name, 12176 "Type_Name"=>$Type1_Pure{"Name"}, 12177 "Old_Size"=>$SizeV1, 12178 "New_Size"=>$SizeV2); 12179 } 12180 } 12181 } 12182 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} 12183 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) 12184 { # do NOT check bitfield type changes 12185 next; 12186 } 12187 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 12188 { 12189 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12190 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12191 { 12192 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=( 12193 "Target"=>$Member_Name, 12194 "Type_Name"=>$Type1_Pure{"Name"}); 12195 } 12196 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12197 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12198 { 12199 %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=( 12200 "Target"=>$Member_Name, 12201 "Type_Name"=>$Type1_Pure{"Name"}); 12202 } 12203 } 12204 my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); 12205 foreach my $ProblemType (keys(%Sub_SubChanges)) 12206 { 12207 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12208 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12209 12210 # quals 12211 if($ProblemType eq "Field_Type" 12212 or $ProblemType eq "Field_Type_And_Size" 12213 or $ProblemType eq "Field_Type_Format") 12214 { 12215 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 12216 { 12217 if(addedQual($Old_Value, $New_Value, "volatile")) { 12218 %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12219 } 12220 elsif(removedQual($Old_Value, $New_Value, "volatile")) { 12221 %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12222 } 12223 } 12224 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 12225 { 12226 if($RA==2) { 12227 %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12228 } 12229 else { 12230 %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12231 } 12232 } 12233 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 12234 { 12235 if($RR==2) { 12236 %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12237 } 12238 else { 12239 %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12240 } 12241 } 12242 } 12243 } 12244 12245 if($Level eq "Source") 12246 { 12247 foreach my $ProblemType (keys(%Sub_SubChanges)) 12248 { 12249 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12250 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12251 12252 if($ProblemType eq "Field_Type") 12253 { 12254 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 12255 delete($Sub_SubChanges{$ProblemType}); 12256 } 12257 } 12258 } 12259 } 12260 12261 foreach my $ProblemType (keys(%Sub_SubChanges)) 12262 { 12263 my $ProblemType_Init = $ProblemType; 12264 if($ProblemType eq "Field_Type_And_Size") 12265 { # Binary 12266 if(not isPublic(\%Type1_Pure, $Member_Pos) 12267 or isUnnamed($Member_Name)) { 12268 $ProblemType = "Private_".$ProblemType; 12269 } 12270 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12271 { # check an effect 12272 if($Type2_Pure{"Type"} ne "Union" 12273 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12274 { # public fields after the current 12275 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12276 { # changed offset 12277 $ProblemType .= "_And_Layout"; 12278 } 12279 } 12280 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12281 $ProblemType .= "_And_Type_Size"; 12282 } 12283 } 12284 } 12285 else 12286 { 12287 # TODO: Private_Field_Type rule? 12288 12289 if(not isPublic(\%Type1_Pure, $Member_Pos) 12290 or isUnnamed($Member_Name)) { 12291 next; 12292 } 12293 } 12294 if($ProblemType eq "Private_Field_Type_And_Size") 12295 { # private field change with no effect 12296 } 12297 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12298 "Target"=>$Member_Name, 12299 "Type_Name"=>$Type1_Pure{"Name"}); 12300 12301 foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}})) 12302 { # other properties 12303 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr}; 12304 } 12305 } 12306 if(not isPublic(\%Type1_Pure, $Member_Pos)) 12307 { # do NOT check internal type changes 12308 next; 12309 } 12310 if($MemberType1_Id and $MemberType2_Id) 12311 { # checking member type changes 12312 my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); 12313 12314 my %DupProblems = (); 12315 12316 foreach my $Sub_SubProblemType (sort keys(%{$Sub_SubProblems})) 12317 { 12318 foreach my $Sub_SubLocation (sort {length($a)<=>length($b)} sort keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) 12319 { 12320 if(not defined $AllAffected) 12321 { 12322 if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) { 12323 next; 12324 } 12325 } 12326 12327 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; 12328 $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 12329 12330 if(not defined $AllAffected) 12331 { 12332 $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1; 12333 } 12334 } 12335 } 12336 12337 %DupProblems = (); 12338 } 12339 } 12340 } 12341 } 12342 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 12343 { # checking added members, public and private 12344 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 12345 next if(not $Member_Name); 12346 next if($Member_Name eq "_vptr"); 12347 if($AddedField{$Member_Pos}) 12348 { # added 12349 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 12350 { 12351 my $ProblemType = "Added_Field"; 12352 if(not isPublic(\%Type2_Pure, $Member_Pos) 12353 or isUnnamed($Member_Name)) 12354 { 12355 if($Level eq "Source") { 12356 next; 12357 } 12358 $ProblemType = "Added_Private_Field"; 12359 } 12360 if($Level eq "Binary" 12361 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12362 { 12363 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1)) 12364 { # public fields after the current 12365 if(getOffset($MNum-1, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12366 { # changed offset 12367 $ProblemType .= "_And_Layout"; 12368 } 12369 } 12370 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12371 $ProblemType .= "_And_Size"; 12372 } 12373 } 12374 if($ProblemType eq "Added_Private_Field") 12375 { # skip added private fields 12376 next; 12377 } 12378 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12379 "Target"=>$Member_Name, 12380 "Type_Name"=>$Type1_Pure{"Name"}); 12381 } 12382 elsif($Type2_Pure{"Type"} eq "Union") 12383 { 12384 if($Level eq "Binary" 12385 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 12386 { 12387 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=( 12388 "Target"=>$Member_Name, 12389 "Type_Name"=>$Type1_Pure{"Name"}); 12390 } 12391 else 12392 { 12393 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=( 12394 "Target"=>$Member_Name, 12395 "Type_Name"=>$Type1_Pure{"Name"}); 12396 } 12397 } 12398 elsif($Type2_Pure{"Type"} eq "Enum") 12399 { 12400 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"}; 12401 next if($Member_Value eq ""); 12402 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=( 12403 "Target"=>$Member_Name, 12404 "Type_Name"=>$Type2_Pure{"Name"}, 12405 "New_Value"=>$Member_Value); 12406 } 12407 } 12408 } 12409 12410 if($Type1_Pure{"Type"} eq "FuncPtr") 12411 { 12412 foreach my $PPos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Param"}})) 12413 { 12414 if(not defined $Type2_Pure{"Param"}{$PPos}) { 12415 next; 12416 } 12417 12418 my $PT1 = $Type1_Pure{"Param"}{$PPos}{"type"}; 12419 my $PT2 = $Type2_Pure{"Param"}{$PPos}{"type"}; 12420 12421 my $PName = "p".$PPos; 12422 12423 my $FP_SubProblems = mergeTypes($PT1, $PT2, $Level); 12424 my %DupProblems = (); 12425 12426 foreach my $FP_SubProblemType (keys(%{$FP_SubProblems})) 12427 { 12428 foreach my $FP_SubLocation (keys(%{$FP_SubProblems->{$FP_SubProblemType}})) 12429 { 12430 if(not defined $AllAffected) 12431 { 12432 if(defined $DupProblems{$FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}}) { 12433 next; 12434 } 12435 } 12436 12437 my $NewLocation = ($FP_SubLocation)?$PName."->".$FP_SubLocation:$PName; 12438 $SubProblems{$FP_SubProblemType}{$NewLocation} = $FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}; 12439 12440 if(not defined $AllAffected) 12441 { 12442 $DupProblems{$FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}} = 1; 12443 } 12444 } 12445 } 12446 12447 %DupProblems = (); 12448 } 12449 } 12450 12451 pop(@RecurTypes); 12452 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 12453} 12454 12455sub isUnnamed($) { 12456 return $_[0]=~/\Aunnamed\d+\Z/; 12457} 12458 12459sub get_ShortClass($$) 12460{ 12461 my ($TypeId, $LibVersion) = @_; 12462 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 12463 if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) { 12464 $TypeName = uncover_typedefs($TypeName, $LibVersion); 12465 } 12466 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) { 12467 $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g; 12468 } 12469 return $TypeName; 12470} 12471 12472sub goToFirst($$$) 12473{ 12474 my ($TypeId, $LibVersion, $Type_Type) = @_; 12475 return () if(not $TypeId); 12476 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) { 12477 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}}; 12478 } 12479 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12480 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12481 return () if(not $Type{"Type"}); 12482 if($Type{"Type"} ne $Type_Type) 12483 { 12484 return () if(not $Type{"BaseType"}); 12485 %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type); 12486 } 12487 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type; 12488 return %Type; 12489} 12490 12491my %TypeSpecAttributes = ( 12492 "Const" => 1, 12493 "Volatile" => 1, 12494 "ConstVolatile" => 1, 12495 "Restrict" => 1, 12496 "Typedef" => 1 12497); 12498 12499sub get_PureType($$) 12500{ 12501 my ($TypeId, $Info) = @_; 12502 if(not $TypeId or not $Info 12503 or not $Info->{$TypeId}) { 12504 return (); 12505 } 12506 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) { 12507 return %{$Cache{"get_PureType"}{$TypeId}{$Info}}; 12508 } 12509 my %Type = %{$Info->{$TypeId}}; 12510 return %Type if(not $Type{"BaseType"}); 12511 if($TypeSpecAttributes{$Type{"Type"}}) { 12512 %Type = get_PureType($Type{"BaseType"}, $Info); 12513 } 12514 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type; 12515 return %Type; 12516} 12517 12518sub get_PLevel($$) 12519{ 12520 my ($TypeId, $LibVersion) = @_; 12521 return 0 if(not $TypeId); 12522 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) { 12523 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion}; 12524 } 12525 return 0 if(not $TypeInfo{$LibVersion}{$TypeId}); 12526 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12527 return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/); 12528 my $PLevel = 0; 12529 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) { 12530 $PLevel += 1; 12531 } 12532 return $PLevel if(not $Type{"BaseType"}); 12533 $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion); 12534 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel; 12535 return $PLevel; 12536} 12537 12538sub get_BaseType($$) 12539{ 12540 my ($TypeId, $LibVersion) = @_; 12541 return () if(not $TypeId); 12542 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) { 12543 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}}; 12544 } 12545 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12546 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12547 return %Type if(not $Type{"BaseType"}); 12548 %Type = get_BaseType($Type{"BaseType"}, $LibVersion); 12549 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type; 12550 return %Type; 12551} 12552 12553sub get_BaseTypeQual($$) 12554{ 12555 my ($TypeId, $LibVersion) = @_; 12556 return "" if(not $TypeId); 12557 return "" if(not $TypeInfo{$LibVersion}{$TypeId}); 12558 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12559 return "" if(not $Type{"BaseType"}); 12560 my $Qual = ""; 12561 if($Type{"Type"} eq "Pointer") { 12562 $Qual .= "*"; 12563 } 12564 elsif($Type{"Type"} eq "Ref") { 12565 $Qual .= "&"; 12566 } 12567 elsif($Type{"Type"} eq "ConstVolatile") { 12568 $Qual .= "const volatile"; 12569 } 12570 elsif($Type{"Type"} eq "Const" 12571 or $Type{"Type"} eq "Volatile" 12572 or $Type{"Type"} eq "Restrict") { 12573 $Qual .= lc($Type{"Type"}); 12574 } 12575 my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion); 12576 return $BQual.$Qual; 12577} 12578 12579sub get_OneStep_BaseType($$) 12580{ 12581 my ($TypeId, $Info) = @_; 12582 if(not $TypeId or not $Info 12583 or not $Info->{$TypeId}) { 12584 return (); 12585 } 12586 my %Type = %{$Info->{$TypeId}}; 12587 return %Type if(not $Type{"BaseType"}); 12588 if(my $BTid = $Type{"BaseType"}) 12589 { 12590 if($Info->{$BTid}) { 12591 return %{$Info->{$BTid}}; 12592 } 12593 else { # something is going wrong 12594 return (); 12595 } 12596 } 12597 else { 12598 return %Type; 12599 } 12600} 12601 12602sub get_Type($$) 12603{ 12604 my ($TypeId, $LibVersion) = @_; 12605 return () if(not $TypeId); 12606 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12607 return %{$TypeInfo{$LibVersion}{$TypeId}}; 12608} 12609 12610sub isPrivateData($) 12611{ # non-public global data 12612 my $Symbol = $_[0]; 12613 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/); 12614} 12615 12616sub isInLineInst($$) { 12617 return (isTemplateInstance(@_) and not isTemplateSpec(@_)); 12618} 12619 12620sub isTemplateInstance($$) 12621{ 12622 my ($SInfo, $LibVersion) = @_; 12623 12624 if(my $ClassId = $SInfo->{"Class"}) 12625 { 12626 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}) 12627 { 12628 if(index($ClassName,"<")!=-1) { 12629 return 1; 12630 } 12631 } 12632 } 12633 if(my $ShortName = $SInfo->{"ShortName"}) 12634 { 12635 if(index($ShortName,"<")!=-1 12636 and index($ShortName,">")!=-1) { 12637 return 1; 12638 } 12639 } 12640 12641 return 0; 12642} 12643 12644sub isTemplateSpec($$) 12645{ 12646 my ($SInfo, $LibVersion) = @_; 12647 if(my $ClassId = $SInfo->{"Class"}) 12648 { 12649 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"}) 12650 { # class specialization 12651 return 1; 12652 } 12653 elsif($SInfo->{"Spec"}) 12654 { # method specialization 12655 return 1; 12656 } 12657 } 12658 return 0; 12659} 12660 12661sub symbolFilter($$$$) 12662{ # some special cases when the symbol cannot be imported 12663 my ($Symbol, $LibVersion, $Type, $Level) = @_; 12664 12665 if(isPrivateData($Symbol)) 12666 { # non-public global data 12667 return 0; 12668 } 12669 12670 if(defined $SkipInternalSymbols) 12671 { 12672 return 0 if($Symbol=~/($SkipInternalSymbols)/); 12673 } 12674 12675 if($Symbol=~/\A_Z/) 12676 { 12677 if($Symbol=~/[CD][3-4]E/) { 12678 return 0; 12679 } 12680 } 12681 12682 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7")) 12683 { # support for old ABI dumps in --headers-only mode 12684 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 12685 { 12686 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}) 12687 { 12688 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"}; 12689 if(not $PType or $PType eq "Unknown") { 12690 return 0; 12691 } 12692 } 12693 } 12694 } 12695 if($Type=~/Affected/) 12696 { 12697 my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"}; 12698 12699 if($SkipSymbols{$LibVersion}{$Symbol}) 12700 { # user defined symbols to ignore 12701 return 0; 12702 } 12703 12704 if($SymbolsListPath and not $SymbolsList{$Symbol}) 12705 { # user defined symbols 12706 if(not $TargetHeadersPath or not $Header 12707 or not is_target_header($Header, 1)) 12708 { # -symbols-list | -headers-list 12709 return 0; 12710 } 12711 } 12712 12713 if($AppPath and not $SymbolsList_App{$Symbol}) 12714 { # user defined symbols (in application) 12715 return 0; 12716 } 12717 12718 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}; 12719 12720 if($ClassId) 12721 { 12722 if(not isTargetType($ClassId, $LibVersion)) { 12723 return 0; 12724 } 12725 } 12726 12727 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 12728 if(not $NameSpace and $ClassId) 12729 { # class methods have no "NameSpace" attribute 12730 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}; 12731 } 12732 if($NameSpace) 12733 { # user defined namespaces to ignore 12734 if($SkipNameSpaces{$LibVersion}{$NameSpace}) { 12735 return 0; 12736 } 12737 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}})) 12738 { # nested namespaces 12739 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) { 12740 return 0; 12741 } 12742 } 12743 } 12744 if($Header) 12745 { 12746 if(my $Skip = skipHeader($Header, $LibVersion)) 12747 { # --skip-headers or <skip_headers> (not <skip_including>) 12748 if($Skip==1) { 12749 return 0; 12750 } 12751 } 12752 } 12753 if($TypesListPath and $ClassId) 12754 { # user defined types 12755 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 12756 12757 if(not $TypesList{$CName}) 12758 { 12759 if(my $NS = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}) 12760 { 12761 $CName=~s/\A\Q$NS\E\:\://g; 12762 } 12763 12764 if(not $TypesList{$CName}) 12765 { 12766 my $Found = 0; 12767 12768 while($CName=~s/\:\:.+?\Z//) 12769 { 12770 if($TypesList{$CName}) 12771 { 12772 $Found = 1; 12773 last; 12774 } 12775 } 12776 12777 if(not $Found) { 12778 return 0; 12779 } 12780 } 12781 } 12782 } 12783 12784 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion)) 12785 { # non-target symbols 12786 return 0; 12787 } 12788 if($Level eq "Binary") 12789 { 12790 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 12791 or isInLineInst($CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) 12792 { 12793 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 12794 { # inline virtual methods 12795 if($Type=~/InlineVirt/) { 12796 return 1; 12797 } 12798 my $Allocable = (not isCopyingClass($ClassId, $LibVersion)); 12799 if(not $Allocable) 12800 { # check bases 12801 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1)) 12802 { 12803 if(not isCopyingClass($DCId, $LibVersion)) 12804 { # exists a derived class without default c-tor 12805 $Allocable=1; 12806 last; 12807 } 12808 } 12809 } 12810 if(not $Allocable) { 12811 return 0; 12812 } 12813 } 12814 else 12815 { # inline non-virtual methods 12816 return 0; 12817 } 12818 } 12819 } 12820 } 12821 return 1; 12822} 12823 12824sub detectAdded($) 12825{ 12826 my $Level = $_[0]; 12827 foreach my $Symbol (keys(%{$Symbol_Library{2}})) 12828 { 12829 if(link_symbol($Symbol, 1, "+Deps")) 12830 { # linker can find a new symbol 12831 # in the old-version library 12832 # So, it's not a new symbol 12833 next; 12834 } 12835 if(my $VSym = $SymVer{2}{$Symbol} 12836 and index($Symbol,"\@")==-1) { 12837 next; 12838 } 12839 $AddedInt{$Level}{$Symbol} = 1; 12840 } 12841} 12842 12843sub detectRemoved($) 12844{ 12845 my $Level = $_[0]; 12846 foreach my $Symbol (keys(%{$Symbol_Library{1}})) 12847 { 12848 if(link_symbol($Symbol, 2, "+Deps")) 12849 { # linker can find an old symbol 12850 # in the new-version library 12851 next; 12852 } 12853 if(my $VSym = $SymVer{1}{$Symbol} 12854 and index($Symbol,"\@")==-1) { 12855 next; 12856 } 12857 $RemovedInt{$Level}{$Symbol} = 1; 12858 } 12859} 12860 12861sub mergeLibs($) 12862{ 12863 my $Level = $_[0]; 12864 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 12865 { # checking added symbols 12866 next if($CompleteSignature{2}{$Symbol}{"Private"}); 12867 next if(not $CompleteSignature{2}{$Symbol}{"Header"}); 12868 next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level)); 12869 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 12870 } 12871 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 12872 { # checking removed symbols 12873 next if($CompleteSignature{1}{$Symbol}{"Private"}); 12874 next if(not $CompleteSignature{1}{$Symbol}{"Header"}); 12875 if(index($Symbol, "_ZTV")==0) 12876 { # skip v-tables for templates, that should not be imported by applications 12877 next if($tr_name{$Symbol}=~/</); 12878 if(my $CName = $VTableClass{$Symbol}) 12879 { 12880 if(not keys(%{$ClassMethods{$Level}{1}{$CName}})) 12881 { # vtables for "private" classes 12882 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol 12883 next; 12884 } 12885 } 12886 12887 if($SkipSymbols{1}{$Symbol}) 12888 { # user defined symbols to ignore 12889 next; 12890 } 12891 } 12892 else { 12893 next if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)); 12894 } 12895 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) 12896 { # symbols for pure virtual methods cannot be called by clients 12897 next; 12898 } 12899 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 12900 } 12901} 12902 12903sub checkDump($$) 12904{ 12905 my ($LibVersion, $V) = @_; 12906 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) { 12907 return $Cache{"checkDump"}{$LibVersion}{$V}; 12908 } 12909 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0)); 12910} 12911 12912sub detectAdded_H($) 12913{ 12914 my $Level = $_[0]; 12915 foreach my $Symbol (sort keys(%{$CompleteSignature{2}})) 12916 { 12917 if($Level eq "Source") 12918 { # remove symbol version 12919 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12920 $Symbol=$SN; 12921 12922 if($CompleteSignature{2}{$Symbol}{"Artificial"}) 12923 { # skip artificial constructors 12924 next; 12925 } 12926 } 12927 if(not $CompleteSignature{2}{$Symbol}{"Header"} 12928 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) { 12929 next; 12930 } 12931 if($ExtendedSymbols{$Symbol}) { 12932 next; 12933 } 12934 if(not defined $CompleteSignature{1}{$Symbol} 12935 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) 12936 { 12937 if($UsedDump{2}{"SrcBin"}) 12938 { 12939 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11")) 12940 { # support for old and different (!) ABI dumps 12941 if(not $CompleteSignature{2}{$Symbol}{"Virt"} 12942 and not $CompleteSignature{2}{$Symbol}{"PureVirt"}) 12943 { 12944 if($CheckHeadersOnly) 12945 { 12946 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"}) 12947 { 12948 if($Lang eq "C") 12949 { # support for old ABI dumps: missed extern "C" functions 12950 next; 12951 } 12952 } 12953 } 12954 else 12955 { 12956 if(not link_symbol($Symbol, 2, "-Deps")) 12957 { # skip added inline symbols and const global data 12958 next; 12959 } 12960 } 12961 } 12962 } 12963 } 12964 $AddedInt{$Level}{$Symbol} = 1; 12965 } 12966 } 12967} 12968 12969sub detectRemoved_H($) 12970{ 12971 my $Level = $_[0]; 12972 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 12973 { 12974 my $ISymbol = $Symbol; 12975 12976 if($Level eq "Source") 12977 { # remove symbol version 12978 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12979 $Symbol = $SN; 12980 } 12981 12982 if(not $CompleteSignature{1}{$Symbol}{"Header"} 12983 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) { 12984 next; 12985 } 12986 if($ExtendedSymbols{$Symbol}) { 12987 next; 12988 } 12989 if(not defined $CompleteSignature{2}{$Symbol} 12990 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) 12991 { 12992 if(defined $UsedDump{1}{"DWARF"} 12993 and defined $UsedDump{2}{"DWARF"} 12994 and $Level eq "Source") 12995 { # not present in debug-info, 12996 # but present in dynsym 12997 if(link_symbol($Symbol, 2, "-Deps")) { 12998 next; 12999 } 13000 13001 if($ISymbol ne $Symbol) 13002 { 13003 if(link_symbol($ISymbol, 2, "-Deps")) { 13004 next; 13005 } 13006 } 13007 13008 if(my $SVer = $SymVer{2}{$Symbol}) 13009 { 13010 if(link_symbol($SVer, 2, "-Deps")) { 13011 next; 13012 } 13013 } 13014 13015 if(my $Alias = $CompleteSignature{1}{$ISymbol}{"Alias"}) 13016 { 13017 if(link_symbol($Alias, 2, "-Deps")) { 13018 next; 13019 } 13020 13021 if(my $SAVer = $SymVer{2}{$Alias}) 13022 { 13023 if(link_symbol($SAVer, 2, "-Deps")) { 13024 next; 13025 } 13026 } 13027 } 13028 } 13029 if($UsedDump{1}{"SrcBin"}) 13030 { 13031 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11")) 13032 { # support for old and different (!) ABI dumps 13033 if(not $CompleteSignature{1}{$Symbol}{"Virt"} 13034 and not $CompleteSignature{1}{$Symbol}{"PureVirt"}) 13035 { 13036 if($CheckHeadersOnly) 13037 { # skip all removed symbols 13038 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"}) 13039 { 13040 if($Lang eq "C") 13041 { # support for old ABI dumps: missed extern "C" functions 13042 next; 13043 } 13044 } 13045 } 13046 else 13047 { 13048 if(not link_symbol($Symbol, 1, "-Deps")) 13049 { # skip removed inline symbols 13050 next; 13051 } 13052 } 13053 } 13054 } 13055 } 13056 if(not checkDump(1, "2.15")) 13057 { 13058 if($Symbol=~/_IT_E\Z/) 13059 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E 13060 next; 13061 } 13062 } 13063 if(not $CompleteSignature{1}{$Symbol}{"Class"}) 13064 { 13065 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"}) 13066 { 13067 if(defined $Constants{2}{$Short}) 13068 { 13069 my $Val = $Constants{2}{$Short}{"Value"}; 13070 if(defined $Func_ShortName{2}{$Val}) 13071 { # old name defined to new 13072 next; 13073 } 13074 } 13075 } 13076 13077 } 13078 $RemovedInt{$Level}{$Symbol} = 1; 13079 if($Level eq "Source") 13080 { # search for a source-compatible equivalent 13081 setAlternative($Symbol, $Level); 13082 } 13083 } 13084 } 13085} 13086 13087sub mergeHeaders($) 13088{ 13089 my $Level = $_[0]; 13090 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 13091 { # checking added symbols 13092 next if($CompleteSignature{2}{$Symbol}{"PureVirt"}); 13093 next if($CompleteSignature{2}{$Symbol}{"Private"}); 13094 next if(not symbolFilter($Symbol, 2, "Affected", $Level)); 13095 if($Level eq "Binary") 13096 { 13097 if($CompleteSignature{2}{$Symbol}{"InLine"}) 13098 { 13099 if(not $CompleteSignature{2}{$Symbol}{"Virt"}) 13100 { # skip inline non-virtual functions 13101 next; 13102 } 13103 } 13104 } 13105 else 13106 { # Source 13107 if($SourceAlternative_B{$Symbol}) { 13108 next; 13109 } 13110 } 13111 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 13112 } 13113 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 13114 { # checking removed symbols 13115 next if($CompleteSignature{1}{$Symbol}{"PureVirt"}); 13116 next if($CompleteSignature{1}{$Symbol}{"Private"}); 13117 next if(not symbolFilter($Symbol, 1, "Affected", $Level)); 13118 if($Level eq "Binary") 13119 { 13120 if($CompleteSignature{1}{$Symbol}{"InLine"}) 13121 { 13122 if(not $CompleteSignature{1}{$Symbol}{"Virt"}) 13123 { # skip inline non-virtual functions 13124 next; 13125 } 13126 } 13127 } 13128 else 13129 { # Source 13130 if(my $Alt = $SourceAlternative{$Symbol}) 13131 { 13132 if(defined $CompleteSignature{1}{$Alt} 13133 and $CompleteSignature{1}{$Symbol}{"Const"}) 13134 { 13135 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 13136 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=( 13137 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"}, 13138 "Target"=>get_Signature($Alt, 1)); 13139 } 13140 else 13141 { # do NOT show removed symbol 13142 next; 13143 } 13144 } 13145 } 13146 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 13147 } 13148} 13149 13150sub addParamNames($) 13151{ 13152 my $LibraryVersion = $_[0]; 13153 return if(not keys(%AddIntParams)); 13154 my $SecondVersion = $LibraryVersion==1?2:1; 13155 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}})) 13156 { 13157 next if(not keys(%{$AddIntParams{$Interface}})); 13158 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}})) 13159 { # add absent parameter names 13160 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"}; 13161 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos}) 13162 { # names from the external file 13163 if(defined $CompleteSignature{$SecondVersion}{$Interface} 13164 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}) 13165 { 13166 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) { 13167 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 13168 } 13169 } 13170 else { 13171 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 13172 } 13173 } 13174 } 13175 } 13176} 13177 13178sub detectChangedTypedefs() 13179{ # detect changed typedefs to show 13180 # correct function signatures 13181 foreach my $Typedef (keys(%{$Typedef_BaseName{1}})) 13182 { 13183 next if(not $Typedef); 13184 my $BName1 = $Typedef_BaseName{1}{$Typedef}; 13185 if(not $BName1 or isAnon($BName1)) { 13186 next; 13187 } 13188 my $BName2 = $Typedef_BaseName{2}{$Typedef}; 13189 if(not $BName2 or isAnon($BName2)) { 13190 next; 13191 } 13192 if($BName1 ne $BName2) { 13193 $ChangedTypedef{$Typedef} = 1; 13194 } 13195 } 13196} 13197 13198sub get_symbol_suffix($$) 13199{ 13200 my ($Symbol, $Full) = @_; 13201 my ($SN, $SO, $SV) = separate_symbol($Symbol); 13202 $Symbol=$SN; # remove version 13203 my $Signature = $tr_name{$Symbol}; 13204 my $Suffix = substr($Signature, find_center($Signature, "(")); 13205 if(not $Full) { 13206 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g; 13207 } 13208 return $Suffix; 13209} 13210 13211sub get_symbol_prefix($$) 13212{ 13213 my ($Symbol, $LibVersion) = @_; 13214 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 13215 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 13216 { # methods 13217 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName; 13218 } 13219 return $ShortName; 13220} 13221 13222sub setAlternative($) 13223{ 13224 my $Symbol = $_[0]; 13225 my $PSymbol = $Symbol; 13226 if(not defined $CompleteSignature{2}{$PSymbol} 13227 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"} 13228 and not $CompleteSignature{2}{$PSymbol}{"ShortName"})) 13229 { # search for a pair 13230 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"}) 13231 { 13232 if($CompleteSignature{1}{$PSymbol}{"Data"}) 13233 { 13234 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/ 13235 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/) 13236 { 13237 if(defined $CompleteSignature{2}{$PSymbol} 13238 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13239 { 13240 $SourceAlternative{$Symbol} = $PSymbol; 13241 $SourceAlternative_B{$PSymbol} = $Symbol; 13242 if(not defined $CompleteSignature{1}{$PSymbol} 13243 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 13244 $SourceReplacement{$Symbol} = $PSymbol; 13245 } 13246 } 13247 } 13248 } 13249 else 13250 { 13251 foreach my $Sp ("KV", "VK", "K", "V") 13252 { 13253 if($PSymbol=~s/\A_ZN$Sp/_ZN/ 13254 or $PSymbol=~s/\A_ZN/_ZN$Sp/) 13255 { 13256 if(defined $CompleteSignature{2}{$PSymbol} 13257 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13258 { 13259 $SourceAlternative{$Symbol} = $PSymbol; 13260 $SourceAlternative_B{$PSymbol} = $Symbol; 13261 if(not defined $CompleteSignature{1}{$PSymbol} 13262 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 13263 $SourceReplacement{$Symbol} = $PSymbol; 13264 } 13265 } 13266 } 13267 $PSymbol = $Symbol; 13268 } 13269 } 13270 } 13271 } 13272 return ""; 13273} 13274 13275sub getSymKind($$) 13276{ 13277 my ($Symbol, $LibVersion) = @_; 13278 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}) 13279 { 13280 return "Global_Data"; 13281 } 13282 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 13283 { 13284 return "Method"; 13285 } 13286 return "Function"; 13287} 13288 13289sub mergeSymbols($) 13290{ 13291 my $Level = $_[0]; 13292 my %SubProblems = (); 13293 13294 mergeBases($Level); 13295 13296 my %AddedOverloads = (); 13297 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 13298 { # check all added exported symbols 13299 if(not $CompleteSignature{2}{$Symbol}{"Header"}) { 13300 next; 13301 } 13302 if(defined $CompleteSignature{1}{$Symbol} 13303 and $CompleteSignature{1}{$Symbol}{"Header"}) 13304 { # double-check added symbol 13305 next; 13306 } 13307 if(not symbolFilter($Symbol, 2, "Affected", $Level)) { 13308 next; 13309 } 13310 if($Symbol=~/\A(_Z|\?)/) 13311 { # C++ 13312 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol; 13313 } 13314 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"}) 13315 { # register virtual overridings 13316 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"}; 13317 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"}; 13318 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} 13319 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"}) 13320 { 13321 if($TName_Tid{1}{$AffectedClass_Name}) 13322 { # class should exist in previous version 13323 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1)) 13324 { # old v-table is NOT copied by old applications 13325 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=( 13326 "Type_Name"=>$AffectedClass_Name, 13327 "Target"=>get_Signature($Symbol, 2), 13328 "Old_Value"=>get_Signature($OverriddenMethod, 2), 13329 "New_Value"=>get_Signature($Symbol, 2)); 13330 } 13331 } 13332 } 13333 } 13334 } 13335 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 13336 { # check all removed exported symbols 13337 if(not $CompleteSignature{1}{$Symbol}{"Header"}) { 13338 next; 13339 } 13340 if(defined $CompleteSignature{2}{$Symbol} 13341 and $CompleteSignature{2}{$Symbol}{"Header"}) 13342 { # double-check removed symbol 13343 next; 13344 } 13345 if($CompleteSignature{1}{$Symbol}{"Private"}) 13346 { # skip private methods 13347 next; 13348 } 13349 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 13350 next; 13351 } 13352 $CheckedSymbols{$Level}{$Symbol} = 1; 13353 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"}) 13354 { # register virtual overridings 13355 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 13356 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"}; 13357 if(defined $CompleteSignature{2}{$OverriddenMethod} 13358 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"}) 13359 { 13360 if($TName_Tid{2}{$AffectedClass_Name}) 13361 { # class should exist in newer version 13362 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1)) 13363 { # old v-table is NOT copied by old applications 13364 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=( 13365 "Type_Name"=>$AffectedClass_Name, 13366 "Target"=>get_Signature($OverriddenMethod, 1), 13367 "Old_Value"=>get_Signature($Symbol, 1), 13368 "New_Value"=>get_Signature($OverriddenMethod, 1)); 13369 } 13370 } 13371 } 13372 } 13373 if($Level eq "Binary" 13374 and $OStarget eq "windows") 13375 { # register the reason of symbol name change 13376 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}}) 13377 { 13378 if($AddedInt{$Level}{$NewSym}) 13379 { 13380 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"}) 13381 { 13382 if($CompleteSignature{2}{$NewSym}{"Static"}) 13383 { 13384 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=( 13385 "Target"=>$tr_name{$Symbol}, 13386 "Old_Value"=>$Symbol, 13387 "New_Value"=>$NewSym ); 13388 } 13389 else 13390 { 13391 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=( 13392 "Target"=>$tr_name{$Symbol}, 13393 "Old_Value"=>$Symbol, 13394 "New_Value"=>$NewSym ); 13395 } 13396 } 13397 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"}) 13398 { 13399 if($CompleteSignature{2}{$NewSym}{"Virt"}) 13400 { 13401 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=( 13402 "Target"=>$tr_name{$Symbol}, 13403 "Old_Value"=>$Symbol, 13404 "New_Value"=>$NewSym ); 13405 } 13406 else 13407 { 13408 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=( 13409 "Target"=>$tr_name{$Symbol}, 13410 "Old_Value"=>$Symbol, 13411 "New_Value"=>$NewSym ); 13412 } 13413 } 13414 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"}; 13415 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"}; 13416 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"}; 13417 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"}; 13418 if($RTName1 ne $RTName2) 13419 { 13420 my $ProblemType = "Symbol_Changed_Return"; 13421 if($CompleteSignature{1}{$Symbol}{"Data"}) { 13422 $ProblemType = "Global_Data_Symbol_Changed_Type"; 13423 } 13424 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=( 13425 "Target"=>$tr_name{$Symbol}, 13426 "Old_Type"=>$RTName1, 13427 "New_Type"=>$RTName2, 13428 "Old_Value"=>$Symbol, 13429 "New_Value"=>$NewSym ); 13430 } 13431 } 13432 } 13433 } 13434 if($Symbol=~/\A(_Z|\?)/) 13435 { # C++ 13436 my $Prefix = get_symbol_prefix($Symbol, 1); 13437 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}}) 13438 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)}) 13439 { # changed signature: params, "const"-qualifier 13440 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]}; 13441 if($CompleteSignature{1}{$Symbol}{"Constructor"}) 13442 { 13443 if($Symbol=~/(C[1-2][EI])/) 13444 { 13445 my $CtorType = $1; 13446 $NewSym=~s/(C[1-2][EI])/$CtorType/g; 13447 } 13448 } 13449 elsif($CompleteSignature{1}{$Symbol}{"Destructor"}) 13450 { 13451 if($Symbol=~/(D[0-2][EI])/) 13452 { 13453 my $DtorType = $1; 13454 $NewSym=~s/(D[0-2][EI])/$DtorType/g; 13455 } 13456 } 13457 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"}; 13458 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"}; 13459 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2)) 13460 { # from the same class and namespace 13461 if($CompleteSignature{1}{$Symbol}{"Const"} 13462 and not $CompleteSignature{2}{$NewSym}{"Const"}) 13463 { # "const" to non-"const" 13464 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=( 13465 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"}, 13466 "Target"=>$tr_name{$Symbol}, 13467 "New_Signature"=>get_Signature($NewSym, 2), 13468 "Old_Value"=>$Symbol, 13469 "New_Value"=>$NewSym ); 13470 } 13471 elsif(not $CompleteSignature{1}{$Symbol}{"Const"} 13472 and $CompleteSignature{2}{$NewSym}{"Const"}) 13473 { # non-"const" to "const" 13474 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=( 13475 "Target"=>$tr_name{$Symbol}, 13476 "New_Signature"=>get_Signature($NewSym, 2), 13477 "Old_Value"=>$Symbol, 13478 "New_Value"=>$NewSym ); 13479 } 13480 if($CompleteSignature{1}{$Symbol}{"Volatile"} 13481 and not $CompleteSignature{2}{$NewSym}{"Volatile"}) 13482 { # "volatile" to non-"volatile" 13483 13484 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=( 13485 "Target"=>$tr_name{$Symbol}, 13486 "New_Signature"=>get_Signature($NewSym, 2), 13487 "Old_Value"=>$Symbol, 13488 "New_Value"=>$NewSym ); 13489 } 13490 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"} 13491 and $CompleteSignature{2}{$NewSym}{"Volatile"}) 13492 { # non-"volatile" to "volatile" 13493 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=( 13494 "Target"=>$tr_name{$Symbol}, 13495 "New_Signature"=>get_Signature($NewSym, 2), 13496 "Old_Value"=>$Symbol, 13497 "New_Value"=>$NewSym ); 13498 } 13499 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0)) 13500 { # params list 13501 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=( 13502 "Target"=>$tr_name{$Symbol}, 13503 "New_Signature"=>get_Signature($NewSym, 2), 13504 "Old_Value"=>$Symbol, 13505 "New_Value"=>$NewSym ); 13506 } 13507 } 13508 } 13509 } 13510 } 13511 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 13512 { # checking symbols 13513 $CurrentSymbol = $Symbol; 13514 13515 my ($SN, $SS, $SV) = separate_symbol($Symbol); 13516 if($Level eq "Source") 13517 { # remove symbol version 13518 $Symbol=$SN; 13519 } 13520 else 13521 { # Binary 13522 if(not $SV) 13523 { # symbol without version 13524 if(my $VSym = $SymVer{1}{$Symbol}) 13525 { # the symbol is linked with versioned symbol 13526 if($CompleteSignature{2}{$VSym}{"MnglName"}) 13527 { # show report for symbol@ver only 13528 next; 13529 } 13530 elsif(not link_symbol($VSym, 2, "-Deps")) 13531 { # changed version: sym@v1 to sym@v2 13532 # do NOT show report for symbol 13533 next; 13534 } 13535 } 13536 } 13537 } 13538 my $PSymbol = $Symbol; 13539 if($Level eq "Source" 13540 and my $S = $SourceReplacement{$Symbol}) 13541 { # take a source-compatible replacement function 13542 $PSymbol = $S; 13543 } 13544 if($CompleteSignature{1}{$Symbol}{"Private"}) 13545 { # private symbols 13546 next; 13547 } 13548 if(not defined $CompleteSignature{1}{$Symbol} 13549 or not defined $CompleteSignature{2}{$PSymbol}) 13550 { # no info 13551 next; 13552 } 13553 if(not $CompleteSignature{1}{$Symbol}{"MnglName"} 13554 or not $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13555 { # no mangled name 13556 next; 13557 } 13558 if(not $CompleteSignature{1}{$Symbol}{"Header"} 13559 or not $CompleteSignature{2}{$PSymbol}{"Header"}) 13560 { # without a header 13561 next; 13562 } 13563 13564 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} 13565 and $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13566 { # became pure 13567 next; 13568 } 13569 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13570 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13571 { # became non-pure 13572 next; 13573 } 13574 13575 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)) 13576 { # exported, target, inline virtual and pure virtual 13577 next; 13578 } 13579 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level)) 13580 { # exported, target, inline virtual and pure virtual 13581 next; 13582 } 13583 13584 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 13585 { 13586 if($CompleteSignature{1}{$Symbol}{"Data"} 13587 and $CompleteSignature{2}{$PSymbol}{"Data"}) 13588 { 13589 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"}; 13590 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"}; 13591 if(defined $Value1) 13592 { 13593 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1); 13594 if(defined $Value2) 13595 { 13596 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2); 13597 if($Value1 ne $Value2) 13598 { 13599 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=( 13600 "Old_Value"=>$Value1, 13601 "New_Value"=>$Value2, 13602 "Target"=>get_Signature($Symbol, 1) ); 13603 } 13604 } 13605 } 13606 } 13607 } 13608 13609 if($CompleteSignature{2}{$PSymbol}{"Private"}) 13610 { 13611 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=( 13612 "Target"=>get_Signature_M($PSymbol, 2) ); 13613 } 13614 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"} 13615 and $CompleteSignature{2}{$PSymbol}{"Protected"}) 13616 { 13617 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=( 13618 "Target"=>get_Signature_M($PSymbol, 2) ); 13619 } 13620 elsif($CompleteSignature{1}{$Symbol}{"Protected"} 13621 and not $CompleteSignature{2}{$PSymbol}{"Protected"}) 13622 { 13623 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=( 13624 "Target"=>get_Signature_M($PSymbol, 2) ); 13625 } 13626 13627 # checking virtual table 13628 mergeVirtualTables($Symbol, $Level); 13629 13630 if($COMPILE_ERRORS) 13631 { # if some errors occurred at the compiling stage 13632 # then some false positives can be skipped here 13633 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"} 13634 and not $GlobalDataObject{2}{$Symbol}) 13635 { # missed information about parameters in newer version 13636 next; 13637 } 13638 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol} 13639 and not $CompleteSignature{2}{$PSymbol}{"Data"}) 13640 { # missed information about parameters in older version 13641 next; 13642 } 13643 } 13644 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 13645 # checking attributes 13646 if($CompleteSignature{2}{$PSymbol}{"Static"} 13647 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13648 { 13649 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=( 13650 "Target"=>get_Signature($Symbol, 1) 13651 ); 13652 } 13653 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"} 13654 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13655 { 13656 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=( 13657 "Target"=>get_Signature($Symbol, 1) 13658 ); 13659 } 13660 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"}) 13661 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"})) 13662 { # relative position of virtual and pure virtual methods 13663 if($Level eq "Binary") 13664 { 13665 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"} 13666 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"}) 13667 { # top-level virtual methods only 13668 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"}; 13669 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"}; 13670 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name} 13671 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol}) 13672 { # check the absolute position of virtual method (including added and removed methods) 13673 my %Class_Type = get_Type($Class_Id, 1); 13674 my $ProblemType = "Virtual_Method_Position"; 13675 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) { 13676 $ProblemType = "Pure_Virtual_Method_Position"; 13677 } 13678 if(isUsedClass($Class_Id, 1, $Level)) 13679 { 13680 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}})); 13681 foreach my $ASymbol (@Affected) 13682 { 13683 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 13684 next; 13685 } 13686 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=( 13687 "Type_Name"=>$Class_Type{"Name"}, 13688 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"}, 13689 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"}, 13690 "Target"=>get_Signature($Symbol, 1)); 13691 } 13692 $VTableChanged_M{$Class_Type{"Name"}} = 1; 13693 } 13694 } 13695 } 13696 } 13697 } 13698 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13699 or $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13700 { # do NOT check type changes in pure virtuals 13701 next; 13702 } 13703 $CheckedSymbols{$Level}{$Symbol} = 1; 13704 if($Symbol=~/\A(_Z|\?)/ 13705 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13706 { # C/C++: changes in parameters 13707 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13708 { # checking parameters 13709 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1); 13710 } 13711 } 13712 else 13713 { # C: added/removed parameters 13714 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13715 { # checking added parameters 13716 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13717 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"}; 13718 last if($PType2_Name eq "..."); 13719 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13720 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:""; 13721 my $ParamPos_Prev = "-1"; 13722 if($PName=~/\Ap\d+\Z/i) 13723 { # added unnamed parameter ( pN ) 13724 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1); 13725 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2); 13726 if($#Positions1==-1 or $#Positions2>$#Positions1) { 13727 $ParamPos_Prev = "lost"; 13728 } 13729 } 13730 else { 13731 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1); 13732 } 13733 if($ParamPos_Prev eq "lost") 13734 { 13735 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13736 { 13737 my $ProblemType = "Added_Parameter"; 13738 if($PName=~/\Ap\d+\Z/) { 13739 $ProblemType = "Added_Unnamed_Parameter"; 13740 } 13741 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13742 "Target"=>$PName, 13743 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13744 "Param_Type"=>$PType2_Name, 13745 "New_Signature"=>get_Signature($Symbol, 2) ); 13746 } 13747 else 13748 { 13749 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2}); 13750 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13751 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1}); 13752 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"}) 13753 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost") 13754 { 13755 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13756 { 13757 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13758 "Target"=>$PName_Old, 13759 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13760 "Param_Type"=>$PType2_Name, 13761 "Old_Value"=>$PName_Old, 13762 "New_Value"=>$PName, 13763 "New_Signature"=>get_Signature($Symbol, 2) ); 13764 } 13765 } 13766 else 13767 { 13768 my $ProblemType = "Added_Middle_Parameter"; 13769 if($PName=~/\Ap\d+\Z/) { 13770 $ProblemType = "Added_Middle_Unnamed_Parameter"; 13771 } 13772 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13773 "Target"=>$PName, 13774 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13775 "Param_Type"=>$PType2_Name, 13776 "New_Signature"=>get_Signature($Symbol, 2) ); 13777 } 13778 } 13779 } 13780 } 13781 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13782 { # check relevant parameters 13783 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13784 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13785 # FIXME: find relevant parameter by name 13786 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}) 13787 { 13788 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13789 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13790 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"} 13791 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) { 13792 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0); 13793 } 13794 } 13795 } 13796 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13797 { # checking removed parameters 13798 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13799 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"}; 13800 last if($PType1_Name eq "..."); 13801 my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13802 my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:""; 13803 my $ParamPos_New = "-1"; 13804 if($PName=~/\Ap\d+\Z/i) 13805 { # removed unnamed parameter ( pN ) 13806 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1); 13807 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2); 13808 if($#Positions2==-1 or $#Positions2<$#Positions1) { 13809 $ParamPos_New = "lost"; 13810 } 13811 } 13812 else { 13813 $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2); 13814 } 13815 if($ParamPos_New eq "lost") 13816 { 13817 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1) 13818 { 13819 my $ProblemType = "Removed_Parameter"; 13820 if($PName=~/\Ap\d+\Z/) { 13821 $ProblemType = "Removed_Unnamed_Parameter"; 13822 } 13823 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13824 "Target"=>$PName, 13825 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13826 "Param_Type"=>$PType1_Name, 13827 "New_Signature"=>get_Signature($Symbol, 2) ); 13828 } 13829 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13830 { 13831 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1}); 13832 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13833 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2}); 13834 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"}) 13835 and find_ParamPair_Pos_byName($PName_New, $Symbol, 1) eq "lost") 13836 { 13837 if($PName_New!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13838 { 13839 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13840 "Target"=>$PName, 13841 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13842 "Param_Type"=>$PType1_Name, 13843 "Old_Value"=>$PName, 13844 "New_Value"=>$PName_New, 13845 "New_Signature"=>get_Signature($Symbol, 2) ); 13846 } 13847 } 13848 else 13849 { 13850 my $ProblemType = "Removed_Middle_Parameter"; 13851 if($PName=~/\Ap\d+\Z/) { 13852 $ProblemType = "Removed_Middle_Unnamed_Parameter"; 13853 } 13854 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13855 "Target"=>$PName, 13856 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13857 "Param_Type"=>$PType1_Name, 13858 "New_Signature"=>get_Signature($Symbol, 2) ); 13859 } 13860 } 13861 } 13862 } 13863 } 13864 # checking return type 13865 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"}; 13866 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"}; 13867 my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); 13868 13869 foreach my $SubProblemType (keys(%RC_SubProblems)) 13870 { 13871 my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"}; 13872 my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"}; 13873 my %ProblemTypes = (); 13874 13875 if($CompleteSignature{1}{$Symbol}{"Data"}) 13876 { 13877 if($SubProblemType eq "Return_Type_And_Size") { 13878 $ProblemTypes{"Global_Data_Type_And_Size"} = 1; 13879 } 13880 elsif($SubProblemType eq "Return_Type_Format") { 13881 $ProblemTypes{"Global_Data_Type_Format"} = 1; 13882 } 13883 else { 13884 $ProblemTypes{"Global_Data_Type"} = 1; 13885 } 13886 13887 # quals 13888 if($SubProblemType eq "Return_Type" 13889 or $SubProblemType eq "Return_Type_And_Size" 13890 or $SubProblemType eq "Return_Type_Format") 13891 { 13892 if(my $RR = removedQual($Old_Value, $New_Value, "const")) 13893 { # const to non-const 13894 if($RR==2) { 13895 $ProblemTypes{"Global_Data_Removed_Const"} = 1; 13896 } 13897 else { 13898 $ProblemTypes{"Global_Data_Became_Non_Const"} = 1; 13899 } 13900 $ProblemTypes{"Global_Data_Type"} = 1; 13901 } 13902 elsif(my $RA = addedQual($Old_Value, $New_Value, "const")) 13903 { # non-const to const 13904 if($RA==2) { 13905 $ProblemTypes{"Global_Data_Added_Const"} = 1; 13906 } 13907 else { 13908 $ProblemTypes{"Global_Data_Became_Const"} = 1; 13909 } 13910 $ProblemTypes{"Global_Data_Type"} = 1; 13911 } 13912 } 13913 } 13914 else 13915 { 13916 # quals 13917 if($SubProblemType eq "Return_Type" 13918 or $SubProblemType eq "Return_Type_And_Size" 13919 or $SubProblemType eq "Return_Type_Format") 13920 { 13921 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 13922 { 13923 if(addedQual($Old_Value, $New_Value, "volatile")) 13924 { 13925 $ProblemTypes{"Return_Value_Became_Volatile"} = 1; 13926 if($Level ne "Source" 13927 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13928 $ProblemTypes{"Return_Type"} = 1; 13929 } 13930 } 13931 } 13932 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 13933 { 13934 if($RA==2) { 13935 $ProblemTypes{"Return_Type_Added_Const"} = 1; 13936 } 13937 else { 13938 $ProblemTypes{"Return_Type_Became_Const"} = 1; 13939 } 13940 if($Level ne "Source" 13941 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13942 $ProblemTypes{"Return_Type"} = 1; 13943 } 13944 } 13945 } 13946 } 13947 if($Level eq "Binary" 13948 and not $CompleteSignature{1}{$Symbol}{"Data"}) 13949 { 13950 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 13951 if($Arch1 eq "unknown" or $Arch2 eq "unknown") 13952 { # if one of the architectures is unknown 13953 # then set other arhitecture to unknown too 13954 ($Arch1, $Arch2) = ("unknown", "unknown"); 13955 } 13956 my (%Conv1, %Conv2) = (); 13957 if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"}) 13958 { 13959 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol}); 13960 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol}); 13961 } 13962 else 13963 { 13964 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 13965 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 13966 } 13967 13968 if($SubProblemType eq "Return_Type_Became_Void") 13969 { 13970 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13971 { # parameters stack has been affected 13972 if($Conv1{"Method"} eq "stack") { 13973 $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1; 13974 } 13975 elsif($Conv1{"Hidden"}) { 13976 $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1; 13977 } 13978 } 13979 } 13980 elsif($SubProblemType eq "Return_Type_From_Void") 13981 { 13982 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13983 { # parameters stack has been affected 13984 if($Conv2{"Method"} eq "stack") { 13985 $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1; 13986 } 13987 elsif($Conv2{"Hidden"}) { 13988 $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1; 13989 } 13990 } 13991 } 13992 elsif($SubProblemType eq "Return_Type" 13993 or $SubProblemType eq "Return_Type_And_Size" 13994 or $SubProblemType eq "Return_Type_Format") 13995 { 13996 if($Conv1{"Method"} ne $Conv2{"Method"}) 13997 { 13998 if($Conv1{"Method"} eq "stack") 13999 { # returns in a register instead of a hidden first parameter 14000 $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1; 14001 } 14002 else { 14003 $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1; 14004 } 14005 } 14006 else 14007 { 14008 if($Conv1{"Method"} eq "reg") 14009 { 14010 if($Conv1{"Registers"} ne $Conv2{"Registers"}) 14011 { 14012 if($Conv1{"Hidden"}) { 14013 $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1; 14014 } 14015 elsif($Conv2{"Hidden"}) { 14016 $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1; 14017 } 14018 else { 14019 $ProblemTypes{"Return_Type_And_Register"} = 1; 14020 } 14021 } 14022 } 14023 } 14024 } 14025 } 14026 14027 if(not keys(%ProblemTypes)) 14028 { # default 14029 $ProblemTypes{$SubProblemType} = 1; 14030 } 14031 14032 foreach my $ProblemType (keys(%ProblemTypes)) 14033 { # additional 14034 $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType}; 14035 } 14036 } 14037 if($ReturnType1_Id and $ReturnType2_Id) 14038 { 14039 @RecurTypes = (); 14040 my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); 14041 14042 my $AddProblems = {}; 14043 14044 if($CompleteSignature{1}{$Symbol}{"Data"}) 14045 { 14046 if($Level eq "Binary") 14047 { 14048 if(get_PLevel($ReturnType1_Id, 1)==0) 14049 { 14050 if(defined $Sub_SubProblems->{"DataType_Size"}) 14051 { # add "Global_Data_Size" problem 14052 14053 foreach my $Loc (keys(%{$Sub_SubProblems->{"DataType_Size"}})) 14054 { 14055 if(index($Loc,"->")==-1) 14056 { 14057 if($Loc eq $Sub_SubProblems->{"DataType_Size"}{$Loc}{"Type_Name"}) 14058 { 14059 $AddProblems->{"Global_Data_Size"}{$Loc} = $Sub_SubProblems->{"DataType_Size"}{$Loc}; # add a new problem 14060 last; 14061 } 14062 } 14063 } 14064 } 14065 } 14066 if(not defined $AddProblems->{"Global_Data_Size"}) 14067 { 14068 if(defined $GlobalDataObject{1}{$Symbol} 14069 and defined $GlobalDataObject{2}{$Symbol}) 14070 { 14071 my $Old_Size = $GlobalDataObject{1}{$Symbol}; 14072 my $New_Size = $GlobalDataObject{2}{$Symbol}; 14073 if($Old_Size!=$New_Size) 14074 { 14075 $AddProblems->{"Global_Data_Size"}{"retval"} = { 14076 "Old_Size"=>$Old_Size*$BYTE_SIZE, 14077 "New_Size"=>$New_Size*$BYTE_SIZE }; 14078 } 14079 } 14080 } 14081 } 14082 } 14083 14084 foreach my $SubProblemType (keys(%{$AddProblems})) 14085 { 14086 foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}})) 14087 { 14088 my $NewLocation = "retval"; 14089 if($SubLocation and $SubLocation ne "retval") { 14090 $NewLocation = "retval->".$SubLocation; 14091 } 14092 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation}; 14093 } 14094 } 14095 14096 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 14097 { 14098 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 14099 { 14100 my $NewLocation = "retval"; 14101 if($SubLocation and $SubLocation ne "retval") { 14102 $NewLocation = "retval->".$SubLocation; 14103 } 14104 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 14105 } 14106 } 14107 } 14108 14109 # checking object type 14110 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"}; 14111 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"}; 14112 if($ObjTId1 and $ObjTId2 14113 and not $CompleteSignature{1}{$Symbol}{"Static"}) 14114 { 14115 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1); 14116 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2); 14117 if($ThisPtr1_Id and $ThisPtr2_Id) 14118 { 14119 @RecurTypes = (); 14120 my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); 14121 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 14122 { 14123 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 14124 { 14125 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this"; 14126 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 14127 } 14128 } 14129 } 14130 } 14131 } 14132 if($Level eq "Binary") { 14133 mergeVTables($Level); 14134 } 14135 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) { 14136 $CheckedSymbols{$Level}{$Symbol} = 1; 14137 } 14138} 14139 14140sub rmQuals($$) 14141{ 14142 my ($Value, $Qual) = @_; 14143 if(not $Qual) { 14144 return $Value; 14145 } 14146 if($Qual eq "all") 14147 { # all quals 14148 $Qual = "const|volatile|restrict"; 14149 } 14150 while($Value=~s/\b$Qual\b//) { 14151 $Value = formatName($Value, "T"); 14152 } 14153 return $Value; 14154} 14155 14156sub cmpBTypes($$$$) 14157{ 14158 my ($T1, $T2, $V1, $V2) = @_; 14159 $T1 = uncover_typedefs($T1, $V1); 14160 $T2 = uncover_typedefs($T2, $V2); 14161 return (rmQuals($T1, "all") eq rmQuals($T2, "all")); 14162} 14163 14164sub addedQual($$$) 14165{ 14166 my ($Old_Value, $New_Value, $Qual) = @_; 14167 return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual); 14168} 14169 14170sub removedQual($$$) 14171{ 14172 my ($Old_Value, $New_Value, $Qual) = @_; 14173 return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual); 14174} 14175 14176sub removedQual_I($$$$$) 14177{ 14178 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_; 14179 $Old_Value = uncover_typedefs($Old_Value, $V1); 14180 $New_Value = uncover_typedefs($New_Value, $V2); 14181 14182 if($Old_Value eq $New_Value) 14183 { # equal types 14184 return 0; 14185 } 14186 if($Old_Value!~/\b$Qual\b/) 14187 { # without a qual 14188 return 0; 14189 } 14190 elsif($New_Value!~/\b$Qual\b/) 14191 { # became non-qual 14192 return 1; 14193 } 14194 else 14195 { 14196 my @BQ1 = getQualModel($Old_Value, $Qual); 14197 my @BQ2 = getQualModel($New_Value, $Qual); 14198 foreach (0 .. $#BQ1) 14199 { # removed qual 14200 if($BQ1[$_]==1 14201 and $BQ2[$_]!=1) 14202 { 14203 return 2; 14204 } 14205 } 14206 } 14207 return 0; 14208} 14209 14210sub getQualModel($$) 14211{ 14212 my ($Value, $Qual) = @_; 14213 if(not $Qual) { 14214 return $Value; 14215 } 14216 14217 # cleaning 14218 while($Value=~/(\w+)/) 14219 { 14220 my $W = $1; 14221 14222 if($W eq $Qual) { 14223 $Value=~s/\b$W\b/\@/g; 14224 } 14225 else { 14226 $Value=~s/\b$W\b//g; 14227 } 14228 } 14229 14230 $Value=~s/\@/$Qual/g; 14231 $Value=~s/[^\*\&\w]+//g; 14232 14233 # modeling 14234 # int*const*const == 011 14235 # int**const == 001 14236 my @Model = (); 14237 my @Elems = split(/[\*\&]/, $Value); 14238 if(not @Elems) { 14239 return (0); 14240 } 14241 foreach (@Elems) 14242 { 14243 if($_ eq $Qual) { 14244 push(@Model, 1); 14245 } 14246 else { 14247 push(@Model, 0); 14248 } 14249 } 14250 14251 return @Model; 14252} 14253 14254my %StringTypes = map {$_=>1} ( 14255 "char*", 14256 "char const*" 14257); 14258 14259my %CharTypes = map {$_=>1} ( 14260 "char", 14261 "char const" 14262); 14263 14264sub showVal($$$) 14265{ 14266 my ($Value, $TypeId, $LibVersion) = @_; 14267 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 14268 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion); 14269 if(substr($Value, 0, 2) eq "_Z") 14270 { 14271 if(my $Unmangled = $tr_name{$Value}) { 14272 return $Unmangled; 14273 } 14274 } 14275 elsif(defined $StringTypes{$TName} or $TName=~/string/i) 14276 { # strings 14277 return "\"$Value\""; 14278 } 14279 elsif(defined $CharTypes{$TName}) 14280 { # characters 14281 return "\'$Value\'"; 14282 } 14283 if($Value eq "") 14284 { # other 14285 return "\'\'"; 14286 } 14287 return $Value; 14288} 14289 14290sub getRegs($$$) 14291{ 14292 my ($LibVersion, $Symbol, $Pos) = @_; 14293 14294 if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"}) 14295 { 14296 my %Regs = (); 14297 foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}})) 14298 { 14299 if($Elem=~/\A$Pos([\.\+]|\Z)/) { 14300 $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1; 14301 } 14302 } 14303 14304 return join(", ", sort keys(%Regs)); 14305 } 14306 elsif(defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"} 14307 and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{0} 14308 and not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{0}{"offset"}) 14309 { 14310 return "unknown"; 14311 } 14312 14313 return undef; 14314} 14315 14316sub mergeParameters($$$$$$) 14317{ 14318 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_; 14319 if(not $Symbol) { 14320 return; 14321 } 14322 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"}; 14323 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"}; 14324 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"}; 14325 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"}; 14326 if(not $PType1_Id 14327 or not $PType2_Id) { 14328 return; 14329 } 14330 14331 if($Symbol=~/\A(_Z|\?)/) 14332 { # do not merge "this" 14333 if($PName1 eq "this" or $PName2 eq "this") { 14334 return; 14335 } 14336 } 14337 14338 my %Type1 = get_Type($PType1_Id, 1); 14339 my %Type2 = get_Type($PType2_Id, 2); 14340 14341 my %PureType1 = get_PureType($PType1_Id, $TypeInfo{1}); 14342 14343 my %BaseType1 = get_BaseType($PType1_Id, 1); 14344 my %BaseType2 = get_BaseType($PType2_Id, 2); 14345 14346 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter"; 14347 14348 if($Level eq "Binary") 14349 { 14350 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1")) 14351 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format) 14352 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14353 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14354 { 14355 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=( 14356 "Target"=>$PName1, 14357 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14358 } 14359 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14360 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14361 { 14362 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=( 14363 "Target"=>$PName1, 14364 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14365 } 14366 } 14367 14368 if(defined $UsedDump{1}{"DWARF"} 14369 and defined $UsedDump{2}{"DWARF"}) 14370 { 14371 if(checkDump(1, "3.0") and checkDump(2, "3.0")) 14372 { 14373 my $Old_Regs = getRegs(1, $Symbol, $ParamPos1); 14374 my $New_Regs = getRegs(2, $PSymbol, $ParamPos2); 14375 14376 if($Old_Regs ne "unknown" 14377 and $New_Regs ne "unknown") 14378 { 14379 if($Old_Regs and $New_Regs) 14380 { 14381 if($Old_Regs ne $New_Regs) 14382 { 14383 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=( 14384 "Target"=>$PName1, 14385 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14386 "Old_Value"=>$Old_Regs, 14387 "New_Value"=>$New_Regs ); 14388 } 14389 } 14390 elsif($Old_Regs and not $New_Regs) 14391 { 14392 %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=( 14393 "Target"=>$PName1, 14394 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14395 "Old_Value"=>$Old_Regs ); 14396 } 14397 elsif(not $Old_Regs and $New_Regs) 14398 { 14399 %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=( 14400 "Target"=>$PName1, 14401 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14402 "New_Value"=>$New_Regs ); 14403 } 14404 } 14405 14406 if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne "" 14407 and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "") 14408 { 14409 if($Old_Offset ne $New_Offset) 14410 { 14411 my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"}; 14412 my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"}; 14413 14414 $Old_Offset = $Old_Offset - $Start1; 14415 $New_Offset = $New_Offset - $Start2; 14416 14417 if($Old_Offset ne $New_Offset) 14418 { 14419 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( 14420 "Target"=>$PName1, 14421 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14422 "Old_Value"=>$Old_Offset, 14423 "New_Value"=>$New_Offset ); 14424 } 14425 } 14426 } 14427 } 14428 } 14429 } 14430 if(checkDump(1, "2.0") and checkDump(2, "2.0") 14431 and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1") 14432 { # "default" attribute added in ACC 1.22 (dump 2.0 format) 14433 # broken in 3.1, fixed in 3.2 14434 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"}; 14435 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"}; 14436 if(not checkDump(1, "2.13") 14437 and checkDump(2, "2.13")) 14438 { # support for old ABI dumps 14439 if(defined $Value_Old and defined $Value_New) 14440 { 14441 if($PureType1{"Name"} eq "bool" 14442 and $Value_Old eq "false" and $Value_New eq "0") 14443 { # int class::method ( bool p = 0 ); 14444 # old ABI dumps: "false" 14445 # new ABI dumps: "0" 14446 $Value_Old = "0"; 14447 } 14448 } 14449 } 14450 if(not checkDump(1, "2.18") 14451 and checkDump(2, "2.18")) 14452 { # support for old ABI dumps 14453 if(not defined $Value_Old 14454 and substr($Value_New, 0, 2) eq "_Z") { 14455 $Value_Old = $Value_New; 14456 } 14457 } 14458 if(defined $Value_Old) 14459 { 14460 $Value_Old = showVal($Value_Old, $PType1_Id, 1); 14461 if(defined $Value_New) 14462 { 14463 $Value_New = showVal($Value_New, $PType2_Id, 2); 14464 if($Value_Old ne $Value_New) 14465 { # FIXME: how to distinguish "0" and 0 (NULL) 14466 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=( 14467 "Target"=>$PName1, 14468 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14469 "Old_Value"=>$Value_Old, 14470 "New_Value"=>$Value_New ); 14471 } 14472 } 14473 else 14474 { 14475 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=( 14476 "Target"=>$PName1, 14477 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14478 "Old_Value"=>$Value_Old ); 14479 } 14480 } 14481 elsif(defined $Value_New) 14482 { 14483 $Value_New = showVal($Value_New, $PType2_Id, 2); 14484 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=( 14485 "Target"=>$PName1, 14486 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14487 "New_Value"=>$Value_New ); 14488 } 14489 } 14490 14491 if($ChkRnmd) 14492 { 14493 if($PName1 and $PName2 and $PName1 ne $PName2 14494 and $PType1_Id!=-1 and $PType2_Id!=-1 14495 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/) 14496 { # except unnamed "..." value list (Id=-1) 14497 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=( 14498 "Target"=>$PName1, 14499 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14500 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, 14501 "Old_Value"=>$PName1, 14502 "New_Value"=>$PName2, 14503 "New_Signature"=>get_Signature($Symbol, 2) ); 14504 } 14505 } 14506 14507 # checking type change (replace) 14508 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level); 14509 14510 foreach my $SubProblemType (keys(%SubProblems)) 14511 { # add new problems, remove false alarms 14512 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14513 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14514 14515 # quals 14516 if($SubProblemType eq "Parameter_Type" 14517 or $SubProblemType eq "Parameter_Type_And_Size" 14518 or $SubProblemType eq "Parameter_Type_Format") 14519 { 14520 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14521 { 14522 if(addedQual($Old_Value, $New_Value, "restrict")) { 14523 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14524 } 14525 elsif(removedQual($Old_Value, $New_Value, "restrict")) { 14526 %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14527 } 14528 } 14529 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14530 { 14531 if(removedQual($Old_Value, $New_Value, "volatile")) { 14532 %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}}; 14533 } 14534 } 14535 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"} 14536 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14537 { # int to "int const" 14538 delete($SubProblems{$SubProblemType}); 14539 } 14540 elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"} 14541 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14542 { # "int const" to int 14543 delete($SubProblems{$SubProblemType}); 14544 } 14545 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 14546 { # "const" to non-"const" 14547 if($RR==2) { 14548 %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}}; 14549 } 14550 else { 14551 %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}}; 14552 } 14553 } 14554 } 14555 } 14556 14557 if($Level eq "Source") 14558 { 14559 foreach my $SubProblemType (keys(%SubProblems)) 14560 { 14561 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14562 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14563 14564 if($SubProblemType eq "Parameter_Type") 14565 { 14566 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 14567 delete($SubProblems{$SubProblemType}); 14568 } 14569 } 14570 } 14571 } 14572 14573 foreach my $SubProblemType (keys(%SubProblems)) 14574 { # modify/register problems 14575 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14576 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14577 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"}; 14578 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"}; 14579 14580 my $NewProblemType = $SubProblemType; 14581 if($Old_Value eq "..." and $New_Value ne "...") 14582 { # change from "..." to "int" 14583 if($ParamPos1==0) 14584 { # ISO C requires a named argument before "..." 14585 next; 14586 } 14587 $NewProblemType = "Parameter_Became_Non_VaList"; 14588 } 14589 elsif($New_Value eq "..." and $Old_Value ne "...") 14590 { # change from "int" to "..." 14591 if($ParamPos2==0) 14592 { # ISO C requires a named argument before "..." 14593 next; 14594 } 14595 $NewProblemType = "Parameter_Became_VaList"; 14596 } 14597 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size" 14598 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format")) 14599 { 14600 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 14601 if($Arch1 eq "unknown" 14602 or $Arch2 eq "unknown") 14603 { # if one of the architectures is unknown 14604 # then set other arhitecture to unknown too 14605 ($Arch1, $Arch2) = ("unknown", "unknown"); 14606 } 14607 my (%Conv1, %Conv2) = (); 14608 if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"}) 14609 { # real 14610 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1); 14611 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2); 14612 } 14613 else 14614 { # model 14615 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 14616 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 14617 } 14618 if($Conv1{"Method"} eq $Conv2{"Method"}) 14619 { 14620 if($Conv1{"Method"} eq "stack") 14621 { 14622 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset 14623 $NewProblemType = "Parameter_Type_And_Stack"; 14624 } 14625 } 14626 elsif($Conv1{"Method"} eq "reg") 14627 { 14628 if($Conv1{"Registers"} ne $Conv2{"Registers"}) { 14629 $NewProblemType = "Parameter_Type_And_Register"; 14630 } 14631 } 14632 } 14633 elsif($Conv1{"Method"} ne "unknown" 14634 and $Conv2{"Method"} ne "unknown") 14635 { 14636 if($Conv1{"Method"} eq "stack") { 14637 $NewProblemType = "Parameter_Type_From_Stack_To_Register"; 14638 } 14639 elsif($Conv1{"Method"} eq "register") { 14640 $NewProblemType = "Parameter_Type_From_Register_To_Stack"; 14641 } 14642 } 14643 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"}; 14644 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"}; 14645 } 14646 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=( 14647 "Target"=>$PName1, 14648 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14649 "New_Signature"=>get_Signature($Symbol, 2) ); 14650 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; 14651 } 14652 14653 @RecurTypes = (); 14654 14655 # checking type definition changes 14656 my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level); 14657 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 14658 { 14659 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 14660 { 14661 my $NewProblemType = $SubProblemType; 14662 if($SubProblemType eq "DataType_Size") 14663 { 14664 if($PureType1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) 14665 { # stack has been affected 14666 $NewProblemType = "DataType_Size_And_Stack"; 14667 } 14668 } 14669 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location; 14670 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 14671 } 14672 } 14673} 14674 14675sub find_ParamPair_Pos_byName($$$) 14676{ 14677 my ($Name, $Symbol, $LibVersion) = @_; 14678 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14679 { 14680 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14681 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name) 14682 { 14683 return $ParamPos; 14684 } 14685 } 14686 return "lost"; 14687} 14688 14689sub find_ParamPair_Pos_byTypeAndPos($$$$$) 14690{ 14691 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_; 14692 my @Positions = (); 14693 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14694 { 14695 next if($Order eq "backward" and $ParamPos>$MediumPos); 14696 next if($Order eq "forward" and $ParamPos<$MediumPos); 14697 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14698 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"}; 14699 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) { 14700 push(@Positions, $ParamPos); 14701 } 14702 } 14703 return @Positions; 14704} 14705 14706sub getTypeIdByName($$) 14707{ 14708 my ($TypeName, $LibVersion) = @_; 14709 return $TName_Tid{$LibVersion}{formatName($TypeName, "T")}; 14710} 14711 14712sub diffTypes($$$) 14713{ 14714 if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) { 14715 return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}; 14716 } 14717 if(isRecurType($_[0], $_[1], \@RecurTypes_Diff)) 14718 { # skip recursive declarations 14719 return 0; 14720 } 14721 14722 pushType($_[0], $_[1], \@RecurTypes_Diff); 14723 my $Diff = diffTypes_I(@_); 14724 pop(@RecurTypes_Diff); 14725 14726 return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff); 14727} 14728 14729sub diffTypes_I($$$) 14730{ 14731 my ($Type1_Id, $Type2_Id, $Level) = @_; 14732 14733 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14734 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14735 14736 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 14737 { # equal types 14738 return 0; 14739 } 14740 if($Type1_Pure{"Name"} eq "void") 14741 { # from void* to something 14742 return 0; 14743 } 14744 if($Type2_Pure{"Name"} eq "void") 14745 { # from something to void* 14746 return 0; 14747 } 14748 if($Type1_Pure{"Name"}=~/\*/ 14749 or $Type2_Pure{"Name"}=~/\*/) 14750 { # compared in detectTypeChange() 14751 return 0; 14752 } 14753 14754 my %FloatType = map {$_=>1} ( 14755 "float", 14756 "double", 14757 "long double" 14758 ); 14759 14760 my $T1 = $Type1_Pure{"Type"}; 14761 my $T2 = $Type2_Pure{"Type"}; 14762 14763 if($T1 eq "Struct" 14764 and $T2 eq "Class") 14765 { # compare as data structures 14766 $T2 = "Struct"; 14767 } 14768 14769 if($T1 eq "Class" 14770 and $T2 eq "Struct") 14771 { # compare as data structures 14772 $T1 = "Struct"; 14773 } 14774 14775 if($T1 ne $T2) 14776 { # different types 14777 if($T1 eq "Intrinsic" 14778 and $T2 eq "Enum") 14779 { # "int" to "enum" 14780 return 0; 14781 } 14782 elsif($T2 eq "Intrinsic" 14783 and $T1 eq "Enum") 14784 { # "enum" to "int" 14785 return 0; 14786 } 14787 else 14788 { # union to struct 14789 # ... 14790 return 1; 14791 } 14792 } 14793 else 14794 { 14795 if($T1 eq "Intrinsic") 14796 { 14797 if($FloatType{$Type1_Pure{"Name"}} 14798 or $FloatType{$Type2_Pure{"Name"}}) 14799 { # "float" to "double" 14800 # "float" to "int" 14801 if($Level eq "Source") 14802 { # Safe 14803 return 0; 14804 } 14805 else { 14806 return 1; 14807 } 14808 } 14809 } 14810 elsif($T1=~/Class|Struct|Union|Enum/) 14811 { 14812 my @Membs1 = keys(%{$Type1_Pure{"Memb"}}); 14813 my @Membs2 = keys(%{$Type2_Pure{"Memb"}}); 14814 if(not @Membs1 14815 or not @Membs2) 14816 { # private 14817 return 0; 14818 } 14819 if($#Membs1!=$#Membs2) 14820 { # different number of elements 14821 return 1; 14822 } 14823 if($T1 eq "Enum") 14824 { 14825 foreach my $Pos (@Membs1) 14826 { # compare elements by name and value 14827 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"} 14828 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"}) 14829 { # different names 14830 return 1; 14831 } 14832 } 14833 } 14834 else 14835 { 14836 foreach my $Pos (@Membs1) 14837 { 14838 if($Level eq "Source") 14839 { 14840 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}) 14841 { # different names 14842 return 1; 14843 } 14844 } 14845 14846 my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}}; 14847 my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}}; 14848 14849 if($MT1{"Name"} ne $MT2{"Name"} 14850 or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"})) 14851 { 14852 my $PL1 = get_PLevel($MT1{"Tid"}, 1); 14853 my $PL2 = get_PLevel($MT2{"Tid"}, 2); 14854 14855 if($PL1 ne $PL2) 14856 { # different pointer level 14857 return 1; 14858 } 14859 14860 # compare base types 14861 my %BT1 = get_BaseType($MT1{"Tid"}, 1); 14862 my %BT2 = get_BaseType($MT2{"Tid"}, 2); 14863 14864 if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level)) 14865 { # different types 14866 return 1; 14867 } 14868 } 14869 } 14870 } 14871 } 14872 else 14873 { 14874 # TODO: arrays, etc. 14875 } 14876 } 14877 return 0; 14878} 14879 14880sub detectTypeChange($$$$) 14881{ 14882 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_; 14883 if(not $Type1_Id or not $Type2_Id) { 14884 return (); 14885 } 14886 my %LocalProblems = (); 14887 my %Type1 = get_Type($Type1_Id, 1); 14888 my %Type2 = get_Type($Type2_Id, 2); 14889 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14890 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14891 14892 if(defined $SkipTypedefUncover) 14893 { 14894 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) { 14895 return (); 14896 } 14897 14898 if(cmpBTypes($Type1_Pure{"Name"}, $Type2_Pure{"Name"}, 1, 2)) { 14899 return (); 14900 } 14901 } 14902 14903 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1); 14904 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2); 14905 14906 if(defined $UsedDump{1}{"DWARF"}) 14907 { 14908 if($Type1_Pure{"Name"} eq "__unknown__" 14909 or $Type2_Pure{"Name"} eq "__unknown__" 14910 or $Type1_Base{"Name"} eq "__unknown__" 14911 or $Type2_Base{"Name"} eq "__unknown__") 14912 { # Error ABI dump 14913 return (); 14914 } 14915 } 14916 14917 my $Type1_PLevel = get_PLevel($Type1_Id, 1); 14918 my $Type2_PLevel = get_PLevel($Type2_Id, 2); 14919 return () if(not $Type1{"Name"} or not $Type2{"Name"}); 14920 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"}); 14921 return () if($Type1_PLevel eq "" or $Type2_PLevel eq ""); 14922 if($Type1_Base{"Name"} ne $Type2_Base{"Name"} 14923 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel 14924 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void"))) 14925 { # base type change 14926 if($Type1{"Name"} eq $Type2{"Name"}) 14927 { 14928 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef") 14929 { # will be reported in mergeTypes() as typedef problem 14930 return (); 14931 } 14932 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 14933 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 14934 if(%Typedef_1 and %Typedef_2) 14935 { 14936 if($Typedef_1{"Name"} eq $Typedef_2{"Name"} 14937 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef") 14938 { # const Typedef 14939 return (); 14940 } 14941 } 14942 } 14943 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/) 14944 { 14945 if($Level eq "Binary" 14946 and $Type1_Base{"Size"} and $Type2_Base{"Size"} 14947 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}) 14948 { 14949 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=( 14950 "Old_Value"=>$Type1_Base{"Name"}, 14951 "New_Value"=>$Type2_Base{"Name"}, 14952 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14953 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14954 } 14955 else 14956 { 14957 if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level)) 14958 { # format change 14959 %{$LocalProblems{$Prefix."_BaseType_Format"}}=( 14960 "Old_Value"=>$Type1_Base{"Name"}, 14961 "New_Value"=>$Type2_Base{"Name"}, 14962 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14963 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14964 } 14965 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"})) 14966 { 14967 %{$LocalProblems{$Prefix."_BaseType"}}=( 14968 "Old_Value"=>$Type1_Base{"Name"}, 14969 "New_Value"=>$Type2_Base{"Name"}, 14970 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14971 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14972 } 14973 } 14974 } 14975 } 14976 elsif($Type1{"Name"} ne $Type2{"Name"}) 14977 { # type change 14978 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/) 14979 { 14980 if($Prefix eq "Return" 14981 and $Type1_Pure{"Name"} eq "void") 14982 { 14983 %{$LocalProblems{"Return_Type_From_Void"}}=( 14984 "New_Value"=>$Type2{"Name"}, 14985 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14986 } 14987 elsif($Prefix eq "Return" 14988 and $Type2_Pure{"Name"} eq "void") 14989 { 14990 %{$LocalProblems{"Return_Type_Became_Void"}}=( 14991 "Old_Value"=>$Type1{"Name"}, 14992 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE); 14993 } 14994 else 14995 { 14996 if($Level eq "Binary" 14997 and $Type1{"Size"} and $Type2{"Size"} 14998 and $Type1{"Size"} ne $Type2{"Size"}) 14999 { 15000 %{$LocalProblems{$Prefix."_Type_And_Size"}}=( 15001 "Old_Value"=>$Type1{"Name"}, 15002 "New_Value"=>$Type2{"Name"}, 15003 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 15004 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 15005 } 15006 else 15007 { 15008 if(diffTypes($Type1_Id, $Type2_Id, $Level)) 15009 { # format change 15010 %{$LocalProblems{$Prefix."_Type_Format"}}=( 15011 "Old_Value"=>$Type1{"Name"}, 15012 "New_Value"=>$Type2{"Name"}, 15013 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 15014 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 15015 } 15016 elsif(tNameLock($Type1_Id, $Type2_Id)) 15017 { # FIXME: correct this condition 15018 %{$LocalProblems{$Prefix."_Type"}}=( 15019 "Old_Value"=>$Type1{"Name"}, 15020 "New_Value"=>$Type2{"Name"}, 15021 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 15022 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 15023 } 15024 } 15025 } 15026 } 15027 } 15028 if($Type1_PLevel!=$Type2_PLevel) 15029 { 15030 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..." 15031 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...") 15032 { 15033 if($Level eq "Source") 15034 { 15035 %{$LocalProblems{$Prefix."_PointerLevel"}}=( 15036 "Old_Value"=>$Type1_PLevel, 15037 "New_Value"=>$Type2_PLevel); 15038 } 15039 else 15040 { 15041 if($Type2_PLevel>$Type1_PLevel) 15042 { 15043 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=( 15044 "Old_Value"=>$Type1_PLevel, 15045 "New_Value"=>$Type2_PLevel); 15046 } 15047 else 15048 { 15049 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=( 15050 "Old_Value"=>$Type1_PLevel, 15051 "New_Value"=>$Type2_PLevel); 15052 } 15053 } 15054 } 15055 } 15056 if($Type1_Pure{"Type"} eq "Array" 15057 and $Type1_Pure{"BaseType"}) 15058 { # base_type[N] -> base_type[N] 15059 # base_type: older_structure -> typedef to newer_structure 15060 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level); 15061 foreach my $SubProblemType (keys(%SubProblems)) 15062 { 15063 $SubProblemType=~s/_Type/_BaseType/g; 15064 next if(defined $LocalProblems{$SubProblemType}); 15065 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) { 15066 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr}; 15067 } 15068 } 15069 } 15070 return %LocalProblems; 15071} 15072 15073sub tNameLock($$) 15074{ 15075 my ($Tid1, $Tid2) = @_; 15076 my $Changed = 0; 15077 if(differentDumps("G")) 15078 { # different GCC versions 15079 $Changed = 1; 15080 } 15081 elsif(differentDumps("V")) 15082 { # different versions of ABI dumps 15083 if(not checkDump(1, "2.20") 15084 or not checkDump(2, "2.20")) 15085 { # latest names update 15086 # 2.6: added restrict qualifier 15087 # 2.13: added missed typedefs to qualified types 15088 # 2.20: prefix for struct, union and enum types 15089 $Changed = 1; 15090 } 15091 } 15092 15093 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"}; 15094 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"}; 15095 15096 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"}; 15097 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"}; 15098 15099 if($Changed) 15100 { # different formats 15101 my %Base1 = get_Type($Tid1, 1); 15102 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") { 15103 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1}); 15104 } 15105 my %Base2 = get_Type($Tid2, 2); 15106 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") { 15107 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2}); 15108 } 15109 my $BName1 = uncover_typedefs($Base1{"Name"}, 1); 15110 my $BName2 = uncover_typedefs($Base2{"Name"}, 2); 15111 if($BName1 eq $BName2) 15112 { # equal base types 15113 return 0; 15114 } 15115 15116 if(not checkDump(1, "2.13") 15117 or not checkDump(2, "2.13")) 15118 { # broken array names in ABI dumps < 2.13 15119 if($TT1 eq "Array" 15120 and $TT2 eq "Array") { 15121 return 0; 15122 } 15123 } 15124 15125 if(not checkDump(1, "2.6") 15126 or not checkDump(2, "2.6")) 15127 { # added restrict attribute in 2.6 15128 if($TN1!~/\brestrict\b/ 15129 and $TN2=~/\brestrict\b/) { 15130 return 0; 15131 } 15132 } 15133 15134 if(not checkDump(1, "2.20") 15135 or not checkDump(2, "2.20")) 15136 { # added type prefix in 2.20 15137 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/ 15138 or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 15139 return 0; 15140 } 15141 } 15142 } 15143 else 15144 { 15145 # typedef struct {...} type_t 15146 # typedef struct type_t {...} type_t 15147 if(index($TN1, " ".$TN2)!=-1) 15148 { 15149 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) { 15150 return 0; 15151 } 15152 } 15153 if(index($TN2, " ".$TN1)!=-1) 15154 { 15155 if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 15156 return 0; 15157 } 15158 } 15159 15160 if($TT1 eq "FuncPtr" 15161 and $TT2 eq "FuncPtr") 15162 { 15163 my $TN1_C = $TN1; 15164 my $TN2_C = $TN2; 15165 15166 $TN1_C=~s/\b(struct|union) //g; 15167 $TN2_C=~s/\b(struct|union) //g; 15168 15169 if($TN1_C eq $TN2_C) { 15170 return 0; 15171 } 15172 } 15173 } 15174 15175 my ($N1, $N2) = ($TN1, $TN2); 15176 $N1=~s/\b(struct|union) //g; 15177 $N2=~s/\b(struct|union) //g; 15178 15179 if($N1 eq $N2) 15180 { # QList<struct QUrl> and QList<QUrl> 15181 return 0; 15182 } 15183 15184 return 1; 15185} 15186 15187sub differentDumps($) 15188{ 15189 my $Check = $_[0]; 15190 if(defined $Cache{"differentDumps"}{$Check}) { 15191 return $Cache{"differentDumps"}{$Check}; 15192 } 15193 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"}) 15194 { 15195 if($Check eq "G") 15196 { 15197 if(getGccVersion(1) ne getGccVersion(2)) 15198 { # different GCC versions 15199 return ($Cache{"differentDumps"}{$Check}=1); 15200 } 15201 } 15202 if($Check eq "V") 15203 { 15204 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2), 15205 formatVersion($UsedDump{2}{"V"}, 2))!=0) 15206 { # different dump versions (skip micro version) 15207 return ($Cache{"differentDumps"}{$Check}=1); 15208 } 15209 } 15210 } 15211 return ($Cache{"differentDumps"}{$Check}=0); 15212} 15213 15214sub formatVersion($$) 15215{ # cut off version digits 15216 my ($V, $Digits) = @_; 15217 my @Elems = split(/\./, $V); 15218 return join(".", splice(@Elems, 0, $Digits)); 15219} 15220 15221sub htmlSpecChars($) 15222{ 15223 my $Str = $_[0]; 15224 if(not $Str) { 15225 return $Str; 15226 } 15227 $Str=~s/\&([^#]|\Z)/&$1/g; 15228 $Str=~s/</</g; 15229 $Str=~s/\-\>/->/g; # − 15230 $Str=~s/>/>/g; 15231 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 15232 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 15233 $Str=~s/ / /g; # 15234 $Str=~s/\@SP\@/ /g; 15235 $Str=~s/\n/<br\/>/g; 15236 $Str=~s/\"/"/g; 15237 $Str=~s/\'/'/g; 15238 return $Str; 15239} 15240 15241sub xmlSpecChars($) 15242{ 15243 my $Str = $_[0]; 15244 if(not $Str) { 15245 return $Str; 15246 } 15247 15248 $Str=~s/\&([^#]|\Z)/&$1/g; 15249 $Str=~s/</</g; 15250 $Str=~s/>/>/g; 15251 15252 $Str=~s/\"/"/g; 15253 $Str=~s/\'/'/g; 15254 15255 return $Str; 15256} 15257 15258sub xmlSpecChars_R($) 15259{ 15260 my $Str = $_[0]; 15261 if(not $Str) { 15262 return $Str; 15263 } 15264 15265 $Str=~s/&/&/g; 15266 $Str=~s/</</g; 15267 $Str=~s/>/>/g; 15268 15269 $Str=~s/"/"/g; 15270 $Str=~s/'/'/g; 15271 15272 return $Str; 15273} 15274 15275sub black_name($) 15276{ 15277 my $Name = $_[0]; 15278 return "<span class='iname_b'>".highLight_Signature($Name)."</span>"; 15279} 15280 15281sub highLight_Signature($) 15282{ 15283 my $Signature = $_[0]; 15284 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0); 15285} 15286 15287sub highLight_Signature_Italic_Color($) 15288{ 15289 my $Signature = $_[0]; 15290 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1); 15291} 15292 15293sub separate_symbol($) 15294{ 15295 my $Symbol = $_[0]; 15296 my ($Name, $Spec, $Ver) = ($Symbol, "", ""); 15297 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) { 15298 ($Name, $Spec, $Ver) = ($1, $2, $3); 15299 } 15300 return ($Name, $Spec, $Ver); 15301} 15302 15303sub cut_f_attrs($) 15304{ 15305 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) { 15306 return $2; 15307 } 15308 return ""; 15309} 15310 15311sub highLight_Signature_PPos_Italic($$$$$) 15312{ 15313 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_; 15314 $Param_Pos = "" if(not defined $Param_Pos); 15315 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature); 15316 my $Return = ""; 15317 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) { 15318 $Return = $2; 15319 } 15320 my $SCenter = find_center($Signature, "("); 15321 if(not $SCenter) 15322 { # global data 15323 $Signature = htmlSpecChars($Signature); 15324 $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g; 15325 $Signature .= (($SymbolVersion)?"<span class='sym_ver'> $VersionSpec $SymbolVersion</span>":""); 15326 if($Return and $ShowReturn) { 15327 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15328 } 15329 return $Signature; 15330 } 15331 my ($Begin, $End) = (substr($Signature, 0, $SCenter), ""); 15332 $Begin.=" " if($Begin!~/ \Z/); 15333 $End = cut_f_attrs($Signature); 15334 my @Parts = (); 15335 my ($Short, $Params) = split_Signature($Signature); 15336 my @SParts = separate_Params($Params, 1, 1); 15337 foreach my $Pos (0 .. $#SParts) 15338 { 15339 my $Part = $SParts[$Pos]; 15340 $Part=~s/\A\s+|\s+\Z//g; 15341 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), ""); 15342 if($Part=~/\([\*]+(\w+)\)/i) { 15343 $ParamName = $1;#func-ptr 15344 } 15345 elsif($Part=~/(\w+)[\,\)]*\Z/i) { 15346 $ParamName = $1; 15347 } 15348 if(not $ParamName) 15349 { 15350 push(@Parts, $Part_Styled); 15351 next; 15352 } 15353 if($ItalicParams and not $TName_Tid{1}{$Part} 15354 and not $TName_Tid{2}{$Part}) 15355 { 15356 my $Style = "<i>$ParamName</i>"; 15357 15358 if($Param_Pos ne "" 15359 and $Pos==$Param_Pos) { 15360 $Style = "<span class=\'fp\'>$ParamName</span>"; 15361 } 15362 elsif($ColorParams) { 15363 $Style = "<span class=\'color_p\'>$ParamName</span>"; 15364 } 15365 15366 $Part_Styled=~s!(\W)$ParamName([\,\)]|\Z)!$1$Style$2!ig; 15367 } 15368 $Part_Styled=~s/,(\w)/, $1/g; 15369 push(@Parts, $Part_Styled); 15370 } 15371 if(@Parts) 15372 { 15373 foreach my $Num (0 .. $#Parts) 15374 { 15375 if($Num==$#Parts) 15376 { # add ")" to the last parameter 15377 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>"; 15378 } 15379 elsif(length($Parts[$Num])<=45) { 15380 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>"; 15381 } 15382 } 15383 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( ".join(" ", @Parts)."</span>".$End; 15384 } 15385 else { 15386 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( )</span>".$End; 15387 } 15388 if($Return and $ShowReturn) { 15389 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15390 } 15391 $Signature=~s!\[\]![ ]!g; 15392 $Signature=~s!operator=!operator =!g; 15393 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g; 15394 if($SymbolVersion) { 15395 $Signature .= "<span class='sym_ver'> $VersionSpec $SymbolVersion</span>"; 15396 } 15397 return $Signature; 15398} 15399 15400sub split_Signature($) 15401{ 15402 my $Signature = $_[0]; 15403 if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) 15404 { 15405 $Signature=~s/\A\Q$ShortName\E\(//g; 15406 cut_f_attrs($Signature); 15407 $Signature=~s/\)\Z//; 15408 return ($ShortName, $Signature); 15409 } 15410 15411 # error 15412 return ($Signature, ""); 15413} 15414 15415sub separate_Params($$$) 15416{ 15417 my ($Params, $Comma, $Sp) = @_; 15418 my @Parts = (); 15419 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15420 my $Part = 0; 15421 foreach my $Pos (0 .. length($Params) - 1) 15422 { 15423 my $S = substr($Params, $Pos, 1); 15424 if(defined $B{$S}) { 15425 $B{$S} += 1; 15426 } 15427 if($S eq "," and 15428 $B{"("}==$B{")"} and $B{"<"}==$B{">"}) 15429 { 15430 if($Comma) 15431 { # include comma 15432 $Parts[$Part] .= $S; 15433 } 15434 $Part += 1; 15435 } 15436 else { 15437 $Parts[$Part] .= $S; 15438 } 15439 } 15440 if(not $Sp) 15441 { # remove spaces 15442 foreach (@Parts) 15443 { 15444 s/\A //g; 15445 s/ \Z//g; 15446 } 15447 } 15448 return @Parts; 15449} 15450 15451sub find_center($$) 15452{ 15453 my ($Sign, $Target) = @_; 15454 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15455 my $Center = 0; 15456 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g) 15457 { # operators 15458 $Center+=length($1); 15459 } 15460 foreach my $Pos (0 .. length($Sign)-1) 15461 { 15462 my $S = substr($Sign, $Pos, 1); 15463 if($S eq $Target) 15464 { 15465 if($B{"("}==$B{")"} 15466 and $B{"<"}==$B{">"}) { 15467 return $Center; 15468 } 15469 } 15470 if(defined $B{$S}) { 15471 $B{$S}+=1; 15472 } 15473 $Center+=1; 15474 } 15475 return 0; 15476} 15477 15478sub appendFile($$) 15479{ 15480 my ($Path, $Content) = @_; 15481 return if(not $Path); 15482 if(my $Dir = get_dirname($Path)) { 15483 mkpath($Dir); 15484 } 15485 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n"); 15486 print FILE $Content; 15487 close(FILE); 15488} 15489 15490sub writeFile($$) 15491{ 15492 my ($Path, $Content) = @_; 15493 return if(not $Path); 15494 if(my $Dir = get_dirname($Path)) { 15495 mkpath($Dir); 15496 } 15497 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n"); 15498 print FILE $Content; 15499 close(FILE); 15500} 15501 15502sub readFile($) 15503{ 15504 my $Path = $_[0]; 15505 return "" if(not $Path or not -f $Path); 15506 open(FILE, $Path); 15507 local $/ = undef; 15508 my $Content = <FILE>; 15509 close(FILE); 15510 if($Path!~/\.(tu|class|abi)\Z/) { 15511 $Content=~s/\r/\n/g; 15512 } 15513 return $Content; 15514} 15515 15516sub get_filename($) 15517{ # much faster than basename() from File::Basename module 15518 if(defined $Cache{"get_filename"}{$_[0]}) { 15519 return $Cache{"get_filename"}{$_[0]}; 15520 } 15521 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) { 15522 return ($Cache{"get_filename"}{$_[0]}=$1); 15523 } 15524 return ($Cache{"get_filename"}{$_[0]}=""); 15525} 15526 15527sub get_dirname($) 15528{ # much faster than dirname() from File::Basename module 15529 if(defined $Cache{"get_dirname"}{$_[0]}) { 15530 return $Cache{"get_dirname"}{$_[0]}; 15531 } 15532 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) { 15533 return ($Cache{"get_dirname"}{$_[0]}=$1); 15534 } 15535 return ($Cache{"get_dirname"}{$_[0]}=""); 15536} 15537 15538sub separate_path($) { 15539 return (get_dirname($_[0]), get_filename($_[0])); 15540} 15541 15542sub esc($) 15543{ 15544 my $Str = $_[0]; 15545 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g; 15546 return $Str; 15547} 15548 15549sub readLineNum($$) 15550{ 15551 my ($Path, $Num) = @_; 15552 return "" if(not $Path or not -f $Path); 15553 open(FILE, $Path); 15554 foreach (1 ... $Num) { 15555 <FILE>; 15556 } 15557 my $Line = <FILE>; 15558 close(FILE); 15559 return $Line; 15560} 15561 15562sub readAttributes($$) 15563{ 15564 my ($Path, $Num) = @_; 15565 return () if(not $Path or not -f $Path); 15566 my %Attributes = (); 15567 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/) 15568 { 15569 foreach my $AttrVal (split(/;/, $1)) 15570 { 15571 if($AttrVal=~/(.+):(.+)/) 15572 { 15573 my ($Name, $Value) = ($1, $2); 15574 $Attributes{$Name} = $Value; 15575 } 15576 } 15577 } 15578 return \%Attributes; 15579} 15580 15581sub is_abs($) { 15582 return ($_[0]=~/\A(\/|\w+:[\/\\])/); 15583} 15584 15585sub get_abs_path($) 15586{ # abs_path() should NOT be called for absolute inputs 15587 # because it can change them 15588 my $Path = $_[0]; 15589 if(not is_abs($Path)) { 15590 $Path = abs_path($Path); 15591 } 15592 return path_format($Path, $OSgroup); 15593} 15594 15595sub get_OSgroup() 15596{ 15597 my $N = $Config{"osname"}; 15598 if($N=~/macos|darwin|rhapsody/i) { 15599 return "macos"; 15600 } 15601 elsif($N=~/freebsd|openbsd|netbsd/i) { 15602 return "bsd"; 15603 } 15604 elsif($N=~/haiku|beos/i) { 15605 return "beos"; 15606 } 15607 elsif($N=~/symbian|epoc/i) { 15608 return "symbian"; 15609 } 15610 elsif($N=~/win/i) { 15611 return "windows"; 15612 } 15613 else { 15614 return $N; 15615 } 15616} 15617 15618sub getGccVersion($) 15619{ 15620 my $LibVersion = $_[0]; 15621 if($GCC_VERSION{$LibVersion}) 15622 { # dump version 15623 return $GCC_VERSION{$LibVersion}; 15624 } 15625 elsif($UsedDump{$LibVersion}{"V"}) 15626 { # old-version dumps 15627 return "unknown"; 15628 } 15629 my $GccVersion = get_dumpversion($GCC_PATH); # host version 15630 if(not $GccVersion) { 15631 return "unknown"; 15632 } 15633 return $GccVersion; 15634} 15635 15636sub showArch($) 15637{ 15638 my $Arch = $_[0]; 15639 if($Arch eq "arm" 15640 or $Arch eq "mips") { 15641 return uc($Arch); 15642 } 15643 return $Arch; 15644} 15645 15646sub getArch($) 15647{ 15648 my $LibVersion = $_[0]; 15649 15650 if($TargetArch) { 15651 return $TargetArch; 15652 } 15653 elsif($CPU_ARCH{$LibVersion}) 15654 { # dump 15655 return $CPU_ARCH{$LibVersion}; 15656 } 15657 elsif($UsedDump{$LibVersion}{"V"}) 15658 { # old-version dumps 15659 return "unknown"; 15660 } 15661 15662 return getArch_GCC($LibVersion); 15663} 15664 15665sub get_Report_Title($) 15666{ 15667 my $Level = $_[0]; 15668 15669 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>"; 15670 if(getArch(1) ne getArch(2) 15671 or getArch(1) eq "unknown" 15672 or $Level eq "Source") 15673 { # don't show architecture in the header 15674 $ArchInfo=""; 15675 } 15676 my $Title = ""; 15677 if($Level eq "Source") { 15678 $Title .= "Source compatibility"; 15679 } 15680 elsif($Level eq "Binary") { 15681 $Title .= "Binary compatibility"; 15682 } 15683 else { 15684 $Title .= "API compatibility"; 15685 } 15686 15687 my $V1 = $Descriptor{1}{"Version"}; 15688 my $V2 = $Descriptor{2}{"Version"}; 15689 15690 if($UsedDump{1}{"DWARF"} and $UsedDump{2}{"DWARF"}) 15691 { 15692 my $M1 = $UsedDump{1}{"M"}; 15693 my $M2 = $UsedDump{2}{"M"}; 15694 15695 my $M1S = $M1; 15696 my $M2S = $M2; 15697 15698 $M1S=~s/(\.so|\.ko)\..+/$1/ig; 15699 $M2S=~s/(\.so|\.ko)\..+/$1/ig; 15700 15701 if($M1S eq $M2S 15702 and $V1 ne "X" and $V2 ne "Y") 15703 { 15704 $Title .= " report for the <span style='color:Blue;'>$M1S</span> $TargetComponent"; 15705 $Title .= " between <span style='color:Red;'>".$V1."</span> and <span style='color:Red;'>".$V2."</span> versions"; 15706 } 15707 else 15708 { 15709 $Title .= " report between <span style='color:Blue;'>$M1</span> (<span style='color:Red;'>".$V1."</span>)"; 15710 $Title .= " and <span style='color:Blue;'>$M2</span> (<span style='color:Red;'>".$V2."</span>) objects"; 15711 } 15712 } 15713 else 15714 { 15715 $Title .= " report for the <span style='color:Blue;'>$TargetTitle</span> $TargetComponent"; 15716 $Title .= " between <span style='color:Red;'>".$V1."</span> and <span style='color:Red;'>".$V2."</span> versions"; 15717 } 15718 15719 $Title .= $ArchInfo; 15720 15721 if($AppPath) { 15722 $Title .= " (relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)"; 15723 } 15724 $Title = "<h1>".$Title."</h1>\n"; 15725 return $Title; 15726} 15727 15728sub get_CheckedHeaders($) 15729{ 15730 my $LibVersion = $_[0]; 15731 15732 my @Headers = (); 15733 15734 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 15735 { 15736 my $File = get_filename($Path); 15737 15738 if(not is_target_header($File, $LibVersion)) { 15739 next; 15740 } 15741 15742 if(skipHeader($File, $LibVersion)) { 15743 next; 15744 } 15745 15746 push(@Headers, $Path); 15747 } 15748 15749 return @Headers; 15750} 15751 15752sub get_SourceInfo() 15753{ 15754 my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", ""); 15755 15756 if(my @Headers = get_CheckedHeaders(1)) 15757 { 15758 $CheckedHeaders = "<a name='Headers'></a>"; 15759 if($OldStyle) { 15760 $CheckedHeaders .= "<h2>Header Files (".($#Headers+1).")</h2>"; 15761 } 15762 else { 15763 $CheckedHeaders .= "<h2>Header Files <span class='gray'> ".($#Headers+1)." </span></h2>"; 15764 } 15765 $CheckedHeaders .= "<hr/>\n<div class='h_list'>\n"; 15766 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 15767 { 15768 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"}; 15769 my $Name = get_filename($Identity); 15770 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15771 $CheckedHeaders .= $Name.$Comment."<br/>\n"; 15772 } 15773 $CheckedHeaders .= "</div>\n"; 15774 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n"; 15775 } 15776 15777 if(my @Sources = keys(%{$Registered_Sources{1}})) 15778 { 15779 $CheckedSources = "<a name='Sources'></a>"; 15780 if($OldStyle) { 15781 $CheckedSources .= "<h2>Source Files (".($#Sources+1).")</h2>"; 15782 } 15783 else { 15784 $CheckedSources .= "<h2>Source Files <span class='gray'> ".($#Sources+1)." </span></h2>"; 15785 } 15786 $CheckedSources .= "<hr/>\n<div class='h_list'>\n"; 15787 foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 15788 { 15789 my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"}; 15790 my $Name = get_filename($Identity); 15791 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15792 $CheckedSources .= $Name.$Comment."<br/>\n"; 15793 } 15794 $CheckedSources .= "</div>\n"; 15795 $CheckedSources .= "<br/>$TOP_REF<br/>\n"; 15796 } 15797 15798 if(not $CheckHeadersOnly) 15799 { 15800 $CheckedLibs = "<a name='Libs'></a>"; 15801 if($OldStyle) { 15802 $CheckedLibs .= "<h2>".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")</h2>"; 15803 } 15804 else { 15805 $CheckedLibs .= "<h2>".get_ObjTitle()." <span class='gray'> ".keys(%{$Library_Symbol{1}})." </span></h2>"; 15806 } 15807 $CheckedLibs .= "<hr/>\n<div class='lib_list'>\n"; 15808 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) { 15809 $CheckedLibs .= $Library."<br/>\n"; 15810 } 15811 $CheckedLibs .= "</div>\n"; 15812 $CheckedLibs .= "<br/>$TOP_REF<br/>\n"; 15813 } 15814 15815 return $CheckedHeaders.$CheckedSources.$CheckedLibs; 15816} 15817 15818sub get_ObjTitle() 15819{ 15820 if(defined $UsedDump{1}{"DWARF"}) { 15821 return "Objects"; 15822 } 15823 else { 15824 return ucfirst($SLIB_TYPE)." Libraries"; 15825 } 15826} 15827 15828sub get_TypeProblems_Count($$) 15829{ 15830 my ($TargetSeverity, $Level) = @_; 15831 my $Type_Problems_Count = 0; 15832 15833 foreach my $Type_Name (sort keys(%{$TypeChanges{$Level}})) 15834 { 15835 my %Kinds_Target = (); 15836 foreach my $Kind (keys(%{$TypeChanges{$Level}{$Type_Name}})) 15837 { 15838 foreach my $Location (keys(%{$TypeChanges{$Level}{$Type_Name}{$Kind}})) 15839 { 15840 my $Target = $TypeChanges{$Level}{$Type_Name}{$Kind}{$Location}{"Target"}; 15841 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15842 15843 if($Severity ne $TargetSeverity) { 15844 next; 15845 } 15846 15847 if($Kinds_Target{$Kind}{$Target}) { 15848 next; 15849 } 15850 15851 $Kinds_Target{$Kind}{$Target} = 1; 15852 $Type_Problems_Count += 1; 15853 } 15854 } 15855 } 15856 return $Type_Problems_Count; 15857} 15858 15859sub get_Summary($) 15860{ 15861 my $Level = $_[0]; 15862 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High, 15863 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other, $C_Other) = (0,0,0,0,0,0,0,0,0,0,0,0); 15864 %{$RESULT{$Level}} = ( 15865 "Problems"=>0, 15866 "Warnings"=>0, 15867 "Affected"=>0 ); 15868 # check rules 15869 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15870 { 15871 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 15872 { 15873 if(not defined $CompatRules{$Level}{$Kind}) 15874 { # unknown rule 15875 if(not $UnknownRules{$Level}{$Kind}) 15876 { # only one warning 15877 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15878 $UnknownRules{$Level}{$Kind}=1; 15879 } 15880 delete($CompatProblems{$Level}{$Interface}{$Kind}); 15881 } 15882 } 15883 } 15884 foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}})) 15885 { 15886 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 15887 { 15888 if(not defined $CompatRules{$Level}{$Kind}) 15889 { # unknown rule 15890 if(not $UnknownRules{$Level}{$Kind}) 15891 { # only one warning 15892 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15893 $UnknownRules{$Level}{$Kind}=1; 15894 } 15895 delete($CompatProblems_Constants{$Level}{$Constant}{$Kind}); 15896 } 15897 } 15898 } 15899 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15900 { 15901 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 15902 { 15903 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols") 15904 { 15905 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 15906 { 15907 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15908 if($Kind eq "Added_Symbol") { 15909 $Added += 1; 15910 } 15911 elsif($Kind eq "Removed_Symbol") 15912 { 15913 $Removed += 1; 15914 $TotalAffected{$Level}{$Interface} = $Severity; 15915 } 15916 else 15917 { 15918 if($Severity eq "Safe") { 15919 $I_Other += 1; 15920 } 15921 elsif($Severity eq "High") { 15922 $I_Problems_High += 1; 15923 } 15924 elsif($Severity eq "Medium") { 15925 $I_Problems_Medium += 1; 15926 } 15927 elsif($Severity eq "Low") { 15928 $I_Problems_Low += 1; 15929 } 15930 if(($Severity ne "Low" or $StrictCompat) 15931 and $Severity ne "Safe") { 15932 $TotalAffected{$Level}{$Interface} = $Severity; 15933 } 15934 } 15935 } 15936 } 15937 } 15938 } 15939 15940 my %MethodTypeIndex = (); 15941 15942 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15943 { 15944 my @Kinds = sort keys(%{$CompatProblems{$Level}{$Interface}}); 15945 foreach my $Kind (@Kinds) 15946 { 15947 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 15948 { 15949 my @Locs = sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}); 15950 foreach my $Location (@Locs) 15951 { 15952 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; 15953 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; 15954 15955 if(defined $MethodTypeIndex{$Interface}{$Type_Name}{$Kind}{$Target}) 15956 { # one location for one type and target 15957 next; 15958 } 15959 $MethodTypeIndex{$Interface}{$Type_Name}{$Kind}{$Target} = 1; 15960 $TypeChanges{$Level}{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; 15961 15962 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15963 15964 if(($Severity ne "Low" or $StrictCompat) 15965 and $Severity ne "Safe") 15966 { 15967 if(my $Sev = $TotalAffected{$Level}{$Interface}) 15968 { 15969 if($Severity_Val{$Severity}>$Severity_Val{$Sev}) { 15970 $TotalAffected{$Level}{$Interface} = $Severity; 15971 } 15972 } 15973 else { 15974 $TotalAffected{$Level}{$Interface} = $Severity; 15975 } 15976 } 15977 } 15978 } 15979 } 15980 } 15981 15982 $T_Problems_High = get_TypeProblems_Count("High", $Level); 15983 $T_Problems_Medium = get_TypeProblems_Count("Medium", $Level); 15984 $T_Problems_Low = get_TypeProblems_Count("Low", $Level); 15985 $T_Other = get_TypeProblems_Count("Safe", $Level); 15986 15987 # changed and removed public symbols 15988 my $SCount = keys(%{$CheckedSymbols{$Level}}); 15989 if($ExtendedCheck) 15990 { # don't count external_func_0 for constants 15991 $SCount-=1; 15992 } 15993 if($SCount) 15994 { 15995 my %Weight = ( 15996 "High" => 100, 15997 "Medium" => 50, 15998 "Low" => 25 15999 ); 16000 foreach (keys(%{$TotalAffected{$Level}})) { 16001 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}}; 16002 } 16003 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount; 16004 } 16005 else { 16006 $RESULT{$Level}{"Affected"} = 0; 16007 } 16008 16009 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"}); 16010 if($RESULT{$Level}{"Affected"}>=100) { 16011 $RESULT{$Level}{"Affected"} = 100; 16012 } 16013 16014 $RESULT{$Level}{"Problems"} += $Removed; 16015 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High; 16016 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium; 16017 if($StrictCompat) { 16018 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low; 16019 } 16020 else { 16021 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low; 16022 } 16023 16024 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 16025 { 16026 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 16027 { 16028 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16029 if($Severity eq "Safe") 16030 { 16031 $C_Other+=1; 16032 } 16033 elsif($Severity eq "Low") 16034 { 16035 $C_Problems_Low+=1; 16036 } 16037 } 16038 } 16039 16040 if($C_Problems_Low) 16041 { 16042 if($StrictCompat) { 16043 $RESULT{$Level}{"Problems"} += $C_Problems_Low; 16044 } 16045 else { 16046 $RESULT{$Level}{"Warnings"} += $C_Problems_Low; 16047 } 16048 } 16049 if($RESULT{$Level}{"Problems"} 16050 and $RESULT{$Level}{"Affected"}) { 16051 $RESULT{$Level}{"Verdict"} = "incompatible"; 16052 } 16053 else { 16054 $RESULT{$Level}{"Verdict"} = "compatible"; 16055 } 16056 16057 my $TotalTypes = keys(%{$CheckedTypes{$Level}}); 16058 if(not $TotalTypes) 16059 { # list all the types 16060 $TotalTypes = keys(%{$TName_Tid{1}}); 16061 } 16062 16063 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 16064 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2)); 16065 my ($ClangV1, $ClangV2) = ($CLANG_VERSION{1}, $CLANG_VERSION{2}); 16066 16067 my ($TestInfo, $TestResults, $Problem_Summary) = (); 16068 16069 if($ReportFormat eq "xml") 16070 { # XML 16071 # test info 16072 $TestInfo .= " <library>$TargetLibraryName</library>\n"; 16073 $TestInfo .= " <version1>\n"; 16074 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n"; 16075 $TestInfo .= " <arch>$Arch1</arch>\n"; 16076 if($GccV1) { 16077 $TestInfo .= " <gcc>$GccV1</gcc>\n"; 16078 } 16079 elsif($ClangV1) { 16080 $TestInfo .= " <clang>$ClangV1</clang>\n"; 16081 } 16082 $TestInfo .= " </version1>\n"; 16083 16084 $TestInfo .= " <version2>\n"; 16085 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n"; 16086 $TestInfo .= " <arch>$Arch2</arch>\n"; 16087 if($GccV2) { 16088 $TestInfo .= " <gcc>$GccV2</gcc>\n"; 16089 } 16090 elsif($ClangV2) { 16091 $TestInfo .= " <clang>$ClangV2</clang>\n"; 16092 } 16093 $TestInfo .= " </version2>\n"; 16094 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n"; 16095 16096 # test results 16097 if(my @Headers = keys(%{$Registered_Headers{1}})) 16098 { 16099 $TestResults .= " <headers>\n"; 16100 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 16101 { 16102 my $Identity = $Registered_Headers{1}{$Name}{"Identity"}; 16103 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 16104 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 16105 } 16106 $TestResults .= " </headers>\n"; 16107 } 16108 16109 if(my @Sources = keys(%{$Registered_Sources{1}})) 16110 { 16111 $TestResults .= " <sources>\n"; 16112 foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 16113 { 16114 my $Identity = $Registered_Sources{1}{$Name}{"Identity"}; 16115 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 16116 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 16117 } 16118 $TestResults .= " </sources>\n"; 16119 } 16120 16121 $TestResults .= " <libs>\n"; 16122 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) 16123 { 16124 # $Library .= " (.$LIB_EXT)" if($Library!~/\.\w+\Z/); 16125 $TestResults .= " <name>$Library</name>\n"; 16126 } 16127 $TestResults .= " </libs>\n"; 16128 16129 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n"; 16130 $TestResults .= " <types>".$TotalTypes."</types>\n"; 16131 16132 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n"; 16133 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n"; 16134 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n"; 16135 16136 # problem summary 16137 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n"; 16138 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n"; 16139 16140 $Problem_Summary .= " <problems_with_types>\n"; 16141 $Problem_Summary .= " <high>$T_Problems_High</high>\n"; 16142 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n"; 16143 $Problem_Summary .= " <low>$T_Problems_Low</low>\n"; 16144 $Problem_Summary .= " <safe>$T_Other</safe>\n"; 16145 $Problem_Summary .= " </problems_with_types>\n"; 16146 16147 $Problem_Summary .= " <problems_with_symbols>\n"; 16148 $Problem_Summary .= " <high>$I_Problems_High</high>\n"; 16149 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n"; 16150 $Problem_Summary .= " <low>$I_Problems_Low</low>\n"; 16151 $Problem_Summary .= " <safe>$I_Other</safe>\n"; 16152 $Problem_Summary .= " </problems_with_symbols>\n"; 16153 16154 $Problem_Summary .= " <problems_with_constants>\n"; 16155 $Problem_Summary .= " <low>$C_Problems_Low</low>\n"; 16156 $Problem_Summary .= " </problems_with_constants>\n"; 16157 16158 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n"; 16159 16160 return ($TestInfo.$TestResults.$Problem_Summary, ""); 16161 } 16162 else 16163 { # HTML 16164 # test info 16165 $TestInfo = "<h2>Test Info</h2><hr/>\n"; 16166 $TestInfo .= "<table class='summary'>\n"; 16167 16168 if($TargetComponent eq "library") { 16169 $TestInfo .= "<tr><th>Library Name</th><td>$TargetTitle</td></tr>\n"; 16170 } 16171 else { 16172 $TestInfo .= "<tr><th>Module Name</th><td>$TargetTitle</td></tr>\n"; 16173 } 16174 16175 my (@VInf1, @VInf2, $AddTestInfo) = (); 16176 if($Arch1 ne "unknown" 16177 and $Arch2 ne "unknown") 16178 { # CPU arch 16179 if($Arch1 eq $Arch2) 16180 { # go to the separate section 16181 $AddTestInfo .= "<tr><th>Arch</th><td>".showArch($Arch1)."</td></tr>\n"; 16182 } 16183 else 16184 { # go to the version number 16185 push(@VInf1, showArch($Arch1)); 16186 push(@VInf2, showArch($Arch2)); 16187 } 16188 } 16189 if($Level eq "Binary" 16190 and $OStarget ne "windows") 16191 { 16192 if($GccV1 ne "unknown" 16193 and $GccV2 ne "unknown") 16194 { # GCC version 16195 if($GccV1 eq $GccV2) 16196 { # go to the separate section 16197 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n"; 16198 } 16199 else 16200 { # go to the version number 16201 push(@VInf1, "gcc ".$GccV1); 16202 push(@VInf2, "gcc ".$GccV2); 16203 } 16204 } 16205 elsif($ClangV1 16206 and $ClangV2) 16207 { # Clang version 16208 if($ClangV1 eq $ClangV2) 16209 { # go to the separate section 16210 $AddTestInfo .= "<tr><th>Clang Version</th><td>$ClangV1</td></tr>\n"; 16211 } 16212 else 16213 { # go to the version number 16214 push(@VInf1, "clang ".$ClangV1); 16215 push(@VInf2, "clang ".$ClangV2); 16216 } 16217 } 16218 elsif($GccV1 ne "unknown" and $ClangV2) 16219 { 16220 push(@VInf1, "gcc ".$GccV1); 16221 push(@VInf2, "clang ".$ClangV2); 16222 } 16223 elsif($ClangV1 and $GccV2 ne "unknown") 16224 { 16225 push(@VInf1, "clang ".$ClangV1); 16226 push(@VInf2, "gcc ".$GccV2); 16227 } 16228 } 16229 # show long version names with GCC version and CPU architecture name (if different) 16230 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n"; 16231 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n"; 16232 $TestInfo .= $AddTestInfo; 16233 #if($COMMON_LANGUAGE{1}) { 16234 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n"; 16235 #} 16236 if($ExtendedCheck) { 16237 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n"; 16238 } 16239 if($JoinReport) 16240 { 16241 if($Level eq "Binary") { 16242 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time 16243 } 16244 elsif($Level eq "Source") { 16245 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time 16246 } 16247 } 16248 $TestInfo .= "</table>\n"; 16249 16250 # test results 16251 $TestResults = "<h2>Test Results</h2><hr/>\n"; 16252 $TestResults .= "<table class='summary'>"; 16253 16254 if(my @Headers = get_CheckedHeaders(1)) 16255 { 16256 my $Headers_Link = "<a href='#Headers' style='color:Blue;'>".($#Headers + 1)."</a>"; 16257 $TestResults .= "<tr><th>Total Header Files</th><td>".$Headers_Link."</td></tr>\n"; 16258 } 16259 16260 if(my @Sources = keys(%{$Registered_Sources{1}})) 16261 { 16262 my $Src_Link = "<a href='#Sources' style='color:Blue;'>".($#Sources + 1)."</a>"; 16263 $TestResults .= "<tr><th>Total Source Files</th><td>".$Src_Link."</td></tr>\n"; 16264 } 16265 16266 if(not $ExtendedCheck) 16267 { 16268 my $Libs_Link = "0"; 16269 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0); 16270 $TestResults .= "<tr><th>Total ".get_ObjTitle()."</th><td>".($CheckHeadersOnly?"0 (not analyzed)":$Libs_Link)."</td></tr>\n"; 16271 } 16272 16273 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n"; 16274 16275 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";"; 16276 if($JoinReport) { 16277 $META_DATA = "kind:".lc($Level).";".$META_DATA; 16278 } 16279 16280 my $BC_Rate = show_number(100 - $RESULT{$Level}{"Affected"}); 16281 16282 $TestResults .= "<tr><th>Compatibility</th>\n"; 16283 if($RESULT{$Level}{"Verdict"} eq "incompatible") 16284 { 16285 my $Cl = "incompatible"; 16286 if($BC_Rate>=90) { 16287 $Cl = "warning"; 16288 } 16289 elsif($BC_Rate>=80) { 16290 $Cl = "almost_compatible"; 16291 } 16292 16293 $TestResults .= "<td class=\'$Cl\'>".$BC_Rate."%</td>\n"; 16294 } 16295 else { 16296 $TestResults .= "<td class=\'compatible\'>100%</td>\n"; 16297 } 16298 $TestResults .= "</tr>\n"; 16299 $TestResults .= "</table>\n"; 16300 16301 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents 16302 # problem summary 16303 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n"; 16304 $Problem_Summary .= "<table class='summary'>"; 16305 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>"; 16306 16307 my $Added_Link = "0"; 16308 if($Added>0) 16309 { 16310 if($JoinReport) { 16311 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>"; 16312 } 16313 else { 16314 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>"; 16315 } 16316 } 16317 $META_DATA .= "added:$Added;"; 16318 $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "Added", $Added).">$Added_Link</td></tr>\n"; 16319 16320 my $Removed_Link = "0"; 16321 if($Removed>0) 16322 { 16323 if($JoinReport) { 16324 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>" 16325 } 16326 else { 16327 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>" 16328 } 16329 } 16330 $META_DATA .= "removed:$Removed;"; 16331 $Problem_Summary .= "<tr><th>Removed Symbols</th>"; 16332 $Problem_Summary .= "<td>High</td><td".getStyle("I", "Removed", $Removed).">$Removed_Link</td></tr>\n"; 16333 16334 my $TH_Link = "0"; 16335 $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0); 16336 $META_DATA .= "type_problems_high:$T_Problems_High;"; 16337 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>"; 16338 $Problem_Summary .= "<td>High</td><td".getStyle("T", "High", $T_Problems_High).">$TH_Link</td></tr>\n"; 16339 16340 my $TM_Link = "0"; 16341 $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0); 16342 $META_DATA .= "type_problems_medium:$T_Problems_Medium;"; 16343 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "Medium", $T_Problems_Medium).">$TM_Link</td></tr>\n"; 16344 16345 my $TL_Link = "0"; 16346 $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0); 16347 $META_DATA .= "type_problems_low:$T_Problems_Low;"; 16348 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "Low", $T_Problems_Low).">$TL_Link</td></tr>\n"; 16349 16350 my $IH_Link = "0"; 16351 $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0); 16352 $META_DATA .= "interface_problems_high:$I_Problems_High;"; 16353 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>"; 16354 $Problem_Summary .= "<td>High</td><td".getStyle("I", "High", $I_Problems_High).">$IH_Link</td></tr>\n"; 16355 16356 my $IM_Link = "0"; 16357 $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0); 16358 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;"; 16359 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "Medium", $I_Problems_Medium).">$IM_Link</td></tr>\n"; 16360 16361 my $IL_Link = "0"; 16362 $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0); 16363 $META_DATA .= "interface_problems_low:$I_Problems_Low;"; 16364 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "Low", $I_Problems_Low).">$IL_Link</td></tr>\n"; 16365 16366 my $ChangedConstants_Link = "0"; 16367 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) { 16368 $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>"; 16369 } 16370 $META_DATA .= "changed_constants:$C_Problems_Low;"; 16371 $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "Low", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n"; 16372 16373 # Safe Changes 16374 if($T_Other) 16375 { 16376 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>"; 16377 $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "Safe", $T_Other).">$TS_Link</td></tr>\n"; 16378 $META_DATA .= "type_changes_other:$T_Other;"; 16379 } 16380 16381 if($I_Other) 16382 { 16383 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>"; 16384 $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "Safe", $I_Other).">$IS_Link</td></tr>\n"; 16385 $META_DATA .= "interface_changes_other:$I_Other;"; 16386 } 16387 16388 if($C_Other) 16389 { 16390 my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>"; 16391 $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "Safe", $C_Other).">$CS_Link</td></tr>\n"; 16392 $META_DATA .= "constant_changes_other:$C_Other;"; 16393 } 16394 16395 $META_DATA .= "tool_version:$TOOL_VERSION"; 16396 $Problem_Summary .= "</table>\n"; 16397 16398 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA); 16399 } 16400} 16401 16402sub getStyle($$$) 16403{ 16404 my ($Subj, $Act, $Num) = @_; 16405 my %Style = ( 16406 "Added"=>"new", 16407 "Removed"=>"failed", 16408 "Safe"=>"passed", 16409 "Low"=>"warning", 16410 "Medium"=>"failed", 16411 "High"=>"failed" 16412 ); 16413 16414 if($Num>0) { 16415 return " class='".$Style{$Act}."'"; 16416 } 16417 16418 return ""; 16419} 16420 16421sub show_number($) 16422{ 16423 if($_[0]) 16424 { 16425 my $Num = cut_off_number($_[0], 2, 0); 16426 if($Num eq "0") 16427 { 16428 foreach my $P (3 .. 7) 16429 { 16430 $Num = cut_off_number($_[0], $P, 1); 16431 if($Num ne "0") { 16432 last; 16433 } 16434 } 16435 } 16436 if($Num eq "0") { 16437 $Num = $_[0]; 16438 } 16439 return $Num; 16440 } 16441 return $_[0]; 16442} 16443 16444sub cut_off_number($$$) 16445{ 16446 my ($num, $digs_to_cut, $z) = @_; 16447 if($num!~/\./) 16448 { 16449 $num .= "."; 16450 foreach (1 .. $digs_to_cut-1) { 16451 $num .= "0"; 16452 } 16453 } 16454 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1) 16455 { 16456 foreach (1 .. $digs_to_cut - 1 - length($1)) { 16457 $num .= "0"; 16458 } 16459 } 16460 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) { 16461 $num=sprintf("%.".($digs_to_cut-1)."f", $num); 16462 } 16463 $num=~s/\.[0]+\Z//g; 16464 if($z) { 16465 $num=~s/(\.[1-9]+)[0]+\Z/$1/g; 16466 } 16467 return $num; 16468} 16469 16470sub get_Report_ChangedConstants($$) 16471{ 16472 my ($TargetSeverity, $Level) = @_; 16473 my $CHANGED_CONSTANTS = ""; 16474 16475 my %ReportMap = (); 16476 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 16477 { 16478 my $Header = $Constants{1}{$Constant}{"Header"}; 16479 if(not $Header) 16480 { # added 16481 $Header = $Constants{2}{$Constant}{"Header"} 16482 } 16483 16484 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 16485 { 16486 if(not defined $CompatRules{$Level}{$Kind}) { 16487 next; 16488 } 16489 if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) { 16490 next; 16491 } 16492 $ReportMap{$Header}{$Constant}{$Kind} = 1; 16493 } 16494 } 16495 16496 if($ReportFormat eq "xml") 16497 { # XML 16498 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16499 { 16500 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n"; 16501 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16502 { 16503 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n"; 16504 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16505 { 16506 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16507 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16508 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}; 16509 16510 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n"; 16511 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n"; 16512 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n"; 16513 if($Overcome) { 16514 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n"; 16515 } 16516 $CHANGED_CONSTANTS .= " </problem>\n"; 16517 } 16518 $CHANGED_CONSTANTS .= " </constant>\n"; 16519 } 16520 $CHANGED_CONSTANTS .= " </header>\n"; 16521 } 16522 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n"; 16523 } 16524 else 16525 { # HTML 16526 my $ProblemsNum = 0; 16527 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16528 { 16529 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n"; 16530 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16531 { 16532 my $Report = ""; 16533 16534 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16535 { 16536 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind}); 16537 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16538 $Report .= "<tr>\n<th>1</th>\n<td>".$Change."</td>\n<td>$Effect</td>\n</tr>\n"; 16539 $ProblemsNum += 1; 16540 } 16541 if($Report) 16542 { 16543 $Report = $ContentDivStart."<table class='ptable'>\n<tr>\n<th width='2%'></th>\n<th width='47%'>Change</th>\n<th>Effect</th>\n</tr>\n".$Report."</table>\n<br/>\n$ContentDivEnd\n"; 16544 $Report = $ContentSpanStart."<span class='ext'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report; 16545 $Report = insertIDs($Report); 16546 } 16547 $CHANGED_CONSTANTS .= $Report; 16548 } 16549 $CHANGED_CONSTANTS .= "<br/>\n"; 16550 } 16551 if($CHANGED_CONSTANTS) 16552 { 16553 my $Title = "Problems with Constants, $TargetSeverity Severity"; 16554 if($TargetSeverity eq "Safe") 16555 { # Safe Changes 16556 $Title = "Other Changes in Constants"; 16557 } 16558 if($OldStyle) { 16559 $CHANGED_CONSTANTS = "<h2>$Title ($ProblemsNum)</h2><hr/>\n".$CHANGED_CONSTANTS; 16560 } 16561 else { 16562 $CHANGED_CONSTANTS = "<h2>$Title <span".getStyle("C", $TargetSeverity, $ProblemsNum)."> $ProblemsNum </span></h2><hr/>\n".$CHANGED_CONSTANTS; 16563 } 16564 $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n"; 16565 } 16566 } 16567 return $CHANGED_CONSTANTS; 16568} 16569 16570sub getTitle($$$) 16571{ 16572 my ($Header, $Library, $NameSpace) = @_; 16573 my $Title = ""; 16574 16575 # if($Library and $Library!~/\.\w+\Z/) { 16576 # $Library .= " (.$LIB_EXT)"; 16577 # } 16578 16579 if($Header and $Library) 16580 { 16581 $Title .= "<span class='h_name'>$Header</span>"; 16582 $Title .= ", <span class='lib_name'>$Library</span><br/>\n"; 16583 } 16584 elsif($Library) { 16585 $Title .= "<span class='lib_name'>$Library</span><br/>\n"; 16586 } 16587 elsif($Header) { 16588 $Title .= "<span class='h_name'>$Header</span><br/>\n"; 16589 } 16590 16591 if($NameSpace) { 16592 $Title .= "<span class='ns'>namespace <b>$NameSpace</b></span><br/>\n"; 16593 } 16594 16595 return $Title; 16596} 16597 16598sub get_Report_Added($) 16599{ 16600 my $Level = $_[0]; 16601 my $ADDED_INTERFACES = ""; 16602 my %ReportMap = (); 16603 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 16604 { 16605 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 16606 { 16607 if($Kind eq "Added_Symbol") 16608 { 16609 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"}; 16610 my $DyLib = $Symbol_Library{2}{$Interface}; 16611 if($Level eq "Source" and $ReportFormat eq "html") 16612 { # do not show library name in HTML report 16613 $DyLib = ""; 16614 } 16615 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1; 16616 } 16617 } 16618 } 16619 if($ReportFormat eq "xml") 16620 { # XML 16621 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16622 { 16623 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16624 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16625 { 16626 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16627 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16628 $ADDED_INTERFACES .= " <name>$Interface</name>\n"; 16629 } 16630 $ADDED_INTERFACES .= " </library>\n"; 16631 } 16632 $ADDED_INTERFACES .= " </header>\n"; 16633 } 16634 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n"; 16635 } 16636 else 16637 { # HTML 16638 my $Added_Number = 0; 16639 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16640 { 16641 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16642 { 16643 my %NameSpaceSymbols = (); 16644 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16645 $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1; 16646 } 16647 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16648 { 16649 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16650 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16651 foreach my $Interface (@SortedInterfaces) 16652 { 16653 $Added_Number += 1; 16654 my $Signature = get_Signature($Interface, 2); 16655 if($NameSpace) { 16656 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16657 } 16658 if($Interface=~/\A(_Z|\?)/) 16659 { 16660 if($Signature) { 16661 $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>\n<br/>\n<br/>\n".$ContentDivEnd."\n"); 16662 } 16663 else { 16664 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16665 } 16666 } 16667 else 16668 { 16669 if($Signature) { 16670 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16671 } 16672 else { 16673 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16674 } 16675 } 16676 } 16677 $ADDED_INTERFACES .= "<br/>\n"; 16678 } 16679 } 16680 } 16681 if($ADDED_INTERFACES) 16682 { 16683 my $Anchor = "<a name='Added'></a>"; 16684 if($JoinReport) { 16685 $Anchor = "<a name='".$Level."_Added'></a>"; 16686 } 16687 if($OldStyle) { 16688 $ADDED_INTERFACES = "<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES; 16689 } 16690 else { 16691 $ADDED_INTERFACES = "<h2>Added Symbols <span".getStyle("I", "Added", $Added_Number)."> $Added_Number </span></h2><hr/>\n".$ADDED_INTERFACES; 16692 } 16693 $ADDED_INTERFACES = $Anchor.$ADDED_INTERFACES.$TOP_REF."<br/>\n"; 16694 } 16695 } 16696 return $ADDED_INTERFACES; 16697} 16698 16699sub get_Report_Removed($) 16700{ 16701 my $Level = $_[0]; 16702 my $REMOVED_INTERFACES = ""; 16703 my %ReportMap = (); 16704 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16705 { 16706 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16707 { 16708 if($Kind eq "Removed_Symbol") 16709 { 16710 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16711 my $DyLib = $Symbol_Library{1}{$Symbol}; 16712 if($Level eq "Source" and $ReportFormat eq "html") 16713 { # do not show library name in HTML report 16714 $DyLib = ""; 16715 } 16716 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16717 } 16718 } 16719 } 16720 if($ReportFormat eq "xml") 16721 { # XML 16722 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16723 { 16724 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16725 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16726 { 16727 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16728 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16729 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n"; 16730 } 16731 $REMOVED_INTERFACES .= " </library>\n"; 16732 } 16733 $REMOVED_INTERFACES .= " </header>\n"; 16734 } 16735 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n"; 16736 } 16737 else 16738 { # HTML 16739 my $Removed_Number = 0; 16740 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16741 { 16742 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16743 { 16744 my %NameSpaceSymbols = (); 16745 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16746 $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1; 16747 } 16748 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16749 { 16750 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16751 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16752 foreach my $Symbol (@SortedInterfaces) 16753 { 16754 $Removed_Number += 1; 16755 my $SubReport = ""; 16756 my $Signature = get_Signature($Symbol, 1); 16757 if($NameSpace) { 16758 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16759 } 16760 if($Symbol=~/\A(_Z|\?)/) 16761 { 16762 if($Signature) { 16763 $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span>\n<br/>\n<br/>\n".$ContentDivEnd."\n"); 16764 } 16765 else { 16766 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16767 } 16768 } 16769 else 16770 { 16771 if($Signature) { 16772 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16773 } 16774 else { 16775 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16776 } 16777 } 16778 } 16779 } 16780 $REMOVED_INTERFACES .= "<br/>\n"; 16781 } 16782 } 16783 if($REMOVED_INTERFACES) 16784 { 16785 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>"; 16786 if($JoinReport) { 16787 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>"; 16788 } 16789 if($OldStyle) { 16790 $REMOVED_INTERFACES = "<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES; 16791 } 16792 else { 16793 $REMOVED_INTERFACES = "<h2>Removed Symbols <span".getStyle("I", "Removed", $Removed_Number)."> $Removed_Number </span></h2><hr/>\n".$REMOVED_INTERFACES; 16794 } 16795 16796 $REMOVED_INTERFACES = $Anchor.$REMOVED_INTERFACES.$TOP_REF."<br/>\n"; 16797 } 16798 } 16799 return $REMOVED_INTERFACES; 16800} 16801 16802sub getXmlParams($$) 16803{ 16804 my ($Content, $Problem) = @_; 16805 return "" if(not $Content or not $Problem); 16806 my %XMLparams = (); 16807 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16808 { 16809 my $Macro = "\@".lc($Attr); 16810 if($Content=~/\Q$Macro\E/) { 16811 $XMLparams{lc($Attr)} = $Problem->{$Attr}; 16812 } 16813 } 16814 my @PString = (); 16815 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) { 16816 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\""); 16817 } 16818 if(@PString) { 16819 return " ".join(" ", @PString); 16820 } 16821 else { 16822 return ""; 16823 } 16824} 16825 16826sub addMarkup($) 16827{ 16828 my $Content = $_[0]; 16829 # auto-markup 16830 $Content=~s/\n[ ]*//; # spaces 16831 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size) 16832 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list) 16833 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g; 16834 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ... 16835 if($Content=~/\ANOTE:/) 16836 { # notes 16837 $Content=~s!(NOTE):!<b>$1</b>:!g; 16838 } 16839 else { 16840 $Content=~s!(NOTE):!<br/><b>$1</b>:!g; 16841 } 16842 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters 16843 my @Keywords = ( 16844 "void", 16845 "const", 16846 "static", 16847 "restrict", 16848 "volatile", 16849 "register", 16850 "virtual" 16851 ); 16852 my $MKeys = join("|", @Keywords); 16853 foreach (@Keywords) { 16854 $MKeys .= "|non-".$_; 16855 } 16856 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers 16857 16858 # Markdown 16859 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig; 16860 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig; 16861 return $Content; 16862} 16863 16864sub applyMacroses($$$$) 16865{ 16866 my ($Level, $Kind, $Content, $Problem) = @_; 16867 return "" if(not $Content or not $Problem); 16868 $Problem->{"Word_Size"} = $WORD_SIZE{2}; 16869 $Content = addMarkup($Content); 16870 # macros 16871 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16872 { 16873 my $Macro = "\@".lc($Attr); 16874 my $Value = $Problem->{$Attr}; 16875 if(not defined $Value 16876 or $Value eq "") { 16877 next; 16878 } 16879 16880 if(index($Content, $Macro)==-1) { 16881 next; 16882 } 16883 16884 if($Kind!~/\A(Changed|Added|Removed)_Constant\Z/ 16885 and $Kind!~/_Type_/ 16886 and $Value=~/\s\(/ and $Value!~/['"]/) 16887 { # functions 16888 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals 16889 $Value=~s/\s[a-z]\w*(\)|,)/$1/ig; # remove parameter names 16890 $Value = black_name($Value); 16891 } 16892 elsif($Value=~/\s/) { 16893 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>"; 16894 } 16895 elsif($Value=~/\A\d+\Z/ 16896 and ($Attr eq "Old_Size" or $Attr eq "New_Size")) 16897 { # bits to bytes 16898 if($Value % $BYTE_SIZE) 16899 { # bits 16900 if($Value==1) { 16901 $Value = "<b>".$Value."</b> bit"; 16902 } 16903 else { 16904 $Value = "<b>".$Value."</b> bits"; 16905 } 16906 } 16907 else 16908 { # bytes 16909 $Value /= $BYTE_SIZE; 16910 if($Value==1) { 16911 $Value = "<b>".$Value."</b> byte"; 16912 } 16913 else { 16914 $Value = "<b>".$Value."</b> bytes"; 16915 } 16916 } 16917 } 16918 else 16919 { 16920 $Value = "<b>".htmlSpecChars($Value)."</b>"; 16921 } 16922 $Content=~s/\Q$Macro\E/$Value/g; 16923 } 16924 16925 if($Content=~/(\A|[^\@\w])\@\w/) 16926 { 16927 if(not $IncompleteRules{$Level}{$Kind}) 16928 { # only one warning 16929 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")"); 16930 $IncompleteRules{$Level}{$Kind} = 1; 16931 } 16932 } 16933 return $Content; 16934} 16935 16936sub get_Report_SymbolProblems($$) 16937{ 16938 my ($TargetSeverity, $Level) = @_; 16939 my $INTERFACE_PROBLEMS = ""; 16940 my (%ReportMap, %SymbolChanges) = (); 16941 16942 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16943 { 16944 my ($SN, $SS, $SV) = separate_symbol($Symbol); 16945 if($SV and defined $CompatProblems{$Level}{$SN}) { 16946 next; 16947 } 16948 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16949 my $DyLib = $Symbol_Library{1}{$Symbol}; 16950 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol}) 16951 { # Symbol with Version 16952 $DyLib = $Symbol_Library{1}{$VSym}; 16953 } 16954 if(not $DyLib) 16955 { # const global data 16956 $DyLib = ""; 16957 } 16958 if($Level eq "Source" and $ReportFormat eq "html") 16959 { # do not show library name in HTML report 16960 $DyLib = ""; 16961 } 16962 16963 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16964 { 16965 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols" 16966 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol") 16967 { 16968 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16969 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}})) 16970 { 16971 if($Severity eq $TargetSeverity) 16972 { 16973 $SymbolChanges{$Symbol}{$Kind} = $CompatProblems{$Level}{$Symbol}{$Kind}; 16974 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16975 } 16976 } 16977 } 16978 } 16979 } 16980 16981 if($ReportFormat eq "xml") 16982 { # XML 16983 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16984 { 16985 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 16986 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16987 { 16988 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n"; 16989 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$ReportMap{$HeaderName}{$DyLib}}); 16990 foreach my $Symbol (@SortedInterfaces) 16991 { 16992 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n"; 16993 foreach my $Kind (sort keys(%{$SymbolChanges{$Symbol}})) 16994 { 16995 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16996 { 16997 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 16998 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 16999 17000 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 17001 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 17002 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 17003 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 17004 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 17005 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 17006 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 17007 } 17008 $INTERFACE_PROBLEMS .= " </problem>\n"; 17009 } 17010 } 17011 $INTERFACE_PROBLEMS .= " </symbol>\n"; 17012 } 17013 $INTERFACE_PROBLEMS .= " </library>\n"; 17014 } 17015 $INTERFACE_PROBLEMS .= " </header>\n"; 17016 } 17017 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n"; 17018 } 17019 else 17020 { # HTML 17021 my $ProblemsNum = 0; 17022 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 17023 { 17024 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 17025 { 17026 my (%NameSpaceSymbols, %NewSignature) = (); 17027 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 17028 $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 17029 } 17030 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 17031 { 17032 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace); 17033 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} sort keys(%{$NameSpaceSymbols{$NameSpace}}); 17034 foreach my $Symbol (@SortedInterfaces) 17035 { 17036 my $Signature = get_Signature($Symbol, 1); 17037 my $SYMBOL_REPORT = ""; 17038 my $ProblemNum = 1; 17039 foreach my $Kind (sort keys(%{$SymbolChanges{$Symbol}})) 17040 { 17041 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 17042 { 17043 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 17044 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 17045 if($Problem{"New_Signature"}) { 17046 $NewSignature{$Symbol} = $Problem{"New_Signature"}; 17047 } 17048 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 17049 { 17050 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 17051 $SYMBOL_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td>".$Change."</td>\n<td>".$Effect."</td>\n</tr>\n"; 17052 $ProblemNum += 1; 17053 $ProblemsNum += 1; 17054 } 17055 } 17056 } 17057 $ProblemNum -= 1; 17058 if($SYMBOL_REPORT) 17059 { 17060 my $ShowSymbol = $Symbol; 17061 if($Signature) { 17062 $ShowSymbol = highLight_Signature_Italic_Color($Signature); 17063 } 17064 17065 if($NameSpace) 17066 { 17067 $SYMBOL_REPORT = cut_Namespace($SYMBOL_REPORT, $NameSpace); 17068 $ShowSymbol = cut_Namespace($ShowSymbol, $NameSpace); 17069 } 17070 17071 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='ext'>[+]</span> ".$ShowSymbol; 17072 if($OldStyle) { 17073 $INTERFACE_PROBLEMS .= " ($ProblemNum)"; 17074 } 17075 else { 17076 $INTERFACE_PROBLEMS .= " <span".getStyle("I", $TargetSeverity, $ProblemNum)."> $ProblemNum </span>"; 17077 } 17078 $INTERFACE_PROBLEMS .= $ContentSpanEnd."<br/>\n"; 17079 $INTERFACE_PROBLEMS .= $ContentDivStart."\n"; 17080 17081 if(my $NSign = $NewSignature{$Symbol}) 17082 { # argument list changed to 17083 if($NameSpace) { 17084 $NSign = cut_Namespace($NSign, $NameSpace); 17085 } 17086 $INTERFACE_PROBLEMS .= "\n<span class='new_sign_lbl'>changed to:</span>\n<br/>\n<span class='new_sign'>".highLight_Signature_Italic_Color($NSign)."</span><br/>\n"; 17087 } 17088 17089 if($Symbol=~/\A(_Z|\?)/) { 17090 $INTERFACE_PROBLEMS .= "<span class='mangled'>    [symbol: <b>$Symbol</b>]</span><br/>\n"; 17091 } 17092 17093 $INTERFACE_PROBLEMS .= "<table class='ptable'>\n<tr>\n<th width='2%'></th>\n<th width='47%'>Change</th>\n<th>Effect</th>\n</tr>\n$SYMBOL_REPORT</table>\n<br/>\n"; 17094 $INTERFACE_PROBLEMS .= $ContentDivEnd; 17095 } 17096 } 17097 $INTERFACE_PROBLEMS .= "<br/>\n"; 17098 } 17099 } 17100 } 17101 17102 if($INTERFACE_PROBLEMS) 17103 { 17104 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS); 17105 my $Title = "Problems with Symbols, $TargetSeverity Severity"; 17106 if($TargetSeverity eq "Safe") 17107 { # Safe Changes 17108 $Title = "Other Changes in Symbols"; 17109 } 17110 if($OldStyle) { 17111 $INTERFACE_PROBLEMS = "<h2>$Title ($ProblemsNum)</h2><hr/>\n".$INTERFACE_PROBLEMS; 17112 } 17113 else { 17114 $INTERFACE_PROBLEMS = "<h2>$Title <span".getStyle("I", $TargetSeverity, $ProblemsNum)."> $ProblemsNum </span></h2><hr/>\n".$INTERFACE_PROBLEMS; 17115 } 17116 $INTERFACE_PROBLEMS = "<a name=\'".get_Anchor("Symbol", $Level, $TargetSeverity)."\'></a><a name=\'".get_Anchor("Interface", $Level, $TargetSeverity)."\'></a>\n".$INTERFACE_PROBLEMS.$TOP_REF."<br/>\n"; 17117 } 17118 } 17119 return $INTERFACE_PROBLEMS; 17120} 17121 17122sub cut_Namespace($$) 17123{ 17124 my ($N, $Ns) = @_; 17125 $N=~s/\b\Q$Ns\E:://g; 17126 return $N; 17127} 17128 17129sub get_Report_TypeProblems($$) 17130{ 17131 my ($TargetSeverity, $Level) = @_; 17132 my $TYPE_PROBLEMS = ""; 17133 17134 my %ReportMap = (); 17135 my %TypeChanges_Sev = (); 17136 17137 foreach my $TypeName (keys(%{$TypeChanges{$Level}})) 17138 { 17139 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"}; 17140 17141 foreach my $Kind (keys(%{$TypeChanges{$Level}{$TypeName}})) 17142 { 17143 foreach my $Location (keys(%{$TypeChanges{$Level}{$TypeName}{$Kind}})) 17144 { 17145 my $Target = $TypeChanges{$Level}{$TypeName}{$Kind}{$Location}{"Target"}; 17146 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 17147 17148 if($Severity eq $TargetSeverity) 17149 { 17150 $ReportMap{$HeaderName}{$TypeName} = 1; 17151 $TypeChanges_Sev{$TypeName}{$Kind}{$Location} = $TypeChanges{$Level}{$TypeName}{$Kind}{$Location}; 17152 } 17153 } 17154 } 17155 } 17156 17157 if($ReportFormat eq "xml") 17158 { # XML 17159 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 17160 { 17161 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 17162 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) 17163 { 17164 my (%Kinds_Locations, %Kinds_Target) = (); 17165 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n"; 17166 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges_Sev{$TypeName}})) 17167 { 17168 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges_Sev{$TypeName}{$Kind}})) 17169 { 17170 $Kinds_Locations{$Kind}{$Location} = 1; 17171 17172 my $Target = $TypeChanges_Sev{$TypeName}{$Kind}{$Location}{"Target"}; 17173 if($Kinds_Target{$Kind}{$Target}) { 17174 next; 17175 } 17176 $Kinds_Target{$Kind}{$Target} = 1; 17177 17178 my %Problem = %{$TypeChanges_Sev{$TypeName}{$Kind}{$Location}}; 17179 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 17180 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 17181 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 17182 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 17183 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 17184 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 17185 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 17186 } 17187 $TYPE_PROBLEMS .= " </problem>\n"; 17188 } 17189 } 17190 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, \%Kinds_Locations); 17191 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%Kinds_Locations)) { 17192 $TYPE_PROBLEMS .= showVTables($TypeName); 17193 } 17194 $TYPE_PROBLEMS .= " </type>\n"; 17195 } 17196 $TYPE_PROBLEMS .= " </header>\n"; 17197 } 17198 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n"; 17199 } 17200 else 17201 { # HTML 17202 my $ProblemsNum = 0; 17203 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 17204 { 17205 my (%NameSpace_Type) = (); 17206 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) { 17207 $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1; 17208 } 17209 foreach my $NameSpace (sort keys(%NameSpace_Type)) 17210 { 17211 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace); 17212 my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}}); 17213 foreach my $TypeName (@SortedTypes) 17214 { 17215 my $ProblemNum = 1; 17216 my $TYPE_REPORT = ""; 17217 my (%Kinds_Locations, %Kinds_Target) = (); 17218 17219 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges_Sev{$TypeName}})) 17220 { 17221 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges_Sev{$TypeName}{$Kind}})) 17222 { 17223 $Kinds_Locations{$Kind}{$Location} = 1; 17224 17225 my $Target = $TypeChanges_Sev{$TypeName}{$Kind}{$Location}{"Target"}; 17226 if($Kinds_Target{$Kind}{$Target}) { 17227 next; 17228 } 17229 $Kinds_Target{$Kind}{$Target} = 1; 17230 17231 my %Problem = %{$TypeChanges_Sev{$TypeName}{$Kind}{$Location}}; 17232 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 17233 { 17234 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 17235 $TYPE_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td>".$Change."</td>\n<td>$Effect</td>\n</tr>\n"; 17236 $ProblemNum += 1; 17237 $ProblemsNum += 1; 17238 } 17239 } 17240 } 17241 $ProblemNum -= 1; 17242 if($TYPE_REPORT) 17243 { 17244 my $Affected = getAffectedSymbols($Level, $TypeName, \%Kinds_Locations); 17245 my $ShowVTables = ""; 17246 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%Kinds_Locations)) { 17247 $ShowVTables = showVTables($TypeName); 17248 } 17249 17250 my $ShowType = show_Type($TypeName, 1, 1); 17251 17252 if($NameSpace) 17253 { 17254 $TYPE_REPORT = cut_Namespace($TYPE_REPORT, $NameSpace); 17255 $ShowType = cut_Namespace($ShowType, $NameSpace); 17256 $Affected = cut_Namespace($Affected, $NameSpace); 17257 $ShowVTables = cut_Namespace($ShowVTables, $NameSpace); 17258 } 17259 17260 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='ext'>[+]</span> ".$ShowType; 17261 if($OldStyle) { 17262 $TYPE_PROBLEMS .= " ($ProblemNum)"; 17263 } 17264 else { 17265 $TYPE_PROBLEMS .= " <span".getStyle("T", $TargetSeverity, $ProblemNum)."> $ProblemNum </span>"; 17266 } 17267 $TYPE_PROBLEMS .= $ContentSpanEnd; 17268 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n"; 17269 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n"; 17270 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n"; 17271 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n"; 17272 } 17273 } 17274 $TYPE_PROBLEMS .= "<br/>\n"; 17275 } 17276 } 17277 17278 if($TYPE_PROBLEMS) 17279 { 17280 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS); 17281 my $Title = "Problems with Data Types, $TargetSeverity Severity"; 17282 if($TargetSeverity eq "Safe") 17283 { # Safe Changes 17284 $Title = "Other Changes in Data Types"; 17285 } 17286 if($OldStyle) { 17287 $TYPE_PROBLEMS = "<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS; 17288 } 17289 else { 17290 $TYPE_PROBLEMS = "<h2>$Title <span".getStyle("T", $TargetSeverity, $ProblemsNum)."> $ProblemsNum </span></h2><hr/>\n".$TYPE_PROBLEMS; 17291 } 17292 $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n"; 17293 } 17294 } 17295 return $TYPE_PROBLEMS; 17296} 17297 17298sub show_Type($$$) 17299{ 17300 my ($Name, $Html, $LibVersion) = @_; 17301 my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"}; 17302 $TType = lc($TType); 17303 if($TType=~/struct|union|enum/) { 17304 $Name=~s/\A\Q$TType\E //g; 17305 } 17306 if($Html) { 17307 $Name = "<span class='ttype'>".$TType."</span> ".htmlSpecChars($Name); 17308 } 17309 else { 17310 $Name = $TType." ".$Name; 17311 } 17312 return $Name; 17313} 17314 17315sub get_Anchor($$$) 17316{ 17317 my ($Kind, $Level, $Severity) = @_; 17318 if($JoinReport) 17319 { 17320 if($Severity eq "Safe") { 17321 return "Other_".$Level."_Changes_In_".$Kind."s"; 17322 } 17323 else { 17324 return $Kind."_".$Level."_Problems_".$Severity; 17325 } 17326 } 17327 else 17328 { 17329 if($Severity eq "Safe") { 17330 return "Other_Changes_In_".$Kind."s"; 17331 } 17332 else { 17333 return $Kind."_Problems_".$Severity; 17334 } 17335 } 17336} 17337 17338sub showVTables($) 17339{ 17340 my $TypeName = $_[0]; 17341 my $TypeId1 = $TName_Tid{1}{$TypeName}; 17342 my %Type1 = get_Type($TypeId1, 1); 17343 if(defined $Type1{"VTable"} 17344 and keys(%{$Type1{"VTable"}})) 17345 { 17346 my $TypeId2 = $TName_Tid{2}{$TypeName}; 17347 my %Type2 = get_Type($TypeId2, 2); 17348 if(defined $Type2{"VTable"} 17349 and keys(%{$Type2{"VTable"}})) 17350 { 17351 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}})); 17352 my %Entries = (); 17353 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes))) 17354 { 17355 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index}); 17356 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index}); 17357 } 17358 my $VTABLES = ""; 17359 if($ReportFormat eq "xml") 17360 { # XML 17361 $VTABLES .= " <vtable>\n"; 17362 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 17363 { 17364 $VTABLES .= " <entry offset=\"".$Index."\">\n"; 17365 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n"; 17366 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n"; 17367 $VTABLES .= " </entry>\n"; 17368 } 17369 $VTABLES .= " </vtable>\n\n"; 17370 } 17371 else 17372 { # HTML 17373 $VTABLES .= "<table class='vtable'>"; 17374 $VTABLES .= "<tr><th>Offset</th>"; 17375 $VTABLES .= "<th>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>"; 17376 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>"; 17377 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 17378 { 17379 my ($Color1, $Color2) = ("", ""); 17380 17381 my $E1 = $Entries{$Index}{"E1"}; 17382 my $E2 = $Entries{$Index}{"E2"}; 17383 17384 if($E1 ne $E2 17385 and $E1!~/ 0x/ 17386 and $E2!~/ 0x/) 17387 { 17388 if($Entries{$Index}{"E1"}) 17389 { 17390 $Color1 = " class='failed'"; 17391 $Color2 = " class='failed'"; 17392 } 17393 else { 17394 $Color2 = " class='warning'"; 17395 } 17396 } 17397 $VTABLES .= "<tr><th>".$Index."</th>\n"; 17398 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n"; 17399 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n"; 17400 } 17401 $VTABLES .= "</table><br/>\n"; 17402 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd; 17403 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES; 17404 } 17405 return $VTABLES; 17406 } 17407 } 17408 return ""; 17409} 17410 17411sub simpleVEntry($) 17412{ 17413 my $VEntry = $_[0]; 17414 if(not defined $VEntry 17415 or $VEntry eq "") { 17416 return ""; 17417 } 17418 17419 $VEntry=~s/ \[.+?\]\Z//; # support for ABI Dumper 17420 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks 17421 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo 17422 if($VEntry=~/\A_ZThn.+\Z/) { 17423 $VEntry = "non-virtual thunk"; 17424 } 17425 $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i; 17426 # support for old GCC versions 17427 $VEntry=~s/\A0u\Z/(int (*)(...))0/; 17428 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/; 17429 $VEntry=~s/\A&_Z\Z/& _Z/; 17430 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors 17431 return $VEntry; 17432} 17433 17434sub adjustParamPos($$$) 17435{ 17436 my ($Pos, $Symbol, $LibVersion) = @_; 17437 if(defined $CompleteSignature{$LibVersion}{$Symbol}) 17438 { 17439 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"} 17440 and $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 17441 { 17442 return $Pos-1; 17443 } 17444 17445 return $Pos; 17446 } 17447 17448 return undef; 17449} 17450 17451sub getParamPos($$$) 17452{ 17453 my ($Name, $Symbol, $LibVersion) = @_; 17454 17455 if(defined $CompleteSignature{$LibVersion}{$Symbol} 17456 and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}) 17457 { 17458 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17459 foreach (keys(%{$Info->{"Param"}})) 17460 { 17461 if($Info->{"Param"}{$_}{"name"} eq $Name) 17462 { 17463 return $_; 17464 } 17465 } 17466 } 17467 17468 return undef; 17469} 17470 17471sub getParamName($) 17472{ 17473 my $Loc = $_[0]; 17474 $Loc=~s/\->.*//g; 17475 return $Loc; 17476} 17477 17478sub getAffectedSymbols($$$) 17479{ 17480 my ($Level, $Target_TypeName, $Kinds_Locations) = @_; 17481 17482 my $LIMIT = 10; 17483 if(defined $AffectLimit) { 17484 $LIMIT = $AffectLimit; 17485 } 17486 17487 my @Kinds = sort keys(%{$Kinds_Locations}); 17488 my %KLocs = (); 17489 foreach my $Kind (@Kinds) 17490 { 17491 my @Locs = sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$Kinds_Locations->{$Kind}}); 17492 $KLocs{$Kind} = \@Locs; 17493 } 17494 17495 my %SymLocKind = (); 17496 foreach my $Symbol (sort keys(%{$TypeProblemsIndex{$Level}{$Target_TypeName}})) 17497 { 17498 if(index($Symbol, "_Z")==0 17499 and $Symbol=~/(C2|D2|D0)[EI]/) 17500 { # duplicated problems for C2 constructors, D2 and D0 destructors 17501 next; 17502 } 17503 17504 foreach my $Kind (@Kinds) 17505 { 17506 foreach my $Loc (@{$KLocs{$Kind}}) 17507 { 17508 if(not defined $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}) { 17509 next; 17510 } 17511 17512 if(index($Symbol, "\@")!=-1 17513 or index($Symbol, "\$")!=-1) 17514 { 17515 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17516 17517 if($Level eq "Source") 17518 { # remove symbol version 17519 $Symbol = $SN; 17520 } 17521 17522 if($SV and defined $CompatProblems{$Level}{$SN} 17523 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Loc}) 17524 { # duplicated problems for versioned symbols 17525 next; 17526 } 17527 } 17528 17529 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}{"Type_Name"}; 17530 if($Type_Name ne $Target_TypeName) { 17531 next; 17532 } 17533 17534 $SymLocKind{$Symbol}{$Loc}{$Kind} = 1; 17535 last; 17536 } 17537 } 17538 } 17539 17540 %KLocs = (); # clear 17541 17542 my %SymSel = (); 17543 my $Num = 0; 17544 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymLocKind)) 17545 { 17546 LOOP: foreach my $Loc (sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$SymLocKind{$Symbol}})) 17547 { 17548 foreach my $Kind (sort keys(%{$SymLocKind{$Symbol}{$Loc}})) 17549 { 17550 $SymSel{$Symbol}{"Loc"} = $Loc; 17551 $SymSel{$Symbol}{"Kind"} = $Kind; 17552 last LOOP; 17553 } 17554 } 17555 17556 $Num += 1; 17557 17558 if($Num>=$LIMIT) { 17559 last; 17560 } 17561 } 17562 17563 my $Affected = ""; 17564 17565 if($ReportFormat eq "xml") 17566 { # XML 17567 $Affected .= " <affected>\n"; 17568 17569 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17570 { 17571 my $Kind = $SymSel{$Symbol}{"Kind"}; 17572 my $Loc = $SymSel{$Symbol}{"Loc"}; 17573 17574 my $PName = getParamName($Loc); 17575 my $Desc = getAffectDesc($Level, $Symbol, $Kind, $Loc); 17576 17577 my $Target = ""; 17578 if($PName) 17579 { 17580 $Target .= " param=\"$PName\""; 17581 $Desc=~s/parameter $PName /parameter \@param /; 17582 } 17583 elsif($Loc=~/\Aretval(\-|\Z)/i) { 17584 $Target .= " affected=\"retval\""; 17585 } 17586 elsif($Loc=~/\Athis(\-|\Z)/i) { 17587 $Target .= " affected=\"this\""; 17588 } 17589 17590 if($Desc=~s/\AField ([^\s]+) /Field \@field /) { 17591 $Target .= " field=\"$1\""; 17592 } 17593 17594 $Affected .= " <symbol name=\"$Symbol\"$Target>\n"; 17595 $Affected .= " <comment>".xmlSpecChars($Desc)."</comment>\n"; 17596 $Affected .= " </symbol>\n"; 17597 } 17598 $Affected .= " </affected>\n"; 17599 } 17600 else 17601 { # HTML 17602 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17603 { 17604 my $Kind = $SymSel{$Symbol}{"Kind"}; 17605 my $Loc = $SymSel{$Symbol}{"Loc"}; 17606 17607 my $Desc = getAffectDesc($Level, $Symbol, $Kind, $Loc); 17608 my $S = get_Signature($Symbol, 1); 17609 my $PName = getParamName($Loc); 17610 my $Pos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1); 17611 17612 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($S, $Pos, 1, 0, 0)."</span><br/>\n"; 17613 $Affected .= "<div class='affect'>".htmlSpecChars($Desc)."</div>\n"; 17614 } 17615 17616 if(keys(%SymLocKind)>$LIMIT) { 17617 $Affected .= " <b>...</b>\n<br/>\n"; # and others ... 17618 } 17619 17620 $Affected = "<div class='affected'>".$Affected."</div>\n"; 17621 if($Affected) 17622 { 17623 my $Num = keys(%SymLocKind); 17624 my $Per = show_number($Num*100/keys(%{$CheckedSymbols{$Level}})); 17625 $Affected = $ContentDivStart.$Affected.$ContentDivEnd; 17626 $Affected = $ContentSpanStart_Affected."[+] affected symbols: $Num ($Per\%)".$ContentSpanEnd.$Affected; 17627 } 17628 } 17629 17630 return $Affected; 17631} 17632 17633sub cmpLocations($$) 17634{ 17635 my ($L1, $L2) = @_; 17636 if($L2=~/\A(retval|this)\b/ 17637 and $L1!~/\A(retval|this)\b/) 17638 { 17639 if($L1!~/\-\>/) { 17640 return 1; 17641 } 17642 elsif($L2=~/\-\>/) { 17643 return 1; 17644 } 17645 } 17646 return 0; 17647} 17648 17649sub getAffectDesc($$$$) 17650{ 17651 my ($Level, $Symbol, $Kind, $Location) = @_; 17652 17653 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}}; 17654 17655 my $Location_I = $Location; 17656 $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field 17657 17658 my @Sentence = (); 17659 17660 if($Kind eq "Overridden_Virtual_Method" 17661 or $Kind eq "Overridden_Virtual_Method_B") { 17662 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method."); 17663 } 17664 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 17665 { 17666 my %SymInfo = %{$CompleteSignature{1}{$Symbol}}; 17667 17668 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/) 17669 { 17670 my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method"; 17671 my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"}; 17672 17673 if($ClassName eq $Problem{"Type_Name"}) { 17674 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class."); 17675 } 17676 else { 17677 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'."); 17678 } 17679 } 17680 else 17681 { 17682 my $TypeID = undef; 17683 17684 if($Location=~/retval/) 17685 { # return value 17686 if(index($Location, "->")!=-1) { 17687 push(@Sentence, "Field \'".$Location."\' in return value"); 17688 } 17689 else { 17690 push(@Sentence, "Return value"); 17691 } 17692 17693 $TypeID = $SymInfo{"Return"}; 17694 } 17695 elsif($Location=~/this/) 17696 { # "this" pointer 17697 if(index($Location, "->")!=-1) { 17698 push(@Sentence, "Field \'".$Location."\' in the object of this method"); 17699 } 17700 else { 17701 push(@Sentence, "\'this\' pointer"); 17702 } 17703 17704 $TypeID = $SymInfo{"Class"}; 17705 } 17706 else 17707 { # parameters 17708 17709 my $PName = getParamName($Location); 17710 my $PPos = getParamPos($PName, $Symbol, 1); 17711 17712 if(index($Location, "->")!=-1) { 17713 push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17714 } 17715 else { 17716 push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17717 } 17718 if($PName) { 17719 push(@Sentence, "\'".$PName."\'"); 17720 } 17721 17722 $TypeID = $SymInfo{"Param"}{$PPos}{"type"}; 17723 } 17724 17725 if($Location!~/this/) 17726 { 17727 if(my %PureType = get_PureType($TypeID, $TypeInfo{1})) 17728 { 17729 if($PureType{"Type"} eq "Pointer") { 17730 push(@Sentence, "(pointer)"); 17731 } 17732 elsif($PureType{"Type"} eq "Ref") { 17733 push(@Sentence, "(reference)"); 17734 } 17735 } 17736 } 17737 17738 if($Location eq "this") { 17739 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17740 } 17741 else 17742 { 17743 my $Location_T = $Location; 17744 $Location_T=~s/\A\w+(\->|\Z)//; # location in type 17745 17746 my $TypeID_Problem = $TypeID; 17747 if($Location_T) { 17748 $TypeID_Problem = getFieldType($Location_T, $TypeID, 1); 17749 } 17750 17751 if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) { 17752 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); 17753 } 17754 else { 17755 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17756 } 17757 } 17758 } 17759 } 17760 if($ExtendedSymbols{$Symbol}) { 17761 push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling."); 17762 } 17763 17764 my $Sent = join(" ", @Sentence); 17765 17766 $Sent=~s/->/./g; 17767 17768 if($ReportFormat eq "xml") 17769 { 17770 $Sent=~s/'//g; 17771 } 17772 17773 return $Sent; 17774} 17775 17776sub getFieldType($$$) 17777{ 17778 my ($Location, $TypeId, $LibVersion) = @_; 17779 17780 my @Fields = split(/\->/, $Location); 17781 17782 foreach my $Name (@Fields) 17783 { 17784 my %Info = get_BaseType($TypeId, $LibVersion); 17785 17786 foreach my $Pos (keys(%{$Info{"Memb"}})) 17787 { 17788 if($Info{"Memb"}{$Pos}{"name"} eq $Name) 17789 { 17790 $TypeId = $Info{"Memb"}{$Pos}{"type"}; 17791 last; 17792 } 17793 } 17794 } 17795 17796 return $TypeId; 17797} 17798 17799sub get_XmlSign($$) 17800{ 17801 my ($Symbol, $LibVersion) = @_; 17802 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17803 my $Report = ""; 17804 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}})) 17805 { 17806 my $Name = $Info->{"Param"}{$Pos}{"name"}; 17807 my $Type = $Info->{"Param"}{$Pos}{"type"}; 17808 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"}; 17809 foreach my $Typedef (keys(%ChangedTypedef)) 17810 { 17811 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 17812 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g; 17813 } 17814 } 17815 $Report .= " <param pos=\"$Pos\">\n"; 17816 $Report .= " <name>".$Name."</name>\n"; 17817 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n"; 17818 $Report .= " </param>\n"; 17819 } 17820 if(my $Return = $Info->{"Return"}) 17821 { 17822 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"}; 17823 $Report .= " <retval>\n"; 17824 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n"; 17825 $Report .= " </retval>\n"; 17826 } 17827 return $Report; 17828} 17829 17830sub get_Report_SymbolsInfo($) 17831{ 17832 my $Level = $_[0]; 17833 my $Report = "<symbols_info>\n"; 17834 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 17835 { 17836 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17837 if($SV and defined $CompatProblems{$Level}{$SN}) { 17838 next; 17839 } 17840 $Report .= " <symbol name=\"$Symbol\">\n"; 17841 my ($S1, $P1, $S2, $P2) = (); 17842 if(not $AddedInt{$Level}{$Symbol}) 17843 { 17844 if(defined $CompleteSignature{1}{$Symbol} 17845 and defined $CompleteSignature{1}{$Symbol}{"Header"}) 17846 { 17847 $P1 = get_XmlSign($Symbol, 1); 17848 $S1 = get_Signature($Symbol, 1); 17849 } 17850 elsif($Symbol=~/\A(_Z|\?)/) { 17851 $S1 = $tr_name{$Symbol}; 17852 } 17853 } 17854 if(not $RemovedInt{$Level}{$Symbol}) 17855 { 17856 if(defined $CompleteSignature{2}{$Symbol} 17857 and defined $CompleteSignature{2}{$Symbol}{"Header"}) 17858 { 17859 $P2 = get_XmlSign($Symbol, 2); 17860 $S2 = get_Signature($Symbol, 2); 17861 } 17862 elsif($Symbol=~/\A(_Z|\?)/) { 17863 $S2 = $tr_name{$Symbol}; 17864 } 17865 } 17866 if($S1) 17867 { 17868 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n"; 17869 $Report .= $P1; 17870 $Report .= " </old>\n"; 17871 } 17872 if($S2 and $S2 ne $S1) 17873 { 17874 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n"; 17875 $Report .= $P2; 17876 $Report .= " </new>\n"; 17877 } 17878 $Report .= " </symbol>\n"; 17879 } 17880 $Report .= "</symbols_info>\n"; 17881 return $Report; 17882} 17883 17884sub writeReport($$) 17885{ 17886 my ($Level, $Report) = @_; 17887 if($ReportFormat eq "xml") { 17888 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report; 17889 } 17890 if($StdOut) 17891 { # --stdout option 17892 print STDOUT $Report; 17893 } 17894 else 17895 { 17896 my $RPath = getReportPath($Level); 17897 mkpath(get_dirname($RPath)); 17898 17899 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n"); 17900 print REPORT $Report; 17901 close(REPORT); 17902 } 17903} 17904 17905sub getReport($) 17906{ 17907 my $Level = $_[0]; 17908 if($ReportFormat eq "xml") 17909 { # XML 17910 if($Level eq "Join") 17911 { 17912 my $Report = "<reports>\n"; 17913 $Report .= getReport("Binary"); 17914 $Report .= getReport("Source"); 17915 $Report .= "</reports>\n"; 17916 return $Report; 17917 } 17918 else 17919 { 17920 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n"; 17921 my ($Summary, $MetaData) = get_Summary($Level); 17922 $Report .= $Summary."\n"; 17923 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17924 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17925 17926 # additional symbols info (if needed) 17927 # $Report .= get_Report_SymbolsInfo($Level); 17928 17929 $Report .= "</report>\n"; 17930 return $Report; 17931 } 17932 } 17933 else 17934 { # HTML 17935 my $CssStyles = readModule("Styles", "Report.css"); 17936 my $JScripts = readModule("Scripts", "Sections.js"); 17937 if($Level eq "Join") 17938 { 17939 $CssStyles .= "\n".readModule("Styles", "Tabs.css"); 17940 $JScripts .= "\n".readModule("Scripts", "Tabs.js"); 17941 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report"; 17942 my $Keywords = $TargetTitle.", compatibility, API, ABI, report"; 17943 my $Description = "API/ABI compatibility report for the $TargetTitle $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17944 my ($BSummary, $BMetaData) = get_Summary("Binary"); 17945 my ($SSummary, $SMetaData) = get_Summary("Source"); 17946 my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>"; 17947 $Report .= get_Report_Title("Join")." 17948 <br/> 17949 <div class='tabset'> 17950 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a> 17951 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a> 17952 </div>"; 17953 $Report .= "<div id='BinaryTab' class='tab'>\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."<br/><br/><br/></div>"; 17954 $Report .= "<div id='SourceTab' class='tab'>\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."<br/><br/><br/></div>"; 17955 $Report .= getReportFooter(); 17956 $Report .= "\n</body></html>\n"; 17957 return $Report; 17958 } 17959 else 17960 { 17961 my ($Summary, $MetaData) = get_Summary($Level); 17962 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report"; 17963 my $Keywords = $TargetTitle.", ".lc($Level)." compatibility, API, report"; 17964 my $Description = "$Level compatibility report for the ".$TargetTitle." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17965 if($Level eq "Binary") 17966 { 17967 if(getArch(1) eq getArch(2) 17968 and getArch(1) ne "unknown") { 17969 $Description .= " on ".showArch(getArch(1)); 17970 } 17971 } 17972 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n"; 17973 $Report .= get_Report_Title($Level)."\n".$Summary."\n"; 17974 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17975 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17976 $Report .= get_SourceInfo(); 17977 $Report .= "</div>\n<br/><br/><br/>\n"; 17978 $Report .= getReportFooter(); 17979 $Report .= "\n</body></html>\n"; 17980 return $Report; 17981 } 17982 } 17983} 17984 17985sub createReport() 17986{ 17987 if($JoinReport) 17988 { # --stdout 17989 writeReport("Join", getReport("Join")); 17990 } 17991 elsif($DoubleReport) 17992 { # default 17993 writeReport("Binary", getReport("Binary")); 17994 writeReport("Source", getReport("Source")); 17995 } 17996 elsif($BinaryOnly) 17997 { # --binary 17998 writeReport("Binary", getReport("Binary")); 17999 } 18000 elsif($SourceOnly) 18001 { # --source 18002 writeReport("Source", getReport("Source")); 18003 } 18004} 18005 18006sub getReportFooter() 18007{ 18008 my $Footer = ""; 18009 18010 $Footer .= "<hr/>\n"; 18011 $Footer .= "<div class='footer' align='right'>"; 18012 $Footer .= "<i>Generated by <a href='".$HomePage{"Dev"}."'>ABI Compliance Checker</a> $TOOL_VERSION  </i>\n"; 18013 $Footer .= "</div>\n"; 18014 $Footer .= "<br/>\n"; 18015 18016 return $Footer; 18017} 18018 18019sub get_Report_Problems($$) 18020{ 18021 my ($Severity, $Level) = @_; 18022 18023 my $Report = get_Report_TypeProblems($Severity, $Level); 18024 if(my $SProblems = get_Report_SymbolProblems($Severity, $Level)) { 18025 $Report .= $SProblems; 18026 } 18027 18028 if($Severity eq "Low" or $Severity eq "Safe") { 18029 $Report .= get_Report_ChangedConstants($Severity, $Level); 18030 } 18031 18032 if($ReportFormat eq "html") 18033 { 18034 if($Report) 18035 { # add anchor 18036 if($JoinReport) 18037 { 18038 if($Severity eq "Safe") { 18039 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report; 18040 } 18041 else { 18042 $Report = "<a name=\'".$Severity."_Risk_".$Level."_Problems\'></a>".$Report; 18043 } 18044 } 18045 else 18046 { 18047 if($Severity eq "Safe") { 18048 $Report = "<a name=\'Other_Changes\'></a>".$Report; 18049 } 18050 else { 18051 $Report = "<a name=\'".$Severity."_Risk_Problems\'></a>".$Report; 18052 } 18053 } 18054 } 18055 } 18056 return $Report; 18057} 18058 18059sub composeHTML_Head($$$$$) 18060{ 18061 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_; 18062 18063 my $Head = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 18064 $Head .= "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"; 18065 $Head .= "<head>\n"; 18066 $Head .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; 18067 $Head .= "<meta name=\"keywords\" content=\"$Keywords\" />\n"; 18068 $Head .= "<meta name=\"description\" content=\"$Description\" />\n"; 18069 $Head .= "<title>$Title</title>\n"; 18070 $Head .= "<style type=\"text/css\">\n$Styles</style>\n"; 18071 $Head .= "<script type=\"text/javascript\" language=\"JavaScript\">\n<!--\n$Scripts\n-->\n</script>\n"; 18072 $Head .= "</head>\n"; 18073 18074 return $Head; 18075} 18076 18077sub insertIDs($) 18078{ 18079 my $Text = $_[0]; 18080 while($Text=~/CONTENT_ID/) 18081 { 18082 if(int($Content_Counter)%2) { 18083 $ContentID -= 1; 18084 } 18085 $Text=~s/CONTENT_ID/c_$ContentID/; 18086 $ContentID += 1; 18087 $Content_Counter += 1; 18088 } 18089 return $Text; 18090} 18091 18092sub checkPreprocessedUnit($) 18093{ 18094 my $Path = $_[0]; 18095 my ($CurHeader, $CurHeaderName) = ("", ""); 18096 my $CurClass = ""; # extra info 18097 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n"); 18098 18099 while(my $Line = <PREPROC>) 18100 { # detecting public and private constants 18101 if(substr($Line, 0, 1) eq "#") 18102 { 18103 chomp($Line); 18104 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/) 18105 { 18106 $CurHeader = path_format($1, $OSgroup); 18107 $CurHeaderName = get_filename($CurHeader); 18108 $CurClass = ""; 18109 18110 if(index($CurHeader, $TMP_DIR)==0) { 18111 next; 18112 } 18113 18114 if(substr($CurHeaderName, 0, 1) eq "<") 18115 { # <built-in>, <command-line>, etc. 18116 $CurHeaderName = ""; 18117 $CurHeader = ""; 18118 } 18119 18120 if($ExtraInfo) 18121 { 18122 if($CurHeaderName) { 18123 $PreprocessedHeaders{$Version}{$CurHeader} = 1; 18124 } 18125 } 18126 } 18127 if(not $ExtraDump) 18128 { 18129 if($CurHeaderName) 18130 { 18131 if(not $Include_Neighbors{$Version}{$CurHeaderName} 18132 and not $Registered_Headers{$Version}{$CurHeader}) 18133 { # not a target 18134 next; 18135 } 18136 if(not is_target_header($CurHeaderName, 1) 18137 and not is_target_header($CurHeaderName, 2)) 18138 { # user-defined header 18139 next; 18140 } 18141 } 18142 } 18143 18144 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/) 18145 { 18146 my ($Name, $Value) = ($1, $2); 18147 if(not $Constants{$Version}{$Name}{"Access"}) 18148 { 18149 $Constants{$Version}{$Name}{"Access"} = "public"; 18150 $Constants{$Version}{$Name}{"Value"} = $Value; 18151 if($CurHeaderName) { 18152 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName; 18153 } 18154 } 18155 } 18156 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) { 18157 $Constants{$Version}{$1}{"Access"} = "private"; 18158 } 18159 } 18160 else 18161 { 18162 if(defined $ExtraDump) 18163 { 18164 if($Line=~/(\w+)\s*\(/) 18165 { # functions 18166 $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 18167 } 18168 #elsif($Line=~/(\w+)\s*;/) 18169 #{ # data 18170 # $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 18171 #} 18172 elsif($Line=~/(\A|\s)class\s+(\w+)/) { 18173 $CurClass = $2; 18174 } 18175 } 18176 } 18177 } 18178 close(PREPROC); 18179 foreach my $Constant (keys(%{$Constants{$Version}})) 18180 { 18181 if($Constants{$Version}{$Constant}{"Access"} eq "private") 18182 { 18183 delete($Constants{$Version}{$Constant}); 18184 next; 18185 } 18186 if(not $ExtraDump and ($Constant=~/_h\Z/i 18187 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) 18188 { # skip 18189 delete($Constants{$Version}{$Constant}); 18190 } 18191 else { 18192 delete($Constants{$Version}{$Constant}{"Access"}); 18193 } 18194 } 18195 if($Debug) 18196 { 18197 mkpath($DEBUG_PATH{$Version}); 18198 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt"); 18199 } 18200} 18201 18202sub uncoverConstant($$) 18203{ 18204 my ($LibVersion, $Constant) = @_; 18205 return "" if(not $LibVersion or not $Constant); 18206 return $Constant if(isCyclical(\@RecurConstant, $Constant)); 18207 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) { 18208 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant}; 18209 } 18210 18211 if(defined $Constants{$LibVersion}{$Constant}) 18212 { 18213 my $Value = $Constants{$LibVersion}{$Constant}{"Value"}; 18214 if(defined $Constants{$LibVersion}{$Value}) 18215 { 18216 push(@RecurConstant, $Constant); 18217 my $Uncovered = uncoverConstant($LibVersion, $Value); 18218 if($Uncovered ne "") { 18219 $Value = $Uncovered; 18220 } 18221 pop(@RecurConstant); 18222 } 18223 18224 # FIXME: uncover $Value using all the enum constants 18225 # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define) 18226 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value); 18227 } 18228 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = ""); 18229} 18230 18231sub simpleConstant($$) 18232{ 18233 my ($LibVersion, $Value) = @_; 18234 if($Value=~/\W/) 18235 { 18236 my $Value_Copy = $Value; 18237 while($Value_Copy=~s/([a-z_]\w+)/\@/i) 18238 { 18239 my $Word = $1; 18240 if($Value!~/$Word\s*\(/) 18241 { 18242 my $Val = uncoverConstant($LibVersion, $Word); 18243 if($Val ne "") 18244 { 18245 $Value=~s/\b$Word\b/$Val/g; 18246 } 18247 } 18248 } 18249 } 18250 return $Value; 18251} 18252 18253sub computeValue($) 18254{ 18255 my $Value = $_[0]; 18256 18257 if($Value=~/\A\((-?[\d]+)\)\Z/) { 18258 return $1; 18259 } 18260 18261 if($Value=~/\A[\d\-\+()]+\Z/) { 18262 return eval($Value); 18263 } 18264 18265 return $Value; 18266} 18267 18268my %IgnoreConstant = map {$_=>1} ( 18269 "VERSION", 18270 "VERSIONCODE", 18271 "VERNUM", 18272 "VERS_INFO", 18273 "PATCHLEVEL", 18274 "INSTALLPREFIX", 18275 "VBUILD", 18276 "VPATCH", 18277 "VMINOR", 18278 "BUILD_STRING", 18279 "BUILD_TIME", 18280 "PACKAGE_STRING", 18281 "PRODUCTION", 18282 "CONFIGURE_COMMAND", 18283 "INSTALLDIR", 18284 "BINDIR", 18285 "CONFIG_FILE_PATH", 18286 "DATADIR", 18287 "EXTENSION_DIR", 18288 "INCLUDE_PATH", 18289 "LIBDIR", 18290 "LOCALSTATEDIR", 18291 "SBINDIR", 18292 "SYSCONFDIR", 18293 "RELEASE", 18294 "SOURCE_ID", 18295 "SUBMINOR", 18296 "MINOR", 18297 "MINNOR", 18298 "MINORVERSION", 18299 "MAJOR", 18300 "MAJORVERSION", 18301 "MICRO", 18302 "MICROVERSION", 18303 "BINARY_AGE", 18304 "INTERFACE_AGE", 18305 "CORE_ABI", 18306 "PATCH", 18307 "COPYRIGHT", 18308 "TIMESTAMP", 18309 "REVISION", 18310 "PACKAGE_TAG", 18311 "PACKAGEDATE", 18312 "NUMVERSION", 18313 "Release", 18314 "Version" 18315); 18316 18317sub constantFilter($$$) 18318{ 18319 my ($Name, $Value, $Level) = @_; 18320 18321 if($Level eq "Binary") 18322 { 18323 if($Name=~/_t\Z/) 18324 { # __malloc_ptr_t 18325 return 1; 18326 } 18327 foreach (keys(%IgnoreConstant)) 18328 { 18329 if($Name=~/(\A|_)$_(_|\Z)/) 18330 { # version 18331 return 1; 18332 } 18333 if(/\A[A-Z].*[a-z]\Z/) 18334 { 18335 if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/) 18336 { # version 18337 return 1; 18338 } 18339 } 18340 } 18341 if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i) 18342 { # version 18343 return 1; 18344 } 18345 if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/) 18346 { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ... 18347 return 1; 18348 } 18349 18350 if($Value=~/\A["'].*['"]/i) 18351 { # string 18352 return 0; 18353 } 18354 18355 if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i) 18356 { # static int gcry_pth_init 18357 # extern ABC 18358 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE... 18359 # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ... 18360 return 1; 18361 } 18362 if($Value=~/\w+\s*\(/i) 18363 { # foo(p) 18364 return 1; 18365 } 18366 if($Value=~/\A[a-z_]+\w*\Z/i) 18367 { # asn1_node_st 18368 # __SMTH_P 18369 return 1; 18370 } 18371 } 18372 18373 return 0; 18374} 18375 18376sub mergeConstants($) 18377{ 18378 my $Level = $_[0]; 18379 foreach my $Constant (keys(%{$Constants{1}})) 18380 { 18381 if($SkipConstants{1}{$Constant}) 18382 { # skipped by the user 18383 next; 18384 } 18385 18386 if(my $Header = $Constants{1}{$Constant}{"Header"}) 18387 { 18388 if(not is_target_header($Header, 1) 18389 and not is_target_header($Header, 2)) 18390 { # user-defined header 18391 next; 18392 } 18393 } 18394 else { 18395 next; 18396 } 18397 18398 my $Old_Value = uncoverConstant(1, $Constant); 18399 18400 if(constantFilter($Constant, $Old_Value, $Level)) 18401 { # separate binary and source problems 18402 next; 18403 } 18404 18405 if(not defined $Constants{2}{$Constant}{"Value"}) 18406 { # removed 18407 if(not defined $SkipRemovedConstants) 18408 { 18409 %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = ( 18410 "Target"=>$Constant, 18411 "Old_Value"=>$Old_Value ); 18412 } 18413 next; 18414 } 18415 18416 if($Constants{2}{$Constant}{"Value"} eq "") 18417 { # empty value 18418 # TODO: implement a rule 18419 next; 18420 } 18421 18422 my $New_Value = uncoverConstant(2, $Constant); 18423 18424 my $Old_Value_Pure = $Old_Value; 18425 my $New_Value_Pure = $New_Value; 18426 18427 $Old_Value_Pure=~s/(\W)\s+/$1/g; 18428 $Old_Value_Pure=~s/\s+(\W)/$1/g; 18429 $New_Value_Pure=~s/(\W)\s+/$1/g; 18430 $New_Value_Pure=~s/\s+(\W)/$1/g; 18431 18432 next if($New_Value_Pure eq "" or $Old_Value_Pure eq ""); 18433 18434 if($New_Value_Pure ne $Old_Value_Pure) 18435 { # different values 18436 if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value)) 18437 { # complex values 18438 next; 18439 } 18440 if(computeValue($Old_Value) eq computeValue($New_Value)) 18441 { # expressions 18442 next; 18443 } 18444 if(convert_integer($Old_Value) eq convert_integer($New_Value)) 18445 { # 0x0001 and 0x1, 0x1 and 1 equal constants 18446 next; 18447 } 18448 if($Old_Value eq "0" and $New_Value eq "NULL") 18449 { # 0 => NULL 18450 next; 18451 } 18452 if($Old_Value eq "NULL" and $New_Value eq "0") 18453 { # NULL => 0 18454 next; 18455 } 18456 %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = ( 18457 "Target"=>$Constant, 18458 "Old_Value"=>$Old_Value, 18459 "New_Value"=>$New_Value ); 18460 } 18461 } 18462 18463 if(defined $SkipAddedConstants) { 18464 return; 18465 } 18466 18467 foreach my $Constant (keys(%{$Constants{2}})) 18468 { 18469 if(not defined $Constants{1}{$Constant}{"Value"}) 18470 { 18471 if($SkipConstants{2}{$Constant}) 18472 { # skipped by the user 18473 next; 18474 } 18475 18476 if(my $Header = $Constants{2}{$Constant}{"Header"}) 18477 { 18478 if(not is_target_header($Header, 1) 18479 and not is_target_header($Header, 2)) 18480 { # user-defined header 18481 next; 18482 } 18483 } 18484 else { 18485 next; 18486 } 18487 18488 my $New_Value = uncoverConstant(2, $Constant); 18489 if(not defined $New_Value or $New_Value eq "") { 18490 next; 18491 } 18492 18493 if(constantFilter($Constant, $New_Value, $Level)) 18494 { # separate binary and source problems 18495 next; 18496 } 18497 18498 %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = ( 18499 "Target"=>$Constant, 18500 "New_Value"=>$New_Value ); 18501 } 18502 } 18503} 18504 18505sub convert_integer($) 18506{ 18507 my $Value = $_[0]; 18508 if($Value=~/\A0x[a-f0-9]+\Z/) 18509 { # hexadecimal 18510 return hex($Value); 18511 } 18512 elsif($Value=~/\A0[0-7]+\Z/) 18513 { # octal 18514 return oct($Value); 18515 } 18516 elsif($Value=~/\A0b[0-1]+\Z/) 18517 { # binary 18518 return oct($Value); 18519 } 18520 else { 18521 return $Value; 18522 } 18523} 18524 18525sub readSymbols($) 18526{ 18527 my $LibVersion = $_[0]; 18528 my @LibPaths = getSOPaths($LibVersion); 18529 if($#LibPaths==-1 and not $CheckHeadersOnly) 18530 { 18531 if($LibVersion==1) 18532 { 18533 printMsg("WARNING", "checking headers only"); 18534 $CheckHeadersOnly = 1; 18535 } 18536 else { 18537 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"}); 18538 } 18539 } 18540 18541 foreach my $LibPath (@LibPaths) { 18542 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1); 18543 } 18544 18545 if($CheckUndefined) 18546 { 18547 my %UndefinedLibs = (); 18548 18549 my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}})); 18550 18551 foreach my $LibName (sort @Libs) 18552 { 18553 if(defined $UndefinedSymbols{$LibVersion}{$LibName}) 18554 { 18555 foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}})) 18556 { 18557 if($Symbol_Library{$LibVersion}{$Symbol} 18558 or $DepSymbol_Library{$LibVersion}{$Symbol}) 18559 { # exported by target library 18560 next; 18561 } 18562 if(index($Symbol, '@')!=-1) 18563 { # exported default symbol version (@@) 18564 $Symbol=~s/\@/\@\@/; 18565 if($Symbol_Library{$LibVersion}{$Symbol} 18566 or $DepSymbol_Library{$LibVersion}{$Symbol}) { 18567 next; 18568 } 18569 } 18570 foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) { 18571 $UndefinedLibs{$Path} = 1; 18572 } 18573 } 18574 } 18575 } 18576 if($ExtraInfo) 18577 { # extra information for other tools 18578 if(my @Paths = sort keys(%UndefinedLibs)) 18579 { 18580 my $LibString = ""; 18581 my %Dirs = (); 18582 foreach (@Paths) 18583 { 18584 $KnownLibs{$_} = 1; 18585 my ($Dir, $Name) = separate_path($_); 18586 18587 if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) { 18588 $Dirs{esc($Dir)} = 1; 18589 } 18590 18591 $Name = parse_libname($Name, "name", $OStarget); 18592 $Name=~s/\Alib//; 18593 18594 $LibString .= " -l$Name"; 18595 } 18596 18597 foreach my $Dir (sort {$b cmp $a} keys(%Dirs)) 18598 { 18599 $LibString = " -L".esc($Dir).$LibString; 18600 } 18601 18602 writeFile($ExtraInfo."/libs-string", $LibString); 18603 } 18604 } 18605 } 18606 18607 if($ExtraInfo) { 18608 writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs))); 18609 } 18610 18611 if(not $CheckHeadersOnly) 18612 { 18613 if($#LibPaths!=-1) 18614 { 18615 if(not keys(%{$Symbol_Library{$LibVersion}})) 18616 { 18617 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)"); 18618 printMsg("WARNING", "checking headers only"); 18619 $CheckHeadersOnly = 1; 18620 } 18621 } 18622 } 18623 18624 # clean memory 18625 %SystemObjects = (); 18626} 18627 18628my %Prefix_Lib_Map=( 18629 # symbols for autodetecting library dependencies (by prefix) 18630 "pthread_" => ["libpthread"], 18631 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"], 18632 "cairo_" => ["libcairo"], 18633 "gtk_" => ["libgtk-x11-2.0"], 18634 "atk_" => ["libatk-1.0"], 18635 "gdk_" => ["libgdk-x11-2.0"], 18636 "gl" => ["libGL"], 18637 "glu" => ["libGLU"], 18638 "popt" => ["libpopt"], 18639 "Py" => ["libpython"], 18640 "jpeg_" => ["libjpeg"], 18641 "BZ2_" => ["libbz2"], 18642 "Fc" => ["libfontconfig"], 18643 "Xft" => ["libXft"], 18644 "SSL_" => ["libssl"], 18645 "sem_" => ["libpthread"], 18646 "snd_" => ["libasound"], 18647 "art_" => ["libart_lgpl_2"], 18648 "dbus_g" => ["libdbus-glib-1"], 18649 "GOMP_" => ["libgomp"], 18650 "omp_" => ["libgomp"], 18651 "cms" => ["liblcms"] 18652); 18653 18654my %Pattern_Lib_Map=( 18655 "SL[a-z]" => ["libslang"] 18656); 18657 18658my %Symbol_Lib_Map=( 18659 # symbols for autodetecting library dependencies (by name) 18660 "pow" => "libm", 18661 "fmod" => "libm", 18662 "sin" => "libm", 18663 "floor" => "libm", 18664 "cos" => "libm", 18665 "dlopen" => "libdl", 18666 "deflate" => "libz", 18667 "inflate" => "libz", 18668 "move_panel" => "libpanel", 18669 "XOpenDisplay" => "libX11", 18670 "resize_term" => "libncurses", 18671 "clock_gettime" => "librt", 18672 "crypt" => "libcrypt" 18673); 18674 18675sub find_SymbolLibs($$) 18676{ 18677 my ($LibVersion, $Symbol) = @_; 18678 18679 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/) 18680 { # debug symbols 18681 return (); 18682 } 18683 18684 my %Paths = (); 18685 18686 if(my $LibName = $Symbol_Lib_Map{$Symbol}) 18687 { 18688 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18689 $Paths{$Path} = 1; 18690 } 18691 } 18692 18693 if(my $SymbolPrefix = getPrefix($Symbol)) 18694 { 18695 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) { 18696 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}}; 18697 } 18698 18699 if(not keys(%Paths)) 18700 { 18701 if(defined $Prefix_Lib_Map{$SymbolPrefix}) 18702 { 18703 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}}) 18704 { 18705 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18706 $Paths{$Path} = 1; 18707 } 18708 } 18709 } 18710 } 18711 18712 if(not keys(%Paths)) 18713 { 18714 foreach my $Prefix (sort keys(%Pattern_Lib_Map)) 18715 { 18716 if($Symbol=~/\A$Prefix/) 18717 { 18718 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}}) 18719 { 18720 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18721 $Paths{$Path} = 1; 18722 } 18723 } 18724 } 18725 } 18726 } 18727 18728 if(not keys(%Paths)) 18729 { 18730 if($SymbolPrefix) 18731 { # try to find a library by symbol prefix 18732 if($SymbolPrefix eq "inotify" and 18733 index($Symbol, "\@GLIBC")!=-1) 18734 { 18735 if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) { 18736 $Paths{$Path} = 1; 18737 } 18738 } 18739 else 18740 { 18741 if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) { 18742 $Paths{$Path} = 1; 18743 } 18744 } 18745 } 18746 } 18747 18748 if(my @Paths = keys(%Paths)) { 18749 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths; 18750 } 18751 } 18752 return keys(%Paths); 18753} 18754 18755sub get_LibPath_Prefix($$) 18756{ 18757 my ($LibVersion, $Prefix) = @_; 18758 18759 $Prefix = lc($Prefix); 18760 $Prefix=~s/[_]+\Z//g; 18761 18762 foreach ("-2", "2", "-1", "1", "") 18763 { # libgnome-2.so 18764 # libxml2.so 18765 # libdbus-1.so 18766 if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) { 18767 return $Path; 18768 } 18769 } 18770 return ""; 18771} 18772 18773sub getPrefix($) 18774{ 18775 my $Str = $_[0]; 18776 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/) 18777 { # XmuValidArea: Xmu 18778 return $1; 18779 } 18780 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/) 18781 { # snfReadFont: snf 18782 return $1; 18783 } 18784 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/) 18785 { # XRRTimes: XRR 18786 return $1; 18787 } 18788 elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i) 18789 { # H5HF_delete: H5 18790 return $1; 18791 } 18792 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i) 18793 { # alarm_event_add: alarm_ 18794 return $1; 18795 } 18796 elsif($Str=~/\A(([a-z])\2{1,})/i) 18797 { # ffopen 18798 return $1; 18799 } 18800 return ""; 18801} 18802 18803sub getSymbolSize($$) 18804{ # size from the shared library 18805 my ($Symbol, $LibVersion) = @_; 18806 return 0 if(not $Symbol); 18807 if(defined $Symbol_Library{$LibVersion}{$Symbol} 18808 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol}) 18809 { 18810 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol} 18811 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol}) 18812 { 18813 if($Size<0) { 18814 return -$Size; 18815 } 18816 } 18817 } 18818 return 0; 18819} 18820 18821sub canonifyName($$) 18822{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*) 18823 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*) 18824 my ($Name, $Type) = @_; 18825 18826 # single 18827 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3) 18828 { 18829 my $P = $1; 18830 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g; 18831 } 18832 18833 # double 18834 if($Name=~/$DEFAULT_STD_PARMS/) 18835 { 18836 if($Type eq "S") 18837 { 18838 my ($ShortName, $FuncParams) = split_Signature($Name); 18839 18840 foreach my $FParam (separate_Params($FuncParams, 0, 0)) 18841 { 18842 if(index($FParam, "<")!=-1) 18843 { 18844 $FParam=~s/>([^<>]+)\Z/>/; # remove quals 18845 my $FParam_N = canonifyName($FParam, "T"); 18846 if($FParam_N ne $FParam) { 18847 $Name=~s/\Q$FParam\E/$FParam_N/g; 18848 } 18849 } 18850 } 18851 } 18852 elsif($Type eq "T") 18853 { 18854 my ($ShortTmpl, $TmplParams) = template_Base($Name); 18855 18856 my @TParams = separate_Params($TmplParams, 0, 0); 18857 if($#TParams>=1) 18858 { 18859 my $FParam = $TParams[0]; 18860 foreach my $Pos (1 .. $#TParams) 18861 { 18862 my $TParam = $TParams[$Pos]; 18863 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) { 18864 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g; 18865 } 18866 } 18867 } 18868 } 18869 } 18870 if($Type eq "S") { 18871 return formatName($Name, "S"); 18872 } 18873 return $Name; 18874} 18875 18876sub translateSymbols(@) 18877{ 18878 my $LibVersion = pop(@_); 18879 my (@MnglNames1, @MnglNames2, @UnmangledNames) = (); 18880 foreach my $Symbol (sort @_) 18881 { 18882 if(index($Symbol, "_Z")==0) 18883 { 18884 next if($tr_name{$Symbol}); 18885 $Symbol=~s/[\@\$]+(.*)\Z//; 18886 push(@MnglNames1, $Symbol); 18887 } 18888 elsif(index($Symbol, "?")==0) 18889 { 18890 push(@MnglNames2, $Symbol); 18891 } 18892 else 18893 { # not mangled 18894 $tr_name{$Symbol} = $Symbol; 18895 $mangled_name_gcc{$Symbol} = $Symbol; 18896 $mangled_name{$LibVersion}{$Symbol} = $Symbol; 18897 } 18898 } 18899 if($#MnglNames1 > -1) 18900 { # GCC names 18901 @UnmangledNames = reverse(unmangleArray(@MnglNames1)); 18902 foreach my $MnglName (@MnglNames1) 18903 { 18904 if(my $Unmangled = pop(@UnmangledNames)) 18905 { 18906 $tr_name{$MnglName} = canonifyName($Unmangled, "S"); 18907 if(not $mangled_name_gcc{$tr_name{$MnglName}}) { 18908 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName; 18909 } 18910 if(index($MnglName, "_ZTV")==0 18911 and $tr_name{$MnglName}=~/vtable for (.+)/) 18912 { # bind class name and v-table symbol 18913 my $ClassName = $1; 18914 $ClassVTable{$ClassName} = $MnglName; 18915 $VTableClass{$MnglName} = $ClassName; 18916 } 18917 } 18918 } 18919 } 18920 if($#MnglNames2 > -1) 18921 { # MSVC names 18922 @UnmangledNames = reverse(unmangleArray(@MnglNames2)); 18923 foreach my $MnglName (@MnglNames2) 18924 { 18925 if(my $Unmangled = pop(@UnmangledNames)) 18926 { 18927 $tr_name{$MnglName} = formatName($Unmangled, "S"); 18928 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName; 18929 } 18930 } 18931 } 18932 return \%tr_name; 18933} 18934 18935sub link_symbol($$$) 18936{ 18937 my ($Symbol, $RunWith, $Deps) = @_; 18938 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) { 18939 return 1; 18940 } 18941 if($Deps eq "+Deps") 18942 { # check the dependencies 18943 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) { 18944 return 1; 18945 } 18946 } 18947 return 0; 18948} 18949 18950sub link_symbol_internal($$$) 18951{ 18952 my ($Symbol, $RunWith, $Where) = @_; 18953 return 0 if(not $Where or not $Symbol); 18954 if($Where->{$RunWith}{$Symbol}) 18955 { # the exact match by symbol name 18956 return 1; 18957 } 18958 if(my $VSym = $SymVer{$RunWith}{$Symbol}) 18959 { # indirect symbol version, i.e. 18960 # foo_old and its symlink foo@v (or foo@@v) 18961 # foo_old may be in symtab table 18962 if($Where->{$RunWith}{$VSym}) { 18963 return 1; 18964 } 18965 } 18966 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol); 18967 if($Sym and $Ver) 18968 { # search for the symbol with the same version 18969 # or without version 18970 if($Where->{$RunWith}{$Sym}) 18971 { # old: foo@v|foo@@v 18972 # new: foo 18973 return 1; 18974 } 18975 if($Where->{$RunWith}{$Sym."\@".$Ver}) 18976 { # old: foo|foo@@v 18977 # new: foo@v 18978 return 1; 18979 } 18980 if($Where->{$RunWith}{$Sym."\@\@".$Ver}) 18981 { # old: foo|foo@v 18982 # new: foo@@v 18983 return 1; 18984 } 18985 } 18986 return 0; 18987} 18988 18989sub readSymbols_App($) 18990{ 18991 my $Path = $_[0]; 18992 return () if(not $Path); 18993 my @Imported = (); 18994 if($OStarget eq "macos") 18995 { 18996 my $NM = get_CmdPath("nm"); 18997 if(not $NM) { 18998 exitStatus("Not_Found", "can't find \"nm\""); 18999 } 19000 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |"); 19001 while(<APP>) 19002 { 19003 if(/ U _([\w\$]+)\s*\Z/) { 19004 push(@Imported, $1); 19005 } 19006 } 19007 close(APP); 19008 } 19009 elsif($OStarget eq "windows") 19010 { 19011 my $DumpBinCmd = get_CmdPath("dumpbin"); 19012 if(not $DumpBinCmd) { 19013 exitStatus("Not_Found", "can't find \"dumpbin.exe\""); 19014 } 19015 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |"); 19016 while(<APP>) 19017 { 19018 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) { 19019 push(@Imported, $1); 19020 } 19021 } 19022 close(APP); 19023 } 19024 else 19025 { 19026 my $ReadelfCmd = get_CmdPath("readelf"); 19027 if(not $ReadelfCmd) { 19028 exitStatus("Not_Found", "can't find \"readelf\""); 19029 } 19030 open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |"); 19031 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 19032 while(<APP>) 19033 { 19034 if(defined $symtab) 19035 { # do nothing with symtab 19036 if(index($_, "'.dynsym'")!=-1) 19037 { # dynamic table 19038 $symtab = undef; 19039 } 19040 } 19041 elsif(index($_, "'.symtab'")!=-1) 19042 { # symbol table 19043 $symtab = 1; 19044 } 19045 elsif(my @Info = readline_ELF($_)) 19046 { 19047 my ($Ndx, $Symbol) = ($Info[5], $Info[6]); 19048 if($Ndx eq "UND") 19049 { # only imported symbols 19050 push(@Imported, $Symbol); 19051 } 19052 } 19053 } 19054 close(APP); 19055 } 19056 return @Imported; 19057} 19058 19059my %ELF_BIND = map {$_=>1} ( 19060 "WEAK", 19061 "GLOBAL" 19062); 19063 19064my %ELF_TYPE = map {$_=>1} ( 19065 "FUNC", 19066 "IFUNC", 19067 "OBJECT", 19068 "COMMON" 19069); 19070 19071my %ELF_VIS = map {$_=>1} ( 19072 "DEFAULT", 19073 "PROTECTED" 19074); 19075 19076sub readline_ELF($) 19077{ # read the line of 'readelf' output corresponding to the symbol 19078 my @Info = split(/\s+/, $_[0]); 19079 # Num: Value Size Type Bind Vis Ndx Name 19080 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4 19081 # 135: 00000000 0 FUNC GLOBAL DEFAULT UND av_image_fill_pointers@LIBAVUTIL_52 (3) 19082 shift(@Info); # spaces 19083 shift(@Info); # num 19084 19085 if($#Info==7) 19086 { # UND SYMBOL (N) 19087 if($Info[7]=~/\(\d+\)/) { 19088 pop(@Info); 19089 } 19090 } 19091 19092 if($#Info!=6) 19093 { # other lines 19094 return (); 19095 } 19096 return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND"); 19097 return () if(not defined $ELF_BIND{$Info[3]}); 19098 return () if(not defined $ELF_VIS{$Info[4]}); 19099 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/) 19100 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3 19101 return (); 19102 } 19103 if($OStarget eq "symbian") 19104 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll 19105 if(index($Info[6], "_._.absent_export_")!=-1) 19106 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll 19107 return (); 19108 } 19109 $Info[6]=~s/\@.+//g; # remove version 19110 } 19111 if(index($Info[2], "0x") == 0) 19112 { # size == 0x3d158 19113 $Info[2] = hex($Info[2]); 19114 } 19115 return @Info; 19116} 19117 19118sub get_LibPath($$) 19119{ 19120 my ($LibVersion, $Name) = @_; 19121 return "" if(not $LibVersion or not $Name); 19122 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) { 19123 return $Cache{"get_LibPath"}{$LibVersion}{$Name}; 19124 } 19125 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name)); 19126} 19127 19128sub get_LibPath_I($$) 19129{ 19130 my ($LibVersion, $Name) = @_; 19131 if(is_abs($Name)) 19132 { 19133 if(-f $Name) 19134 { # absolute path 19135 return $Name; 19136 } 19137 else 19138 { # broken 19139 return ""; 19140 } 19141 } 19142 if(defined $RegisteredObjects{$LibVersion}{$Name}) 19143 { # registered paths 19144 return $RegisteredObjects{$LibVersion}{$Name}; 19145 } 19146 if(defined $RegisteredSONAMEs{$LibVersion}{$Name}) 19147 { # registered paths 19148 return $RegisteredSONAMEs{$LibVersion}{$Name}; 19149 } 19150 if(my $DefaultPath = $DyLib_DefaultPath{$Name}) 19151 { # ldconfig default paths 19152 return $DefaultPath; 19153 } 19154 foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}}) 19155 { # search in default linker directories 19156 # and then in all system paths 19157 if(-f $Dir."/".$Name) { 19158 return join_P($Dir,$Name); 19159 } 19160 } 19161 if(not defined $Cache{"checkSystemFiles"}) { 19162 checkSystemFiles(); 19163 } 19164 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) { 19165 return $AllObjects[0]; 19166 } 19167 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget)) 19168 { 19169 if($ShortName ne $Name) 19170 { # FIXME: check this case 19171 if(my $Path = get_LibPath($LibVersion, $ShortName)) { 19172 return $Path; 19173 } 19174 } 19175 } 19176 # can't find 19177 return ""; 19178} 19179 19180sub readSymbols_Lib($$$$$$) 19181{ 19182 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; 19183 return () if(not $LibVersion or not $Lib_Path); 19184 19185 my $Real_Path = realpath_F($Lib_Path); 19186 19187 if(not $Real_Path) 19188 { # broken link 19189 return (); 19190 } 19191 19192 my $Lib_Name = get_filename($Real_Path); 19193 19194 if($ExtraInfo) 19195 { 19196 $KnownLibs{$Real_Path} = 1; 19197 $KnownLibs{$Lib_Path} = 1; # links 19198 } 19199 19200 if($IsNeededLib) 19201 { 19202 if($CheckedDyLib{$LibVersion}{$Lib_Name}) { 19203 return (); 19204 } 19205 } 19206 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1); 19207 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1; 19208 19209 push(@RecurLib, $Lib_Name); 19210 my (%Value_Interface, %Interface_Value, %NeededLib) = (); 19211 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget); 19212 19213 if(not $IsNeededLib) 19214 { # special cases: libstdc++ and libc 19215 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget)) 19216 { 19217 if($ShortName eq "libstdc++") 19218 { # libstdc++.so.6 19219 $STDCXX_TESTING = 1; 19220 } 19221 elsif($ShortName eq "libc") 19222 { # libc-2.11.3.so 19223 $GLIBC_TESTING = 1; 19224 } 19225 } 19226 } 19227 my $DebugPath = ""; 19228 if($Debug and not $DumpSystem) 19229 { # debug mode 19230 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt"; 19231 mkpath(get_dirname($DebugPath)); 19232 } 19233 if($OStarget eq "macos") 19234 { # Mac OS X: *.dylib, *.a 19235 my $NM = get_CmdPath("nm"); 19236 if(not $NM) { 19237 exitStatus("Not_Found", "can't find \"nm\""); 19238 } 19239 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19240 if($DebugPath) 19241 { # debug mode 19242 # write to file 19243 system($NM." >\"$DebugPath\""); 19244 open(LIB, $DebugPath); 19245 } 19246 else 19247 { # write to pipe 19248 open(LIB, $NM." |"); 19249 } 19250 while(<LIB>) 19251 { 19252 if($CheckUndefined) 19253 { 19254 if(not $IsNeededLib) 19255 { 19256 if(/ U _([\w\$]+)\s*\Z/) 19257 { 19258 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0; 19259 next; 19260 } 19261 } 19262 } 19263 19264 if(/ [STD] _([\w\$]+)\s*\Z/) 19265 { 19266 my $Symbol = $1; 19267 if($IsNeededLib) 19268 { 19269 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19270 { 19271 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19272 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 19273 } 19274 } 19275 else 19276 { 19277 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19278 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 19279 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19280 { 19281 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 19282 setLanguage($LibVersion, "C++"); 19283 } 19284 } 19285 } 19286 } 19287 } 19288 close(LIB); 19289 19290 if($Deps) 19291 { 19292 if($LIB_TYPE eq "dynamic") 19293 { # dependencies 19294 19295 my $OtoolCmd = get_CmdPath("otool"); 19296 if(not $OtoolCmd) { 19297 exitStatus("Not_Found", "can't find \"otool\""); 19298 } 19299 19300 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 19301 while(<LIB>) 19302 { 19303 if(/\s*([\/\\].+\.$LIB_EXT)\s*/ 19304 and $1 ne $Lib_Path) { 19305 $NeededLib{$1} = 1; 19306 } 19307 } 19308 close(LIB); 19309 } 19310 } 19311 } 19312 elsif($OStarget eq "windows") 19313 { # Windows *.dll, *.lib 19314 my $DumpBinCmd = get_CmdPath("dumpbin"); 19315 if(not $DumpBinCmd) { 19316 exitStatus("Not_Found", "can't find \"dumpbin\""); 19317 } 19318 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null"; 19319 if($DebugPath) 19320 { # debug mode 19321 # write to file 19322 system($DumpBinCmd." >\"$DebugPath\""); 19323 open(LIB, $DebugPath); 19324 } 19325 else 19326 { # write to pipe 19327 open(LIB, $DumpBinCmd." |"); 19328 } 19329 while(<LIB>) 19330 { 19331 my $realname = undef; 19332 if($LIB_TYPE eq "dynamic") 19333 { 19334 # 1197 4AC 0000A620 SetThreadStackGuarantee 19335 # 1198 4AD SetThreadToken (forwarded to ...) 19336 # 3368 _o2i_ECPublicKey 19337 # 1 0 00005B30 ??0?N = ... (with pdb) 19338 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i 19339 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ 19340 or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) 19341 { # dynamic, static and forwarded symbols 19342 $realname = $1; 19343 } 19344 } 19345 else 19346 { # static 19347 if(/\A\s{10,}\d*\s+([\w\?\@]+)\s*\Z/i) 19348 { 19349 # 16 IID_ISecurityInformation 19350 $realname = $1; 19351 } 19352 } 19353 19354 if($realname) 19355 { 19356 if($IsNeededLib) 19357 { 19358 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19359 { 19360 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name; 19361 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 19362 } 19363 } 19364 else 19365 { 19366 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name; 19367 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 19368 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19369 { 19370 if(index($realname, "_Z")==0 or index($realname, "?")==0) { 19371 setLanguage($LibVersion, "C++"); 19372 } 19373 } 19374 } 19375 } 19376 } 19377 close(LIB); 19378 19379 if($Deps) 19380 { 19381 if($LIB_TYPE eq "dynamic") 19382 { # dependencies 19383 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 19384 while(<LIB>) 19385 { 19386 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i 19387 and $1 ne $Lib_Path) { 19388 $NeededLib{path_format($1, $OSgroup)} = 1; 19389 } 19390 } 19391 close(LIB); 19392 } 19393 } 19394 } 19395 else 19396 { # Unix; *.so, *.a 19397 # Symbian: *.dso, *.lib 19398 my $ReadelfCmd = get_CmdPath("readelf"); 19399 if(not $ReadelfCmd) { 19400 exitStatus("Not_Found", "can't find \"readelf\""); 19401 } 19402 my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19403 if($DebugPath) 19404 { # debug mode 19405 # write to file 19406 system($Cmd." >\"$DebugPath\""); 19407 open(LIB, $DebugPath); 19408 } 19409 else 19410 { # write to pipe 19411 open(LIB, $Cmd." |"); 19412 } 19413 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 19414 while(<LIB>) 19415 { 19416 if($LIB_TYPE eq "dynamic") 19417 { # dynamic library specifics 19418 if(defined $symtab) 19419 { 19420 if(index($_, "'.dynsym'")!=-1) 19421 { # dynamic table 19422 $symtab = undef; 19423 } 19424 # do nothing with symtab 19425 next; 19426 } 19427 elsif(index($_, "'.symtab'")!=-1) 19428 { # symbol table 19429 $symtab = 1; 19430 next; 19431 } 19432 } 19433 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_)) 19434 { # read ELF entry 19435 if($Ndx eq "UND") 19436 { # ignore interfaces that are imported from somewhere else 19437 if($CheckUndefined) 19438 { 19439 if(not $IsNeededLib) { 19440 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0; 19441 } 19442 } 19443 next; 19444 } 19445 if($Bind eq "WEAK") 19446 { 19447 $WeakSymbols{$LibVersion}{$Symbol} = 1; 19448 if($Weak eq "-Weak") 19449 { # skip WEAK symbols 19450 next; 19451 } 19452 } 19453 my $Short = $Symbol; 19454 $Short=~s/\@.+//g; 19455 if($Type eq "OBJECT") 19456 { # global data 19457 $GlobalDataObject{$LibVersion}{$Symbol} = $Size; 19458 $GlobalDataObject{$LibVersion}{$Short} = $Size; 19459 } 19460 if($IsNeededLib) 19461 { 19462 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19463 { 19464 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19465 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19466 } 19467 } 19468 else 19469 { 19470 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19471 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19472 if($Vers) 19473 { 19474 if($LIB_EXT eq "so") 19475 { # value 19476 $Interface_Value{$LibVersion}{$Symbol} = $Value; 19477 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1; 19478 } 19479 } 19480 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19481 { 19482 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 19483 setLanguage($LibVersion, "C++"); 19484 } 19485 } 19486 } 19487 } 19488 } 19489 close(LIB); 19490 19491 if($Deps and $LIB_TYPE eq "dynamic") 19492 { # dynamic library specifics 19493 $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19494 open(LIB, $Cmd." |"); 19495 19496 while(<LIB>) 19497 { 19498 if(/NEEDED.+\[([^\[\]]+)\]/) 19499 { # dependencies: 19500 # 0x00000001 (NEEDED) Shared library: [libc.so.6] 19501 $NeededLib{$1} = 1; 19502 } 19503 } 19504 19505 close(LIB); 19506 } 19507 } 19508 if($Vers) 19509 { 19510 if(not $IsNeededLib and $LIB_EXT eq "so") 19511 { # get symbol versions 19512 my %Found = (); 19513 19514 # by value 19515 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19516 { 19517 next if(index($Symbol,"\@")==-1); 19518 if(my $Value = $Interface_Value{$LibVersion}{$Symbol}) 19519 { 19520 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}})) 19521 { 19522 if($Symbol_SameValue ne $Symbol 19523 and index($Symbol_SameValue,"\@")==-1) 19524 { 19525 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol; 19526 $Found{$Symbol} = 1; 19527 last; 19528 } 19529 } 19530 } 19531 } 19532 19533 # default 19534 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19535 { 19536 next if(defined $Found{$Symbol}); 19537 next if(index($Symbol,"\@\@")==-1); 19538 19539 if($Symbol=~/\A([^\@]*)\@\@/ 19540 and not $SymVer{$LibVersion}{$1}) 19541 { 19542 $SymVer{$LibVersion}{$1} = $Symbol; 19543 $Found{$Symbol} = 1; 19544 } 19545 } 19546 19547 # non-default 19548 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19549 { 19550 next if(defined $Found{$Symbol}); 19551 next if(index($Symbol,"\@")==-1); 19552 19553 if($Symbol=~/\A([^\@]*)\@([^\@]*)/ 19554 and not $SymVer{$LibVersion}{$1}) 19555 { 19556 $SymVer{$LibVersion}{$1} = $Symbol; 19557 $Found{$Symbol} = 1; 19558 } 19559 } 19560 } 19561 } 19562 if($Deps) 19563 { 19564 foreach my $DyLib (sort keys(%NeededLib)) 19565 { 19566 $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1; 19567 19568 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) 19569 { 19570 if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) { 19571 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers); 19572 } 19573 } 19574 } 19575 } 19576 pop(@RecurLib); 19577 return $Library_Symbol{$LibVersion}; 19578} 19579 19580sub get_prefixes($) 19581{ 19582 my %Prefixes = (); 19583 get_prefixes_I([$_[0]], \%Prefixes); 19584 return keys(%Prefixes); 19585} 19586 19587sub get_prefixes_I($$) 19588{ 19589 foreach my $P (@{$_[0]}) 19590 { 19591 my @Parts = reverse(split(/[\/\\]+/, $P)); 19592 my $Name = $Parts[0]; 19593 foreach (1 .. $#Parts) 19594 { 19595 $_[1]->{$Name}{$P} = 1; 19596 last if($_>4 or $Parts[$_] eq "include"); 19597 $Name = $Parts[$_].$SLASH.$Name; 19598 } 19599 } 19600} 19601 19602sub checkSystemFiles() 19603{ 19604 $Cache{"checkSystemFiles"} = 1; 19605 19606 my @SysHeaders = (); 19607 19608 foreach my $DevelPath (@{$SystemPaths{"lib"}}) 19609 { 19610 next if(not -d $DevelPath); 19611 19612 my @Files = cmd_find($DevelPath,"f"); 19613 foreach my $Link (cmd_find($DevelPath,"l")) 19614 { # add symbolic links 19615 if(-f $Link) { 19616 push(@Files, $Link); 19617 } 19618 } 19619 19620 # search for headers in /usr/lib 19621 my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; 19622 @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; 19623 push(@SysHeaders, @Headers); 19624 19625 # search for libraries in /usr/lib (including symbolic links) 19626 my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files; 19627 foreach my $Path (@Libs) 19628 { 19629 my $N = get_filename($Path); 19630 $SystemObjects{$N}{$Path} = 1; 19631 $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1; 19632 } 19633 } 19634 19635 foreach my $DevelPath (@{$SystemPaths{"include"}}) 19636 { 19637 next if(not -d $DevelPath); 19638 # search for all header files in the /usr/include 19639 # with or without extension (ncurses.h, QtCore, ...) 19640 push(@SysHeaders, cmd_find($DevelPath,"f")); 19641 foreach my $Link (cmd_find($DevelPath,"l")) 19642 { # add symbolic links 19643 if(-f $Link) { 19644 push(@SysHeaders, $Link); 19645 } 19646 } 19647 } 19648 get_prefixes_I(\@SysHeaders, \%SystemHeaders); 19649} 19650 19651sub getSOPaths($) 19652{ 19653 my $LibVersion = $_[0]; 19654 my @Paths = (); 19655 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"})) 19656 { 19657 if(not -e $Dest) { 19658 exitStatus("Access_Error", "can't access \'$Dest\'"); 19659 } 19660 $Dest = get_abs_path($Dest); 19661 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion); 19662 foreach (@SoPaths_Dest) { 19663 push(@Paths, $_); 19664 } 19665 } 19666 return sort @Paths; 19667} 19668 19669sub skipLib($$) 19670{ 19671 my ($Path, $LibVersion) = @_; 19672 return 1 if(not $Path or not $LibVersion); 19673 my $Name = get_filename($Path); 19674 if($SkipLibs{$LibVersion}{"Name"}{$Name}) { 19675 return 1; 19676 } 19677 my $ShortName = parse_libname($Name, "name+ext", $OStarget); 19678 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) { 19679 return 1; 19680 } 19681 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}})) 19682 { 19683 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) { 19684 return 1; 19685 } 19686 } 19687 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}})) 19688 { 19689 if($Name=~/$P/) { 19690 return 1; 19691 } 19692 if($P=~/[\/\\]/ and $Path=~/$P/) { 19693 return 1; 19694 } 19695 } 19696 return 0; 19697} 19698 19699sub specificHeader($$) 19700{ 19701 my ($Header, $Spec) = @_; 19702 my $Name = get_filename($Header); 19703 19704 if($Spec eq "windows") 19705 {# MS Windows 19706 return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i); 19707 return 1 if($Name=~/([._-]w|win)(32|64)/i); 19708 return 1 if($Name=~/\A(Win|Windows)[A-Z]/); 19709 return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i); 19710 my @Dirs = ( 19711 "win32", 19712 "win64", 19713 "win", 19714 "windows", 19715 "msvcrt" 19716 ); # /gsf-win32/ 19717 if(my $DIRs = join("|", @Dirs)) { 19718 return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19719 } 19720 } 19721 elsif($Spec eq "macos") 19722 { # Mac OS 19723 return 1 if($Name=~/(\A|[_-])mac[._-]/i); 19724 } 19725 19726 return 0; 19727} 19728 19729sub skipAlienHeader($) 19730{ 19731 my $Path = $_[0]; 19732 my $Name = get_filename($Path); 19733 my $Dir = get_dirname($Path); 19734 19735 if($Tolerance=~/2/) 19736 { # 2 - skip internal headers 19737 my @Terms = ( 19738 "p", 19739 "priv", 19740 "int", 19741 "impl", 19742 "implementation", 19743 "internal", 19744 "private", 19745 "old", 19746 "compat", 19747 "debug", 19748 "test", 19749 "gen" 19750 ); 19751 19752 my @Dirs = ( 19753 "private", 19754 "priv", 19755 "port", 19756 "impl", 19757 "internal", 19758 "detail", 19759 "details", 19760 "old", 19761 "compat", 19762 "debug", 19763 "config", 19764 "compiler", 19765 "platform", 19766 "test" 19767 ); 19768 19769 if(my $TERMs = join("|", @Terms)) { 19770 return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i); 19771 } 19772 if(my $DIRs = join("|", @Dirs)) { 19773 return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19774 } 19775 19776 return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/); 19777 } 19778 19779 if($Tolerance=~/1/) 19780 { # 1 - skip non-Linux headers 19781 if($OSgroup ne "windows") 19782 { 19783 if(specificHeader($Path, "windows")) { 19784 return 1; 19785 } 19786 } 19787 if($OSgroup ne "macos") 19788 { 19789 if(specificHeader($Path, "macos")) { 19790 return 1; 19791 } 19792 } 19793 } 19794 19795 # valid 19796 return 0; 19797} 19798 19799sub skipHeader($$) 19800{ 19801 my ($Path, $LibVersion) = @_; 19802 return 1 if(not $Path or not $LibVersion); 19803 if(defined $Cache{"skipHeader"}{$Path}) { 19804 return $Cache{"skipHeader"}{$Path}; 19805 } 19806 if(defined $Tolerance and $Tolerance=~/1|2/) 19807 { # --tolerant 19808 if(skipAlienHeader($Path)) { 19809 return ($Cache{"skipHeader"}{$Path} = 1); 19810 } 19811 } 19812 if(not keys(%{$SkipHeaders{$LibVersion}})) { 19813 return 0; 19814 } 19815 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_)); 19816} 19817 19818sub skipHeader_I($$) 19819{ # returns: 19820 # 1 - if header should NOT be included and checked 19821 # 2 - if header should NOT be included, but should be checked 19822 my ($Path, $LibVersion) = @_; 19823 my $Name = get_filename($Path); 19824 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) { 19825 return $Kind; 19826 } 19827 foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}} 19828 keys(%{$SkipHeaders{$LibVersion}{"Path"}})) 19829 { 19830 if(index($Path, $D)!=-1) 19831 { 19832 if($Path=~/\Q$D\E([\/\\]|\Z)/) { 19833 return $SkipHeaders{$LibVersion}{"Path"}{$D}; 19834 } 19835 } 19836 } 19837 foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}} 19838 keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) 19839 { 19840 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P}) 19841 { 19842 if($Name=~/$P/) { 19843 return $Kind; 19844 } 19845 if($P=~/[\/\\]/ and $Path=~/$P/) { 19846 return $Kind; 19847 } 19848 } 19849 } 19850 19851 return 0; 19852} 19853 19854sub registerObject_Dir($$) 19855{ 19856 my ($Dir, $LibVersion) = @_; 19857 if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}}) 19858 { # system directory 19859 return; 19860 } 19861 if($RegisteredObject_Dirs{$LibVersion}{$Dir}) 19862 { # already registered 19863 return; 19864 } 19865 foreach my $Path (find_libs($Dir,"",1)) 19866 { 19867 next if(ignore_path($Path)); 19868 next if(skipLib($Path, $LibVersion)); 19869 registerObject($Path, $LibVersion); 19870 } 19871 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1; 19872} 19873 19874sub registerObject($$) 19875{ 19876 my ($Path, $LibVersion) = @_; 19877 19878 my $Name = get_filename($Path); 19879 $RegisteredObjects{$LibVersion}{$Name} = $Path; 19880 if($OStarget=~/linux|bsd|gnu|solaris/i) 19881 { 19882 if(my $SONAME = getSONAME($Path)) { 19883 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path; 19884 } 19885 } 19886 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) { 19887 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path; 19888 } 19889 19890 if(not $CheckedArch{$LibVersion} and -f $Path) 19891 { 19892 if(my $ObjArch = getArch_Object($Path)) 19893 { 19894 if($ObjArch ne getArch_GCC($LibVersion)) 19895 { # translation unit dump generated by the GCC compiler should correspond to the input objects 19896 $CheckedArch{$LibVersion} = 1; 19897 printMsg("WARNING", "the architectures of input objects and the used GCC compiler are not equal, please change the compiler by --gcc-path=PATH option."); 19898 } 19899 } 19900 } 19901} 19902 19903sub getArch_Object($) 19904{ 19905 my $Path = $_[0]; 19906 19907 my %MachineType = ( 19908 "14C" => "x86", 19909 "8664" => "x86_64", 19910 "1C0" => "arm", 19911 "200" => "ia64" 19912 ); 19913 19914 my %ArchName = ( 19915 "s390:31-bit" => "s390", 19916 "s390:64-bit" => "s390x", 19917 "powerpc:common" => "ppc32", 19918 "powerpc:common64" => "ppc64", 19919 "i386:x86-64" => "x86_64", 19920 "mips:3000" => "mips", 19921 "sparc:v8plus" => "sparcv9" 19922 ); 19923 19924 if($OStarget eq "windows") 19925 { 19926 my $DumpbinCmd = get_CmdPath("dumpbin"); 19927 if(not $DumpbinCmd) { 19928 exitStatus("Not_Found", "can't find \"dumpbin\""); 19929 } 19930 19931 my $Cmd = $DumpbinCmd." /headers \"$Path\""; 19932 my $Out = `$Cmd`; 19933 19934 if($Out=~/(\w+)\smachine/) 19935 { 19936 if(my $Type = $MachineType{uc($1)}) 19937 { 19938 return $Type; 19939 } 19940 } 19941 } 19942 elsif($OStarget=~/macos/) 19943 { 19944 my $OtoolCmd = get_CmdPath("otool"); 19945 if(not $OtoolCmd) { 19946 exitStatus("Not_Found", "can't find \"otool\""); 19947 } 19948 19949 my $Cmd = $OtoolCmd." -hv -arch all \"$Path\""; 19950 my $Out = qx/$Cmd/; 19951 19952 if($Out=~/X86_64/i) { 19953 return "x86_64"; 19954 } 19955 elsif($Out=~/X86/i) { 19956 return "x86"; 19957 } 19958 } 19959 else 19960 { # linux, bsd, gnu, solaris, ... 19961 my $ObjdumpCmd = get_CmdPath("objdump"); 19962 if(not $ObjdumpCmd) { 19963 exitStatus("Not_Found", "can't find \"objdump\""); 19964 } 19965 19966 my $Cmd = $ObjdumpCmd." -f \"$Path\""; 19967 19968 if($OSgroup eq "windows") { 19969 $Cmd = "set LANG=$LOCALE & ".$Cmd; 19970 } 19971 else { 19972 $Cmd = "LANG=$LOCALE ".$Cmd; 19973 } 19974 my $Out = `$Cmd`; 19975 19976 if($Out=~/architecture:\s+([\w\-\:]+)/) 19977 { 19978 my $Arch = $1; 19979 if($Arch=~s/\:(.+)//) 19980 { 19981 my $Suffix = $1; 19982 19983 if(my $Name = $ArchName{$Arch.":".$Suffix}) 19984 { 19985 $Arch = $Name; 19986 } 19987 } 19988 19989 if($Arch=~/i[3-6]86/) { 19990 $Arch = "x86"; 19991 } 19992 19993 if($Arch eq "x86-64") { 19994 $Arch = "x86_64"; 19995 } 19996 19997 if($Arch eq "ia64-elf64") { 19998 $Arch = "ia64"; 19999 } 20000 20001 return $Arch; 20002 } 20003 } 20004 20005 return undef; 20006} 20007 20008sub getSONAME($) 20009{ 20010 my $Path = $_[0]; 20011 return if(not $Path); 20012 if(defined $Cache{"getSONAME"}{$Path}) { 20013 return $Cache{"getSONAME"}{$Path}; 20014 } 20015 my $ObjdumpCmd = get_CmdPath("objdump"); 20016 if(not $ObjdumpCmd) { 20017 exitStatus("Not_Found", "can't find \"objdump\""); 20018 } 20019 my $SonameCmd = "$ObjdumpCmd -x \"$Path\" 2>$TMP_DIR/null"; 20020 if($OSgroup eq "windows") { 20021 $SonameCmd .= " | find \"SONAME\""; 20022 } 20023 else { 20024 $SonameCmd .= " | grep SONAME"; 20025 } 20026 if(my $SonameInfo = `$SonameCmd`) 20027 { 20028 if($SonameInfo=~/SONAME\s+([^\s]+)/) { 20029 return ($Cache{"getSONAME"}{$Path} = $1); 20030 } 20031 } 20032 return ($Cache{"getSONAME"}{$Path}=""); 20033} 20034 20035sub getSOPaths_Dest($$) 20036{ 20037 my ($Dest, $LibVersion) = @_; 20038 if(skipLib($Dest, $LibVersion)) { 20039 return (); 20040 } 20041 if(-f $Dest) 20042 { 20043 if(not parse_libname($Dest, "name", $OStarget)) { 20044 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'"); 20045 } 20046 registerObject($Dest, $LibVersion); 20047 registerObject_Dir(get_dirname($Dest), $LibVersion); 20048 return ($Dest); 20049 } 20050 elsif(-d $Dest) 20051 { 20052 $Dest=~s/[\/\\]+\Z//g; 20053 my %Libs = (); 20054 if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}}) 20055 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor 20056 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...) 20057 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2)) 20058 { # all files and symlinks that match the name of a library 20059 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i) 20060 { 20061 registerObject($Path, $LibVersion); 20062 $Libs{realpath_F($Path)} = 1; 20063 } 20064 } 20065 } 20066 else 20067 { # search for all files and symlinks 20068 foreach my $Path (find_libs($Dest,"","")) 20069 { 20070 next if(ignore_path($Path)); 20071 next if(skipLib($Path, $LibVersion)); 20072 registerObject($Path, $LibVersion); 20073 $Libs{realpath_F($Path)} = 1; 20074 } 20075 if($OSgroup eq "macos") 20076 { # shared libraries on MacOS X may have no extension 20077 foreach my $Path (cmd_find($Dest,"f")) 20078 { 20079 next if(ignore_path($Path)); 20080 next if(skipLib($Path, $LibVersion)); 20081 if(get_filename($Path)!~/\./ 20082 and cmd_file($Path)=~/(shared|dynamic)\s+library/i) 20083 { 20084 registerObject($Path, $LibVersion); 20085 $Libs{realpath_F($Path)} = 1; 20086 } 20087 } 20088 } 20089 } 20090 return keys(%Libs); 20091 } 20092 else { 20093 return (); 20094 } 20095} 20096 20097sub realpath_F($) 20098{ 20099 my $Path = $_[0]; 20100 return path_format(realpath($Path), $OSgroup); 20101} 20102 20103sub isCyclical($$) 20104{ 20105 my ($Stack, $Value) = @_; 20106 return (grep {$_ eq $Value} @{$Stack}); 20107} 20108 20109sub getGCC_Opts($) 20110{ # to use in module 20111 my $LibVersion = $_[0]; 20112 20113 my @Opts = (); 20114 20115 if($CompilerOptions{$LibVersion}) 20116 { # user-defined options 20117 push(@Opts, $CompilerOptions{$LibVersion}); 20118 } 20119 if($GccOptions) 20120 { # additional 20121 push(@Opts, $GccOptions); 20122 } 20123 20124 if(@Opts) { 20125 return join(" ", @Opts); 20126 } 20127 20128 return undef; 20129} 20130 20131sub getArch_GCC($) 20132{ 20133 my $LibVersion = $_[0]; 20134 20135 if(defined $Cache{"getArch_GCC"}{$LibVersion}) { 20136 return $Cache{"getArch_GCC"}{$LibVersion}; 20137 } 20138 20139 if(not $GCC_PATH) { 20140 return undef; 20141 } 20142 20143 my $Arch = undef; 20144 20145 if(my $Target = get_dumpmachine($GCC_PATH)) 20146 { 20147 if($Target=~/x86_64/) { 20148 $Arch = "x86_64"; 20149 } 20150 elsif($Target=~/i[3-6]86/) { 20151 $Arch = "x86"; 20152 } 20153 elsif($Target=~/\Aarm/i) { 20154 $Arch = "arm"; 20155 } 20156 } 20157 20158 if(not $Arch) 20159 { 20160 writeFile("$TMP_DIR/test.c", "int main(){return 0;}\n"); 20161 20162 my $Cmd = $GCC_PATH." test.c -o test"; 20163 if(my $Opts = getGCC_Opts($LibVersion)) 20164 { # user-defined options 20165 $Cmd .= " ".$Opts; 20166 } 20167 20168 chdir($TMP_DIR); 20169 system($Cmd); 20170 chdir($ORIG_DIR); 20171 20172 my $EX = join_P($TMP_DIR, "test"); 20173 20174 if($OSgroup eq "windows") { 20175 $EX = join_P($TMP_DIR, "test.exe"); 20176 } 20177 20178 $Arch = getArch_Object($EX); 20179 20180 unlink("$TMP_DIR/test.c"); 20181 unlink($EX); 20182 } 20183 20184 if(not $Arch) { 20185 exitStatus("Error", "can't check ARCH type"); 20186 } 20187 20188 return ($Cache{"getArch_GCC"}{$LibVersion} = $Arch); 20189} 20190 20191sub detectWordSize($) 20192{ 20193 my $LibVersion = $_[0]; 20194 20195 my $Size = undef; 20196 20197 # speed up detection 20198 if(my $Arch = getArch($LibVersion)) 20199 { 20200 if($Arch=~/\A(x86_64|s390x|ppc64|ia64|alpha)\Z/) { 20201 $Size = "8"; 20202 } 20203 elsif($Arch=~/\A(x86|s390|ppc32)\Z/) { 20204 $Size = "4"; 20205 } 20206 } 20207 20208 if($GCC_PATH) 20209 { 20210 writeFile("$TMP_DIR/empty.h", ""); 20211 20212 my $Cmd = $GCC_PATH." -E -dD empty.h"; 20213 if(my $Opts = getGCC_Opts($LibVersion)) 20214 { # user-defined options 20215 $Cmd .= " ".$Opts; 20216 } 20217 20218 chdir($TMP_DIR); 20219 my $Defines = `$Cmd`; 20220 chdir($ORIG_DIR); 20221 20222 unlink("$TMP_DIR/empty.h"); 20223 20224 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/) 20225 { # GCC 4 20226 $Size = $1; 20227 } 20228 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/) 20229 { # GCC 3 20230 my $PTRDIFF = $1; 20231 if($PTRDIFF=~/long/) { 20232 $Size = "8"; 20233 } 20234 else { 20235 $Size = "4"; 20236 } 20237 } 20238 } 20239 20240 if(not $Size) { 20241 exitStatus("Error", "can't check WORD size"); 20242 } 20243 20244 return $Size; 20245} 20246 20247sub getWordSize($) 20248{ # to use in module 20249 return $WORD_SIZE{$_[0]}; 20250} 20251 20252sub majorVersion($) 20253{ 20254 my $V = $_[0]; 20255 return 0 if(not $V); 20256 my @VParts = split(/\./, $V); 20257 return $VParts[0]; 20258} 20259 20260sub cmpVersions($$) 20261{ # compare two versions in dotted-numeric format 20262 my ($V1, $V2) = @_; 20263 return 0 if($V1 eq $V2); 20264 my @V1Parts = split(/\./, $V1); 20265 my @V2Parts = split(/\./, $V2); 20266 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) 20267 { 20268 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); 20269 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); 20270 } 20271 return -1 if($#V1Parts < $#V2Parts); 20272 return 1 if($#V1Parts > $#V2Parts); 20273 return 0; 20274} 20275 20276sub read_ABI_Dump($$) 20277{ 20278 my ($LibVersion, $Path) = @_; 20279 return if(not $LibVersion or not -e $Path); 20280 my $FilePath = ""; 20281 if(isDump_U($Path)) 20282 { # input *.abi 20283 $FilePath = $Path; 20284 } 20285 else 20286 { # input *.abi.tar.gz 20287 $FilePath = unpackDump($Path); 20288 if(not isDump_U($FilePath)) { 20289 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 20290 } 20291 } 20292 20293 my $ABI = {}; 20294 20295 my $Line = readLineNum($FilePath, 0); 20296 if($Line=~/xml/) 20297 { # XML format 20298 loadModule("XmlDump"); 20299 $ABI = readXmlDump($FilePath); 20300 } 20301 else 20302 { # Perl Data::Dumper format (default) 20303 open(DUMP, $FilePath); 20304 local $/ = undef; 20305 my $Content = <DUMP>; 20306 close(DUMP); 20307 20308 if(get_dirname($FilePath) eq $TMP_DIR."/unpack") 20309 { # remove temp file 20310 unlink($FilePath); 20311 } 20312 if($Content!~/};\s*\Z/) { 20313 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 20314 } 20315 $ABI = eval($Content); 20316 if(not $ABI) { 20317 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 20318 } 20319 } 20320 # new dumps (>=1.22) have a personal versioning 20321 my $DVersion = $ABI->{"ABI_DUMP_VERSION"}; 20322 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}; 20323 if(not $DVersion) 20324 { # old dumps (<=1.21.6) have been marked by the tool version 20325 $DVersion = $ToolVersion; 20326 } 20327 $UsedDump{$LibVersion}{"V"} = $DVersion; 20328 $UsedDump{$LibVersion}{"M"} = $ABI->{"LibraryName"}; 20329 20330 if($ABI->{"PublicABI"}) { 20331 $UsedDump{$LibVersion}{"Public"} = 1; 20332 } 20333 20334 if($ABI->{"ABI_DUMP_VERSION"}) 20335 { 20336 if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0) 20337 { # Don't know how to parse future dump formats 20338 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)"); 20339 } 20340 } 20341 else 20342 { # support for old ABI dumps 20343 if(cmpVersions($DVersion, $TOOL_VERSION)>0) 20344 { # Don't know how to parse future dump formats 20345 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)"); 20346 } 20347 } 20348 20349 if(majorVersion($DVersion)<2) 20350 { 20351 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)"); 20352 } 20353 20354 if(defined $ABI->{"ABI_DUMPER_VERSION"}) 20355 { # DWARF ABI Dump 20356 $UseConv_Real{$LibVersion}{"P"} = 1; 20357 $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet 20358 20359 $UsedDump{$LibVersion}{"DWARF"} = 1; 20360 20361 if(not $TargetComponent_Opt) 20362 { 20363 if($ABI->{"LibraryName"}=~/\.ko[\.\d]*\Z/) { 20364 $TargetComponent = "module"; 20365 } 20366 else { 20367 $TargetComponent = "object"; 20368 } 20369 } 20370 } 20371 20372 if(not checkDump($LibVersion, "2.11")) 20373 { # old ABI dumps 20374 $UsedDump{$LibVersion}{"BinOnly"} = 1; 20375 } 20376 elsif($ABI->{"BinOnly"}) 20377 { # ABI dump created with --binary option 20378 $UsedDump{$LibVersion}{"BinOnly"} = 1; 20379 } 20380 else 20381 { # default 20382 $UsedDump{$LibVersion}{"SrcBin"} = 1; 20383 } 20384 20385 if(defined $ABI->{"Mode"} 20386 and $ABI->{"Mode"} eq "Extended") 20387 { # --ext option 20388 $ExtendedCheck = 1; 20389 } 20390 if($ABI->{"Extra"}) { 20391 $ExtraDump = 1; 20392 } 20393 20394 if(my $Lang = $ABI->{"Language"}) 20395 { 20396 $UsedDump{$LibVersion}{"L"} = $Lang; 20397 setLanguage($LibVersion, $Lang); 20398 } 20399 if(checkDump($LibVersion, "2.15")) { 20400 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"}; 20401 } 20402 else 20403 { # support for old ABI dumps 20404 my $TInfo = $ABI->{"TypeInfo"}; 20405 if(not $TInfo) 20406 { # support for older ABI dumps 20407 $TInfo = $ABI->{"TypeDescr"}; 20408 } 20409 my %Tid_TDid = (); 20410 foreach my $TDid (keys(%{$TInfo})) 20411 { 20412 foreach my $Tid (keys(%{$TInfo->{$TDid}})) 20413 { 20414 $MAX_ID = $Tid if($Tid>$MAX_ID); 20415 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID); 20416 $Tid_TDid{$Tid}{$TDid} = 1; 20417 } 20418 } 20419 my %NewID = (); 20420 foreach my $Tid (keys(%Tid_TDid)) 20421 { 20422 my @TDids = keys(%{$Tid_TDid{$Tid}}); 20423 if($#TDids>=1) 20424 { 20425 foreach my $TDid (@TDids) 20426 { 20427 if($TDid) { 20428 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 20429 } 20430 else 20431 { 20432 my $ID = ++$MAX_ID; 20433 20434 $NewID{$TDid}{$Tid} = $ID; 20435 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; 20436 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; 20437 } 20438 } 20439 } 20440 else 20441 { 20442 my $TDid = $TDids[0]; 20443 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 20444 } 20445 } 20446 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 20447 { 20448 my %Info = %{$TypeInfo{$LibVersion}{$Tid}}; 20449 if(defined $Info{"BaseType"}) 20450 { 20451 my $Bid = $Info{"BaseType"}{"Tid"}; 20452 my $BDid = $Info{"BaseType"}{"TDid"}; 20453 $BDid="" if(not defined $BDid); 20454 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"}); 20455 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) { 20456 $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID; 20457 } 20458 } 20459 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"}); 20460 } 20461 } 20462 read_Machine_DumpInfo($ABI, $LibVersion); 20463 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"}; 20464 if(not $SymbolInfo{$LibVersion}) 20465 { # support for old dumps 20466 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"}; 20467 } 20468 if(not keys(%{$SymbolInfo{$LibVersion}})) 20469 { # validation of old-version dumps 20470 if(not $ExtendedCheck) { 20471 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid"); 20472 } 20473 } 20474 if(checkDump($LibVersion, "2.15")) { 20475 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"}; 20476 } 20477 else 20478 { # support for old ABI dumps 20479 my $DepSymbols = $ABI->{"DepSymbols"}; 20480 if(not $DepSymbols) { 20481 $DepSymbols = $ABI->{"DepInterfaces"}; 20482 } 20483 if(not $DepSymbols) 20484 { # Cannot reconstruct DepSymbols. This may result in false 20485 # positives if the old dump is for library 2. Not a problem if 20486 # old dumps are only from old libraries. 20487 $DepSymbols = {}; 20488 } 20489 foreach my $Symbol (keys(%{$DepSymbols})) { 20490 $DepSymbol_Library{$LibVersion}{$Symbol} = 1; 20491 } 20492 } 20493 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"}; 20494 20495 if(my $V = $TargetVersion{$LibVersion}) { 20496 $Descriptor{$LibVersion}{"Version"} = $V; 20497 } 20498 else { 20499 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"}; 20500 } 20501 20502 if(not keys(%{$SkipTypes{$LibVersion}})) 20503 { # if not defined by -skip-types option 20504 if(defined $ABI->{"SkipTypes"}) 20505 { 20506 foreach my $TName (keys(%{$ABI->{"SkipTypes"}})) 20507 { 20508 $SkipTypes{$LibVersion}{$TName} = 1; 20509 } 20510 } 20511 if(defined $ABI->{"OpaqueTypes"}) 20512 { # support for old dumps 20513 foreach my $TName (keys(%{$ABI->{"OpaqueTypes"}})) 20514 { 20515 $SkipTypes{$LibVersion}{$TName} = 1; 20516 } 20517 } 20518 } 20519 20520 if(not keys(%{$SkipSymbols{$LibVersion}})) 20521 { # if not defined by -skip-symbols option 20522 if(defined $ABI->{"SkipSymbols"}) { 20523 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; 20524 } 20525 if(defined $ABI->{"SkipInterfaces"}) 20526 { # support for old dumps 20527 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"}; 20528 } 20529 if(defined $ABI->{"InternalInterfaces"}) 20530 { # support for old dumps 20531 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"}; 20532 } 20533 } 20534 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"}; 20535 20536 if(not $TargetHeaders{$LibVersion}) 20537 { # if not defined by -headers-list option 20538 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"}; 20539 } 20540 20541 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}})) 20542 { 20543 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path}; 20544 20545 my ($CPath, $Type) = classifyPath($Path); 20546 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path}; 20547 } 20548 20549 read_Source_DumpInfo($ABI, $LibVersion); 20550 read_Libs_DumpInfo($ABI, $LibVersion); 20551 20552 if(not checkDump($LibVersion, "2.10.1") 20553 or not $TargetHeaders{$LibVersion}) 20554 { # support for old ABI dumps: added target headers 20555 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20556 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20557 } 20558 20559 if(not $ABI->{"PublicABI"}) 20560 { 20561 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20562 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20563 } 20564 } 20565 } 20566 $Constants{$LibVersion} = $ABI->{"Constants"}; 20567 if(defined $ABI->{"GccConstants"}) 20568 { # 3.0 20569 foreach my $Name (keys(%{$ABI->{"GccConstants"}})) { 20570 $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name}; 20571 } 20572 } 20573 20574 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"}; 20575 if(not $NestedNameSpaces{$LibVersion}) 20576 { # support for old dumps 20577 # Cannot reconstruct NameSpaces. This may affect design 20578 # of the compatibility report. 20579 $NestedNameSpaces{$LibVersion} = {}; 20580 } 20581 # target system type 20582 # needed to adopt HTML report 20583 if(not $DumpSystem) 20584 { # to use in createSymbolsList(...) 20585 $OStarget = $ABI->{"Target"}; 20586 } 20587 # recreate environment 20588 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}})) 20589 { 20590 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 20591 { 20592 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20593 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1) 20594 { # data marked as -size in the dump 20595 $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}; 20596 } 20597 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 20598 { 20599 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 20600 setLanguage($LibVersion, "C++"); 20601 } 20602 } 20603 } 20604 } 20605 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}})) 20606 { 20607 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) { 20608 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20609 } 20610 } 20611 20612 my @VFunc = (); 20613 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20614 { 20615 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20616 { 20617 if(not $Symbol_Library{$LibVersion}{$MnglName} 20618 and not $DepSymbol_Library{$LibVersion}{$MnglName}) { 20619 push(@VFunc, $MnglName); 20620 } 20621 } 20622 } 20623 translateSymbols(@VFunc, $LibVersion); 20624 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 20625 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 20626 20627 if(not checkDump($LibVersion, "3.0")) 20628 { # support for old ABI dumps 20629 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20630 { 20631 if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20632 { 20633 if(ref($BaseType) eq "HASH") { 20634 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"}; 20635 } 20636 } 20637 } 20638 } 20639 20640 if(not checkDump($LibVersion, "3.2")) 20641 { # support for old ABI dumps 20642 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20643 { 20644 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) 20645 { 20646 foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) { 20647 $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset}); 20648 } 20649 } 20650 } 20651 20652 # repair target headers list 20653 delete($TargetHeaders{$LibVersion}); 20654 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20655 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20656 } 20657 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20658 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20659 } 20660 20661 # non-target constants from anon enums 20662 foreach my $Name (keys(%{$Constants{$LibVersion}})) 20663 { 20664 if(not $ExtraDump 20665 and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion)) 20666 { 20667 delete($Constants{$LibVersion}{$Name}); 20668 } 20669 } 20670 } 20671 20672 if(not checkDump($LibVersion, "2.20")) 20673 { # support for old ABI dumps 20674 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20675 { 20676 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20677 20678 if($TType=~/Struct|Union|Enum|Typedef/) 20679 { # repair complex types first 20680 next; 20681 } 20682 20683 if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20684 { 20685 my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"}); 20686 if($BType=~/Struct|Union|Enum/i) 20687 { 20688 my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}; 20689 $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g; 20690 } 20691 } 20692 } 20693 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20694 { 20695 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20696 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 20697 if($TType=~/Struct|Union|Enum/) { 20698 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName; 20699 } 20700 } 20701 } 20702 20703 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20704 { # NOTE: order is important 20705 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}) 20706 { # support for old ABI dumps < 2.0 (ACC 1.22) 20707 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}})) 20708 { 20709 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId}) 20710 { 20711 if($Access ne "public") { 20712 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access; 20713 } 20714 } 20715 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {}; 20716 } 20717 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}); 20718 } 20719 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"}) 20720 { # support for old ABI dumps 20721 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup); 20722 } 20723 elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"}) 20724 { # DWARF ABI Dumps 20725 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source; 20726 } 20727 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) { 20728 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId; 20729 } 20730 20731 # support for old formatting of type names 20732 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = formatName($TypeInfo{$LibVersion}{$TypeId}{"Name"}, "T"); 20733 20734 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}}; 20735 if(defined $TInfo{"Base"}) 20736 { 20737 foreach my $SubId (keys(%{$TInfo{"Base"}})) 20738 { 20739 if($SubId eq $TypeId) 20740 { # Fix erroneus ABI dump 20741 delete($TypeInfo{$LibVersion}{$TypeId}{"Base"}{$SubId}); 20742 next; 20743 } 20744 20745 $Class_SubClasses{$LibVersion}{$SubId}{$TypeId} = 1; 20746 } 20747 } 20748 if($TInfo{"Type"} eq "MethodPtr") 20749 { 20750 if(defined $TInfo{"Param"}) 20751 { # support for old ABI dumps <= 1.17 20752 if(not defined $TInfo{"Param"}{"0"}) 20753 { 20754 my $Max = keys(%{$TInfo{"Param"}}); 20755 foreach my $Pos (1 .. $Max) { 20756 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos}; 20757 } 20758 delete($TInfo{"Param"}{$Max}); 20759 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo; 20760 } 20761 } 20762 } 20763 if($TInfo{"BaseType"} eq $TypeId) 20764 { # fix ABI dump 20765 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"}); 20766 } 20767 20768 if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"}) 20769 { 20770 if(my $BTid = $TInfo{"BaseType"}) 20771 { 20772 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"}; 20773 if(not $BName) 20774 { # broken type 20775 next; 20776 } 20777 if($TInfo{"Name"} eq $BName) 20778 { # typedef to "class Class" 20779 # should not be registered in TName_Tid 20780 next; 20781 } 20782 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) { 20783 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName; 20784 } 20785 } 20786 } 20787 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}}) 20788 { # classes: class (id1), typedef (artificial, id2 > id1) 20789 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId; 20790 } 20791 } 20792 20793 if(not checkDump($LibVersion, "2.15")) 20794 { # support for old ABI dumps 20795 my %Dups = (); 20796 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20797 { 20798 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20799 { 20800 if(not defined $TypeInfo{$LibVersion}{$ClassId}) 20801 { # remove template decls 20802 delete($SymbolInfo{$LibVersion}{$InfoId}); 20803 next; 20804 } 20805 } 20806 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 20807 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20808 { # templates 20809 delete($SymbolInfo{$LibVersion}{$InfoId}); 20810 } 20811 } 20812 } 20813 20814 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20815 { 20816 if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 20817 and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"} 20818 and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 20819 { # support for old ABI dumps (< 3.1) 20820 if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 20821 or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 20822 { # add "this" first parameter 20823 my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion); 20824 my %PInfo = ("name"=>"this", "type"=>"$ThisTid"); 20825 20826 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 20827 { 20828 my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 20829 foreach my $Pos (reverse(0 .. $#Pos)) { 20830 %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}}; 20831 } 20832 } 20833 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo; 20834 } 20835 } 20836 20837 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20838 { # ABI dumps have no mangled names for C-functions 20839 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 20840 } 20841 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"}) 20842 { # support for old ABI dumps 20843 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup); 20844 } 20845 elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"}) 20846 { # DWARF ABI Dumps 20847 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source; 20848 } 20849 } 20850 20851 $Descriptor{$LibVersion}{"Dump"} = 1; 20852} 20853 20854sub read_Machine_DumpInfo($$) 20855{ 20856 my ($ABI, $LibVersion) = @_; 20857 if($ABI->{"Arch"}) { 20858 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"}; 20859 } 20860 if($ABI->{"WordSize"}) { 20861 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"}; 20862 } 20863 else 20864 { # support for old dumps 20865 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"}; 20866 } 20867 if(not $WORD_SIZE{$LibVersion}) 20868 { # support for old dumps (<1.23) 20869 if(my $Tid = getTypeIdByName("char*", $LibVersion)) 20870 { # size of char* 20871 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20872 } 20873 else 20874 { 20875 my $PSize = 0; 20876 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 20877 { 20878 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer") 20879 { # any "pointer"-type 20880 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20881 last; 20882 } 20883 } 20884 if($PSize) 20885 { # a pointer type size 20886 $WORD_SIZE{$LibVersion} = $PSize; 20887 } 20888 else { 20889 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)"); 20890 } 20891 } 20892 } 20893 if($ABI->{"GccVersion"}) { 20894 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"}; 20895 } 20896 elsif($ABI->{"ClangVersion"}) { 20897 $CLANG_VERSION{$LibVersion} = $ABI->{"ClangVersion"}; 20898 } 20899} 20900 20901sub read_Libs_DumpInfo($$) 20902{ 20903 my ($ABI, $LibVersion) = @_; 20904 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"}; 20905 if(not $Library_Symbol{$LibVersion}) 20906 { # support for old dumps 20907 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"}; 20908 } 20909 if(keys(%{$Library_Symbol{$LibVersion}}) 20910 and not $DumpAPI) { 20911 $Descriptor{$LibVersion}{"Libs"} = "OK"; 20912 } 20913} 20914 20915sub read_Source_DumpInfo($$) 20916{ 20917 my ($ABI, $LibVersion) = @_; 20918 20919 if(keys(%{$ABI->{"Headers"}}) 20920 and not $DumpAPI) { 20921 $Descriptor{$LibVersion}{"Headers"} = "OK"; 20922 } 20923 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}})) 20924 { 20925 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity; 20926 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity}; 20927 } 20928 20929 if(keys(%{$ABI->{"Sources"}}) 20930 and not $DumpAPI) { 20931 $Descriptor{$LibVersion}{"Sources"} = "OK"; 20932 } 20933 foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}})) 20934 { 20935 $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name; 20936 $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name}; 20937 } 20938} 20939 20940sub find_libs($$$) 20941{ 20942 my ($Path, $Type, $MaxDepth) = @_; 20943 # FIXME: correct the search pattern 20944 return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1); 20945} 20946 20947sub createDescriptor($$) 20948{ 20949 my ($LibVersion, $Path) = @_; 20950 if(not $LibVersion or not $Path 20951 or not -e $Path) { 20952 return ""; 20953 } 20954 if(-d $Path) 20955 { # directory with headers files and shared objects 20956 return " 20957 <version> 20958 ".$TargetVersion{$LibVersion}." 20959 </version> 20960 20961 <headers> 20962 $Path 20963 </headers> 20964 20965 <libs> 20966 $Path 20967 </libs>"; 20968 } 20969 else 20970 { # files 20971 if($Path=~/\.(xml|desc)\Z/i) 20972 { # standard XML-descriptor 20973 return readFile($Path); 20974 } 20975 elsif(is_header($Path, 2, $LibVersion)) 20976 { # header file 20977 $CheckHeadersOnly = 1; 20978 20979 if($LibVersion==1) { 20980 $TargetVersion{$LibVersion} = "X"; 20981 } 20982 20983 if($LibVersion==2) { 20984 $TargetVersion{$LibVersion} = "Y"; 20985 } 20986 20987 return " 20988 <version> 20989 ".$TargetVersion{$LibVersion}." 20990 </version> 20991 20992 <headers> 20993 $Path 20994 </headers> 20995 20996 <libs> 20997 none 20998 </libs>"; 20999 } 21000 else 21001 { # standard XML-descriptor 21002 return readFile($Path); 21003 } 21004 } 21005} 21006 21007sub detect_lib_default_paths() 21008{ 21009 my %LPaths = (); 21010 if($OSgroup eq "bsd") 21011 { 21012 if(my $LdConfig = get_CmdPath("ldconfig")) 21013 { 21014 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`)) 21015 { 21016 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) 21017 { 21018 my $Name = "lib".$1; 21019 if(not defined $LPaths{$Name}) { 21020 $LPaths{$Name} = $2; 21021 } 21022 } 21023 } 21024 } 21025 else { 21026 printMsg("WARNING", "can't find ldconfig"); 21027 } 21028 } 21029 else 21030 { 21031 if(my $LdConfig = get_CmdPath("ldconfig")) 21032 { 21033 if($SystemRoot and $OSgroup eq "linux") 21034 { # use host (x86) ldconfig with the target (arm) ld.so.conf 21035 if(-e $SystemRoot."/etc/ld.so.conf") { 21036 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf"; 21037 } 21038 } 21039 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`)) 21040 { 21041 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/) 21042 { 21043 my ($Name, $Path) = ($1, $2); 21044 $Path=~s/[\/]{2,}/\//; 21045 if(not defined $LPaths{$Name}) 21046 { # get first element from the list of available paths 21047 21048 # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 21049 # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6 21050 # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6 21051 21052 $LPaths{$Name} = $Path; 21053 } 21054 } 21055 } 21056 } 21057 elsif($OSgroup eq "linux") { 21058 printMsg("WARNING", "can't find ldconfig"); 21059 } 21060 } 21061 return \%LPaths; 21062} 21063 21064sub detect_bin_default_paths() 21065{ 21066 my $EnvPaths = $ENV{"PATH"}; 21067 if($OSgroup eq "beos") { 21068 $EnvPaths.=":".$ENV{"BETOOLS"}; 21069 } 21070 my $Sep = ($OSgroup eq "windows")?";":":|;"; 21071 foreach my $Path (split(/$Sep/, $EnvPaths)) 21072 { 21073 $Path = path_format($Path, $OSgroup); 21074 next if(not $Path); 21075 if($SystemRoot 21076 and $Path=~/\A\Q$SystemRoot\E\//) 21077 { # do NOT use binaries from target system 21078 next; 21079 } 21080 push_U(\@DefaultBinPaths, $Path); 21081 } 21082} 21083 21084sub detect_inc_default_paths() 21085{ 21086 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]); 21087 writeFile("$TMP_DIR/empty.h", ""); 21088 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`)) 21089 { # detecting GCC default include paths 21090 next if(index($Line, "/cc1plus ")!=-1); 21091 21092 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) 21093 { 21094 my $Path = realpath_F($1); 21095 if(index($Path, "c++")!=-1 21096 or index($Path, "/g++/")!=-1) 21097 { 21098 push_U($DPaths{"Cpp"}, $Path); 21099 if(not defined $MAIN_CPP_DIR 21100 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) { 21101 $MAIN_CPP_DIR = $Path; 21102 } 21103 } 21104 elsif(index($Path, "gcc")!=-1) { 21105 push_U($DPaths{"Gcc"}, $Path); 21106 } 21107 else 21108 { 21109 if($Path=~/local[\/\\]+include/) 21110 { # local paths 21111 next; 21112 } 21113 if($SystemRoot 21114 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/) 21115 { # The GCC include path for user headers is not a part of the system root 21116 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler 21117 # or it is the internal cross-GCC path like arm-linux-gnueabi/include 21118 next; 21119 } 21120 push_U($DPaths{"Inc"}, $Path); 21121 } 21122 } 21123 } 21124 unlink("$TMP_DIR/empty.h"); 21125 return %DPaths; 21126} 21127 21128sub detect_default_paths($) 21129{ 21130 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1); 21131 my $Search = $_[0]; 21132 if($Search!~/inc/) { 21133 $HSearch = 0; 21134 } 21135 if($Search!~/lib/) { 21136 $LSearch = 0; 21137 } 21138 if($Search!~/bin/) { 21139 $BSearch = 0; 21140 } 21141 if($Search!~/gcc/) { 21142 $GSearch = 0; 21143 } 21144 if(@{$SystemPaths{"include"}}) 21145 { # <search_headers> section of the XML descriptor 21146 # do NOT search for systems headers 21147 $HSearch = 0; 21148 } 21149 if(@{$SystemPaths{"lib"}}) 21150 { # <search_libs> section of the XML descriptor 21151 # do NOT search for systems libraries 21152 $LSearch = 0; 21153 } 21154 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}})) 21155 { # additional search paths 21156 next if($Type eq "include" and not $HSearch); 21157 next if($Type eq "lib" and not $LSearch); 21158 next if($Type eq "bin" and not $BSearch); 21159 push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}}); 21160 } 21161 if($OSgroup ne "windows") 21162 { # unix-like 21163 foreach my $Type ("include", "lib", "bin") 21164 { # automatic detection of system "devel" directories 21165 next if($Type eq "include" and not $HSearch); 21166 next if($Type eq "lib" and not $LSearch); 21167 next if($Type eq "bin" and not $BSearch); 21168 my ($UsrDir, $RootDir) = ("/usr", "/"); 21169 if($SystemRoot and $Type ne "bin") 21170 { # 1. search for target headers and libraries 21171 # 2. use host commands: ldconfig, readelf, etc. 21172 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot); 21173 } 21174 push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1)); 21175 if(-d $RootDir."/".$Type) 21176 { # if "/lib" is symbolic link 21177 if($RootDir eq "/") { 21178 push_U($SystemPaths{$Type}, "/".$Type); 21179 } 21180 else { 21181 push_U($SystemPaths{$Type}, $RootDir."/".$Type); 21182 } 21183 } 21184 if(-d $UsrDir) 21185 { 21186 push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1)); 21187 if(-d $UsrDir."/".$Type) 21188 { # if "/usr/lib" is symbolic link 21189 push_U($SystemPaths{$Type}, $UsrDir."/".$Type); 21190 } 21191 } 21192 } 21193 } 21194 if($BSearch) 21195 { 21196 detect_bin_default_paths(); 21197 push_U($SystemPaths{"bin"}, @DefaultBinPaths); 21198 } 21199 # check environment variables 21200 if($OSgroup eq "beos") 21201 { 21202 foreach (my @Paths = @{$SystemPaths{"bin"}}) 21203 { 21204 if($_ eq ".") { 21205 next; 21206 } 21207 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/ 21208 if(my @Dirs = sort cmd_find($_, "d", "bin")) { 21209 push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs); 21210 } 21211 } 21212 if($HSearch) 21213 { 21214 push_U(\@DefaultIncPaths, grep { is_abs($_) } ( 21215 split(/:|;/, $ENV{"BEINCLUDES"}) 21216 )); 21217 } 21218 if($LSearch) 21219 { 21220 push_U(\@DefaultLibPaths, grep { is_abs($_) } ( 21221 split(/:|;/, $ENV{"BELIBRARIES"}), 21222 split(/:|;/, $ENV{"LIBRARY_PATH"}) 21223 )); 21224 } 21225 } 21226 if($LSearch) 21227 { # using linker to get system paths 21228 if(my $LPaths = detect_lib_default_paths()) 21229 { # unix-like 21230 my %Dirs = (); 21231 foreach my $Name (keys(%{$LPaths})) 21232 { 21233 if($SystemRoot 21234 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//) 21235 { # wrong ldconfig configuration 21236 # check your <sysroot>/etc/ld.so.conf 21237 next; 21238 } 21239 $DyLib_DefaultPath{$Name} = $LPaths->{$Name}; 21240 if(my $Dir = get_dirname($LPaths->{$Name})) { 21241 $Dirs{$Dir} = 1; 21242 } 21243 } 21244 push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs)); 21245 } 21246 push_U($SystemPaths{"lib"}, @DefaultLibPaths); 21247 } 21248 if($BSearch) 21249 { 21250 if($CrossGcc) 21251 { # --cross-gcc=arm-linux-gcc 21252 if(-e $CrossGcc) 21253 { # absolute or relative path 21254 $GCC_PATH = get_abs_path($CrossGcc); 21255 } 21256 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc)) 21257 { # command name 21258 $GCC_PATH = $CrossGcc; 21259 } 21260 else { 21261 exitStatus("Access_Error", "can't access \'$CrossGcc\'"); 21262 } 21263 if($GCC_PATH=~/\s/) { 21264 $GCC_PATH = "\"".$GCC_PATH."\""; 21265 } 21266 } 21267 } 21268 if($GSearch) 21269 { # GCC path and default include dirs 21270 if(not $CrossGcc) 21271 { # try default gcc 21272 $GCC_PATH = get_CmdPath("gcc"); 21273 } 21274 if(not $GCC_PATH) 21275 { # try to find gcc-X.Y 21276 foreach my $Path (@{$SystemPaths{"bin"}}) 21277 { 21278 if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1)) 21279 { # select the latest version 21280 @GCCs = sort {$b cmp $a} @GCCs; 21281 if(check_gcc($GCCs[0], "3")) 21282 { 21283 $GCC_PATH = $GCCs[0]; 21284 last; 21285 } 21286 } 21287 } 21288 } 21289 if(not $GCC_PATH) { 21290 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); 21291 } 21292 21293 my $GCC_Ver = get_dumpversion($GCC_PATH); 21294 if($GCC_Ver eq "4.8") 21295 { # on Ubuntu -dumpversion returns 4.8 for gcc 4.8.4 21296 my $Info = `$GCC_PATH --version`; 21297 21298 if($Info=~/gcc\s+(|\([^()]+\)\s+)(\d+\.\d+\.\d+)/) 21299 { # gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 21300 # gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6) 21301 $GCC_Ver = $2; 21302 } 21303 } 21304 21305 if($OStarget=~/macos/) 21306 { 21307 my $Info = `$GCC_PATH --version`; 21308 21309 if($Info=~/clang/i) { 21310 printMsg("WARNING", "doesn't work with clang, please install GCC instead (and select it by -gcc-path option)"); 21311 } 21312 } 21313 21314 if($GCC_Ver) 21315 { 21316 my $GccTarget = get_dumpmachine($GCC_PATH); 21317 21318 if($GccTarget=~/linux/) 21319 { 21320 $OStarget = "linux"; 21321 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; 21322 } 21323 elsif($GccTarget=~/symbian/) 21324 { 21325 $OStarget = "symbian"; 21326 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; 21327 } 21328 21329 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget, target: ".getArch_GCC(1).")"); 21330 21331 # check GCC version 21332 if($GCC_Ver=~/\A4\.8(|\.[012])|6\.[12]\.0\Z/) 21333 { # GCC 4.8.[0-2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 21334 # GCC 6.[1-2].0: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78040 21335 21336 printMsg("ERROR", "Not working properly with GCC $GCC_Ver. Please use other GCC version with the help of --gcc-path=PATH option. Not supported GCC versions: 4.8.0, 4.8.1, 4.8.2, 6.1.0, 6.2.0"); 21337 21338 $GCC_MISSED_MNGL = 1; 21339 } 21340 } 21341 else { 21342 exitStatus("Error", "something is going wrong with the GCC compiler"); 21343 } 21344 } 21345 if($HSearch) 21346 { 21347 # GCC standard paths 21348 if($GCC_PATH and not $NoStdInc) 21349 { 21350 my %DPaths = detect_inc_default_paths(); 21351 @DefaultCppPaths = @{$DPaths{"Cpp"}}; 21352 @DefaultGccPaths = @{$DPaths{"Gcc"}}; 21353 @DefaultIncPaths = @{$DPaths{"Inc"}}; 21354 push_U($SystemPaths{"include"}, @DefaultIncPaths); 21355 } 21356 21357 # users include paths 21358 my $IncPath = "/usr/include"; 21359 if($SystemRoot) { 21360 $IncPath = $SystemRoot.$IncPath; 21361 } 21362 if(-d $IncPath) { 21363 push_U(\@UsersIncPath, $IncPath); 21364 } 21365 } 21366 21367 if($ExtraInfo) 21368 { 21369 writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths)); 21370 writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths))); 21371 } 21372} 21373 21374sub getLIB_EXT($) 21375{ 21376 my $Target = $_[0]; 21377 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) { 21378 return $Ext; 21379 } 21380 return $OS_LibExt{$LIB_TYPE}{"default"}; 21381} 21382 21383sub getAR_EXT($) 21384{ 21385 my $Target = $_[0]; 21386 if(my $Ext = $OS_Archive{$Target}) { 21387 return $Ext; 21388 } 21389 return $OS_Archive{"default"}; 21390} 21391 21392sub get_dumpversion($) 21393{ 21394 my $Cmd = $_[0]; 21395 return "" if(not $Cmd); 21396 if($Cache{"get_dumpversion"}{$Cmd}) { 21397 return $Cache{"get_dumpversion"}{$Cmd}; 21398 } 21399 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`; 21400 chomp($V); 21401 return ($Cache{"get_dumpversion"}{$Cmd} = $V); 21402} 21403 21404sub get_dumpmachine($) 21405{ 21406 my $Cmd = $_[0]; 21407 return "" if(not $Cmd); 21408 if($Cache{"get_dumpmachine"}{$Cmd}) { 21409 return $Cache{"get_dumpmachine"}{$Cmd}; 21410 } 21411 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`; 21412 chomp($Machine); 21413 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine); 21414} 21415 21416sub checkCmd($) 21417{ 21418 my $Cmd = $_[0]; 21419 return "" if(not $Cmd); 21420 my @Options = ( 21421 "--version", 21422 "-help" 21423 ); 21424 foreach my $Opt (@Options) 21425 { 21426 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`; 21427 if($Info) { 21428 return 1; 21429 } 21430 } 21431 return 0; 21432} 21433 21434sub check_gcc($$) 21435{ 21436 my ($Cmd, $ReqVer) = @_; 21437 return 0 if(not $Cmd or not $ReqVer); 21438 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) { 21439 return $Cache{"check_gcc"}{$Cmd}{$ReqVer}; 21440 } 21441 if(my $GccVer = get_dumpversion($Cmd)) 21442 { 21443 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818") 21444 if(cmpVersions($GccVer, $ReqVer)>=0) { 21445 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd); 21446 } 21447 } 21448 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = ""); 21449} 21450 21451sub get_depth($) 21452{ 21453 if(defined $Cache{"get_depth"}{$_[0]}) { 21454 return $Cache{"get_depth"}{$_[0]}; 21455 } 21456 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!)); 21457} 21458 21459sub registerGccHeaders() 21460{ 21461 return if($Cache{"registerGccHeaders"}); # this function should be called once 21462 21463 foreach my $Path (@DefaultGccPaths) 21464 { 21465 my @Headers = cmd_find($Path,"f"); 21466 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 21467 foreach my $HPath (@Headers) 21468 { 21469 my $FileName = get_filename($HPath); 21470 if(not defined $DefaultGccHeader{$FileName}) 21471 { # skip duplicated 21472 $DefaultGccHeader{$FileName} = $HPath; 21473 } 21474 } 21475 } 21476 $Cache{"registerGccHeaders"} = 1; 21477} 21478 21479sub registerCppHeaders() 21480{ 21481 return if($Cache{"registerCppHeaders"}); # this function should be called once 21482 21483 foreach my $CppDir (@DefaultCppPaths) 21484 { 21485 my @Headers = cmd_find($CppDir,"f"); 21486 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 21487 foreach my $Path (@Headers) 21488 { 21489 my $FileName = get_filename($Path); 21490 if(not defined $DefaultCppHeader{$FileName}) 21491 { # skip duplicated 21492 $DefaultCppHeader{$FileName} = $Path; 21493 } 21494 } 21495 } 21496 $Cache{"registerCppHeaders"} = 1; 21497} 21498 21499sub parse_libname($$$) 21500{ 21501 return "" if(not $_[0]); 21502 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) { 21503 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}; 21504 } 21505 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_)); 21506} 21507 21508sub parse_libname_I($$$) 21509{ 21510 my ($Name, $Type, $Target) = @_; 21511 21512 if($Target eq "symbian") { 21513 return parse_libname_symbian($Name, $Type); 21514 } 21515 elsif($Target eq "windows") { 21516 return parse_libname_windows($Name, $Type); 21517 } 21518 21519 # unix 21520 my $Ext = getLIB_EXT($Target); 21521 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/) 21522 { # libSDL-1.2.so.0.7.1 21523 # libwbxml2.so.0.0.18 21524 # libopcodes-2.21.53-system.20110810.so 21525 if($Type eq "name") 21526 { # libSDL-1.2 21527 # libwbxml2 21528 return $2; 21529 } 21530 elsif($Type eq "name+ext") 21531 { # libSDL-1.2.so 21532 # libwbxml2.so 21533 return $1; 21534 } 21535 elsif($Type eq "version") 21536 { 21537 if(defined $7 21538 and $7 ne "") 21539 { # 0.7.1 21540 return $7; 21541 } 21542 else 21543 { # libc-2.5.so (=>2.5 version) 21544 my $MV = $5; 21545 $MV=~s/\A[\-\_]+//g; 21546 return $MV; 21547 } 21548 } 21549 elsif($Type eq "short") 21550 { # libSDL 21551 # libwbxml2 21552 return $3; 21553 } 21554 elsif($Type eq "shortest") 21555 { # SDL 21556 # wbxml 21557 return shortest_name($3); 21558 } 21559 } 21560 return "";# error 21561} 21562 21563sub parse_libname_symbian($$) 21564{ 21565 my ($Name, $Type) = @_; 21566 my $Ext = getLIB_EXT("symbian"); 21567 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/) 21568 { # libpthread{00010001}.dso 21569 if($Type eq "name") 21570 { # libpthread{00010001} 21571 return $2; 21572 } 21573 elsif($Type eq "name+ext") 21574 { # libpthread{00010001}.dso 21575 return $1; 21576 } 21577 elsif($Type eq "version") 21578 { # 00010001 21579 my $V = $4; 21580 $V=~s/\{(.+)\}/$1/; 21581 return $V; 21582 } 21583 elsif($Type eq "short") 21584 { # libpthread 21585 return $3; 21586 } 21587 elsif($Type eq "shortest") 21588 { # pthread 21589 return shortest_name($3); 21590 } 21591 } 21592 return "";# error 21593} 21594 21595sub parse_libname_windows($$) 21596{ 21597 my ($Name, $Type) = @_; 21598 my $Ext = getLIB_EXT("windows"); 21599 if($Name=~/((.+?)\.$Ext)\Z/) 21600 { # netapi32.dll 21601 if($Type eq "name") 21602 { # netapi32 21603 return $2; 21604 } 21605 elsif($Type eq "name+ext") 21606 { # netapi32.dll 21607 return $1; 21608 } 21609 elsif($Type eq "version") 21610 { # DLL version embedded 21611 # at binary-level 21612 return ""; 21613 } 21614 elsif($Type eq "short") 21615 { # netapi32 21616 return $2; 21617 } 21618 elsif($Type eq "shortest") 21619 { # netapi 21620 return shortest_name($2); 21621 } 21622 } 21623 return "";# error 21624} 21625 21626sub shortest_name($) 21627{ 21628 my $Name = $_[0]; 21629 # remove prefix 21630 $Name=~s/\A(lib|open)//; 21631 # remove suffix 21632 $Name=~s/[\W\d_]+\Z//i; 21633 $Name=~s/([a-z]{2,})(lib)\Z/$1/i; 21634 return $Name; 21635} 21636 21637sub createSymbolsList($$$$$) 21638{ 21639 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_; 21640 21641 read_ABI_Dump(1, $DPath); 21642 prepareSymbols(1); 21643 21644 my %SymbolHeaderLib = (); 21645 my $Total = 0; 21646 21647 # Get List 21648 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 21649 { 21650 if(not link_symbol($Symbol, 1, "-Deps")) 21651 { # skip src only and all external functions 21652 next; 21653 } 21654 if(not symbolFilter($Symbol, 1, "Public", "Binary")) 21655 { # skip other symbols 21656 next; 21657 } 21658 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 21659 if(not $HeaderName) 21660 { # skip src only and all external functions 21661 next; 21662 } 21663 my $DyLib = $Symbol_Library{1}{$Symbol}; 21664 if(not $DyLib) 21665 { # skip src only and all external functions 21666 next; 21667 } 21668 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1; 21669 $Total+=1; 21670 } 21671 # Draw List 21672 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)"; 21673 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>"; 21674 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib)) 21675 { 21676 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}})) 21677 { 21678 my %NS_Symbol = (); 21679 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) { 21680 $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 21681 } 21682 foreach my $NameSpace (sort keys(%NS_Symbol)) 21683 { 21684 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace); 21685 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}}); 21686 foreach my $Symbol (@SortedInterfaces) 21687 { 21688 my $SubReport = ""; 21689 my $Signature = get_Signature($Symbol, 1); 21690 if($NameSpace) { 21691 $Signature=~s/\b\Q$NameSpace\E::\b//g; 21692 } 21693 if($Symbol=~/\A(_Z|\?)/) 21694 { 21695 if($Signature) { 21696 $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n"); 21697 } 21698 else { 21699 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21700 } 21701 } 21702 else 21703 { 21704 if($Signature) { 21705 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 21706 } 21707 else { 21708 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21709 } 21710 } 21711 $SYMBOLS_LIST .= $SubReport; 21712 } 21713 } 21714 $SYMBOLS_LIST .= "<br/>\n"; 21715 } 21716 } 21717 # clear info 21718 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library, 21719 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols, 21720 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames, 21721 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = (); 21722 ($Content_Counter, $ContentID) = (0, 0); 21723 # print report 21724 my $CssStyles = readModule("Styles", "SymbolsList.css"); 21725 my $JScripts = readModule("Scripts", "Sections.js"); 21726 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n"; 21727 my $Title = "$LName: public symbols"; 21728 my $Keywords = "$LName, API, symbols"; 21729 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName); 21730 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)." 21731 <body><div>\n$SYMBOLS_LIST</div> 21732 <br/><br/>\n".getReportFooter()." 21733 </body></html>"; 21734 writeFile($SaveTo, $SYMBOLS_LIST); 21735} 21736 21737sub add_target_libs($) 21738{ 21739 foreach (@{$_[0]}) { 21740 $TargetLibs{$_} = 1; 21741 } 21742} 21743 21744sub is_target_lib($) 21745{ 21746 my $LName = $_[0]; 21747 if(not $LName) { 21748 return 0; 21749 } 21750 if($OSgroup eq "windows") { 21751 $LName = lc($LName); 21752 } 21753 if($TargetLibraryName 21754 and $LName!~/\Q$TargetLibraryName\E/) { 21755 return 0; 21756 } 21757 if(keys(%TargetLibs) 21758 and not $TargetLibs{$LName} 21759 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) { 21760 return 0; 21761 } 21762 return 1; 21763} 21764 21765sub is_target_header($$) 21766{ # --header, --headers-list 21767 my ($H, $V) = @_; 21768 if(keys(%{$TargetHeaders{$V}})) 21769 { 21770 if($TargetHeaders{$V}{$H}) { 21771 return 1; 21772 } 21773 } 21774 return 0; 21775} 21776 21777sub readLibs($) 21778{ 21779 my $LibVersion = $_[0]; 21780 if($OStarget eq "windows") 21781 { # dumpbin.exe will crash 21782 # without VS Environment 21783 check_win32_env(); 21784 } 21785 readSymbols($LibVersion); 21786 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 21787 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 21788} 21789 21790sub dump_sorting($) 21791{ 21792 my $Hash = $_[0]; 21793 return [] if(not $Hash); 21794 my @Keys = keys(%{$Hash}); 21795 return [] if($#Keys<0); 21796 if($Keys[0]=~/\A\d+\Z/) 21797 { # numbers 21798 return [sort {int($a)<=>int($b)} @Keys]; 21799 } 21800 else 21801 { # strings 21802 return [sort {$a cmp $b} @Keys]; 21803 } 21804} 21805 21806sub printMsg($$) 21807{ 21808 my ($Type, $Msg) = @_; 21809 if($Type!~/\AINFO/) { 21810 $Msg = $Type.": ".$Msg; 21811 } 21812 if($Type!~/_C\Z/) { 21813 $Msg .= "\n"; 21814 } 21815 if($Quiet) 21816 { # --quiet option 21817 appendFile($COMMON_LOG_PATH, $Msg); 21818 } 21819 else 21820 { 21821 if($Type eq "ERROR") { 21822 print STDERR $Msg; 21823 } 21824 else { 21825 print $Msg; 21826 } 21827 } 21828} 21829 21830sub exitStatus($$) 21831{ 21832 my ($Code, $Msg) = @_; 21833 printMsg("ERROR", $Msg); 21834 exit($ERROR_CODE{$Code}); 21835} 21836 21837sub exitReport() 21838{ # the tool has run without any errors 21839 printReport(); 21840 if($COMPILE_ERRORS) 21841 { # errors in headers may add false positives/negatives 21842 exit($ERROR_CODE{"Compile_Error"}); 21843 } 21844 if($BinaryOnly and $RESULT{"Binary"}{"Problems"}) 21845 { # --binary 21846 exit($ERROR_CODE{"Incompatible"}); 21847 } 21848 elsif($SourceOnly and $RESULT{"Source"}{"Problems"}) 21849 { # --source 21850 exit($ERROR_CODE{"Incompatible"}); 21851 } 21852 elsif($RESULT{"Source"}{"Problems"} 21853 or $RESULT{"Binary"}{"Problems"}) 21854 { # default 21855 exit($ERROR_CODE{"Incompatible"}); 21856 } 21857 else { 21858 exit($ERROR_CODE{"Compatible"}); 21859 } 21860} 21861 21862sub readRules($) 21863{ 21864 my $Kind = $_[0]; 21865 if(not -f $RULES_PATH{$Kind}) { 21866 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'"); 21867 } 21868 my $Content = readFile($RULES_PATH{$Kind}); 21869 while(my $Rule = parseTag(\$Content, "rule")) 21870 { 21871 my $RId = parseTag(\$Rule, "id"); 21872 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind"); 21873 foreach my $Prop (@Properties) { 21874 if(my $Value = parseTag(\$Rule, lc($Prop))) 21875 { 21876 $Value=~s/\n[ ]*//; 21877 $CompatRules{$Kind}{$RId}{$Prop} = $Value; 21878 } 21879 } 21880 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) { 21881 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols"; 21882 } 21883 else { 21884 $CompatRules{$Kind}{$RId}{"Kind"} = "Types"; 21885 } 21886 } 21887} 21888 21889sub getReportPath($) 21890{ 21891 my $Level = $_[0]; 21892 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"}; 21893 if($Level eq "Binary") 21894 { 21895 if($BinaryReportPath) 21896 { # --bin-report-path 21897 return $BinaryReportPath; 21898 } 21899 elsif($OutputReportPath) 21900 { # --report-path 21901 return $OutputReportPath; 21902 } 21903 else 21904 { # default 21905 return $Dir."/abi_compat_report.$ReportFormat"; 21906 } 21907 } 21908 elsif($Level eq "Source") 21909 { 21910 if($SourceReportPath) 21911 { # --src-report-path 21912 return $SourceReportPath; 21913 } 21914 elsif($OutputReportPath) 21915 { # --report-path 21916 return $OutputReportPath; 21917 } 21918 else 21919 { # default 21920 return $Dir."/src_compat_report.$ReportFormat"; 21921 } 21922 } 21923 else 21924 { 21925 if($OutputReportPath) 21926 { # --report-path 21927 return $OutputReportPath; 21928 } 21929 else 21930 { # default 21931 return $Dir."/compat_report.$ReportFormat"; 21932 } 21933 } 21934} 21935 21936sub printStatMsg($) 21937{ 21938 my $Level = $_[0]; 21939 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"}); 21940} 21941 21942sub listAffected($) 21943{ 21944 my $Level = $_[0]; 21945 my $List = ""; 21946 foreach (keys(%{$TotalAffected{$Level}})) 21947 { 21948 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low") 21949 { # skip "Low"-severity problems 21950 next; 21951 } 21952 $List .= "$_\n"; 21953 } 21954 my $Dir = get_dirname(getReportPath($Level)); 21955 if($Level eq "Binary") { 21956 writeFile($Dir."/abi_affected.txt", $List); 21957 } 21958 elsif($Level eq "Source") { 21959 writeFile($Dir."/src_affected.txt", $List); 21960 } 21961} 21962 21963sub printReport() 21964{ 21965 printMsg("INFO", "creating compatibility report ..."); 21966 createReport(); 21967 if($JoinReport or $DoubleReport) 21968 { 21969 if($RESULT{"Binary"}{"Problems"} 21970 or $RESULT{"Source"}{"Problems"}) { 21971 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)"); 21972 } 21973 else { 21974 printMsg("INFO", "result: COMPATIBLE"); 21975 } 21976 printStatMsg("Binary"); 21977 printStatMsg("Source"); 21978 if($ListAffected) 21979 { # --list-affected 21980 listAffected("Binary"); 21981 listAffected("Source"); 21982 } 21983 } 21984 elsif($BinaryOnly) 21985 { 21986 if($RESULT{"Binary"}{"Problems"}) { 21987 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)"); 21988 } 21989 else { 21990 printMsg("INFO", "result: COMPATIBLE"); 21991 } 21992 printStatMsg("Binary"); 21993 if($ListAffected) 21994 { # --list-affected 21995 listAffected("Binary"); 21996 } 21997 } 21998 elsif($SourceOnly) 21999 { 22000 if($RESULT{"Source"}{"Problems"}) { 22001 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)"); 22002 } 22003 else { 22004 printMsg("INFO", "result: COMPATIBLE"); 22005 } 22006 printStatMsg("Source"); 22007 if($ListAffected) 22008 { # --list-affected 22009 listAffected("Source"); 22010 } 22011 } 22012 if($StdOut) 22013 { 22014 if($JoinReport or not $DoubleReport) 22015 { # --binary or --source 22016 printMsg("INFO", "compatibility report has been generated to stdout"); 22017 } 22018 else 22019 { # default 22020 printMsg("INFO", "compatibility reports have been generated to stdout"); 22021 } 22022 } 22023 else 22024 { 22025 if($JoinReport) 22026 { 22027 printMsg("INFO", "see detailed report:\n ".getReportPath("Join")); 22028 } 22029 elsif($DoubleReport) 22030 { # default 22031 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source")); 22032 } 22033 elsif($BinaryOnly) 22034 { # --binary 22035 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary")); 22036 } 22037 elsif($SourceOnly) 22038 { # --source 22039 printMsg("INFO", "see detailed report:\n ".getReportPath("Source")); 22040 } 22041 } 22042} 22043 22044sub check_win32_env() 22045{ 22046 if(not $ENV{"VCINSTALLDIR"} 22047 or not $ENV{"INCLUDE"}) { 22048 exitStatus("Error", "can't start without VC environment (vcvars64.bat)"); 22049 } 22050} 22051 22052sub diffSets($$) 22053{ 22054 my ($S1, $S2) = @_; 22055 my @SK1 = keys(%{$S1}); 22056 my @SK2 = keys(%{$S2}); 22057 if($#SK1!=$#SK2) { 22058 return 1; 22059 } 22060 foreach my $K1 (@SK1) 22061 { 22062 if(not defined $S2->{$K1}) { 22063 return 1; 22064 } 22065 } 22066 return 0; 22067} 22068 22069sub defaultDumpPath($$) 22070{ 22071 my ($N, $V) = @_; 22072 return "abi_dumps/".$N."/".$N."_".$V.".abi.".$AR_EXT; # gzipped by default 22073} 22074 22075sub create_ABI_Dump() 22076{ 22077 if(not -e $DumpAPI) { 22078 exitStatus("Access_Error", "can't access \'$DumpAPI\'"); 22079 } 22080 22081 if(isDump($DumpAPI)) { 22082 read_ABI_Dump(1, $DumpAPI); 22083 } 22084 else { 22085 readDescriptor(1, createDescriptor(1, $DumpAPI)); 22086 } 22087 22088 if(not $Descriptor{1}{"Version"}) 22089 { # set to default: N 22090 $Descriptor{1}{"Version"} = "N"; 22091 } 22092 22093 initLogging(1); 22094 detect_default_paths("inc|lib|bin|gcc"); # complete analysis 22095 22096 my $DumpPath = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 22097 if($OutputDumpPath) 22098 { # user defined path 22099 $DumpPath = $OutputDumpPath; 22100 } 22101 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g); 22102 22103 if(not $Archive and not $StdOut) 22104 { # check archive utilities 22105 if($OSgroup eq "windows") 22106 { # using zip 22107 my $ZipCmd = get_CmdPath("zip"); 22108 if(not $ZipCmd) { 22109 exitStatus("Not_Found", "can't find \"zip\""); 22110 } 22111 } 22112 else 22113 { # using tar and gzip 22114 my $TarCmd = get_CmdPath("tar"); 22115 if(not $TarCmd) { 22116 exitStatus("Not_Found", "can't find \"tar\""); 22117 } 22118 my $GzipCmd = get_CmdPath("gzip"); 22119 if(not $GzipCmd) { 22120 exitStatus("Not_Found", "can't find \"gzip\""); 22121 } 22122 } 22123 } 22124 22125 if(not $Descriptor{1}{"Dump"}) 22126 { 22127 if(not $CheckHeadersOnly) { 22128 readLibs(1); 22129 } 22130 if($CheckHeadersOnly) { 22131 setLanguage(1, "C++"); 22132 } 22133 searchForHeaders(1); 22134 $WORD_SIZE{1} = detectWordSize(1); 22135 } 22136 if(not $Descriptor{1}{"Dump"}) 22137 { 22138 if($Descriptor{1}{"Headers"}) { 22139 readHeaders(1); 22140 } 22141 } 22142 cleanDump(1); 22143 if(not keys(%{$SymbolInfo{1}})) 22144 { # check if created dump is valid 22145 if(not $ExtendedCheck) 22146 { 22147 if($CheckHeadersOnly) { 22148 exitStatus("Empty_Set", "the set of public symbols is empty"); 22149 } 22150 else { 22151 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection"); 22152 } 22153 } 22154 } 22155 my %HeadersInfo = (); 22156 foreach my $HPath (keys(%{$Registered_Headers{1}})) { 22157 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"}; 22158 } 22159 if($ExtraDump) 22160 { # add unmangled names to the ABI dump 22161 my @Names = (); 22162 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 22163 { 22164 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) { 22165 push(@Names, $MnglName); 22166 } 22167 } 22168 translateSymbols(@Names, 1); 22169 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 22170 { 22171 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) 22172 { 22173 if(my $Unmangled = $tr_name{$MnglName}) 22174 { 22175 if($MnglName ne $Unmangled) { 22176 $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled; 22177 } 22178 } 22179 } 22180 } 22181 } 22182 22183 my %GccConstants = (); # built-in GCC constants 22184 foreach my $Name (keys(%{$Constants{1}})) 22185 { 22186 if(not defined $Constants{1}{$Name}{"Header"}) 22187 { 22188 $GccConstants{$Name} = $Constants{1}{$Name}{"Value"}; 22189 delete($Constants{1}{$Name}); 22190 } 22191 } 22192 22193 printMsg("INFO", "creating library ABI dump ..."); 22194 my %ABI = ( 22195 "TypeInfo" => $TypeInfo{1}, 22196 "SymbolInfo" => $SymbolInfo{1}, 22197 "Symbols" => $Library_Symbol{1}, 22198 "DepSymbols" => $DepLibrary_Symbol{1}, 22199 "SymbolVersion" => $SymVer{1}, 22200 "LibraryVersion" => $Descriptor{1}{"Version"}, 22201 "LibraryName" => $TargetLibraryName, 22202 "Language" => $COMMON_LANGUAGE{1}, 22203 "SkipTypes" => $SkipTypes{1}, 22204 "SkipSymbols" => $SkipSymbols{1}, 22205 "SkipNameSpaces" => $SkipNameSpaces{1}, 22206 "SkipHeaders" => $SkipHeadersList{1}, 22207 "Headers" => \%HeadersInfo, 22208 "Constants" => $Constants{1}, 22209 "GccConstants" => \%GccConstants, 22210 "NameSpaces" => $NestedNameSpaces{1}, 22211 "Target" => $OStarget, 22212 "Arch" => getArch(1), 22213 "WordSize" => $WORD_SIZE{1}, 22214 "GccVersion" => get_dumpversion($GCC_PATH), 22215 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION, 22216 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION 22217 ); 22218 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) { 22219 $ABI{"TargetHeaders"} = $TargetHeaders{1}; 22220 } 22221 if($UseXML) { 22222 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION; 22223 } 22224 if($ExtendedCheck) 22225 { # --ext option 22226 $ABI{"Mode"} = "Extended"; 22227 } 22228 if($BinaryOnly) 22229 { # --binary 22230 $ABI{"BinOnly"} = 1; 22231 } 22232 if($ExtraDump) 22233 { # --extra-dump 22234 $ABI{"Extra"} = 1; 22235 $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1}; 22236 $ABI{"Needed"} = $Library_Needed{1}; 22237 } 22238 22239 my $ABI_DUMP = ""; 22240 if($UseXML) 22241 { 22242 loadModule("XmlDump"); 22243 $ABI_DUMP = createXmlDump(\%ABI); 22244 } 22245 else 22246 { # default 22247 $ABI_DUMP = Dumper(\%ABI); 22248 } 22249 if($StdOut) 22250 { # --stdout option 22251 print STDOUT $ABI_DUMP; 22252 printMsg("INFO", "ABI dump has been generated to stdout"); 22253 return; 22254 } 22255 else 22256 { # write to gzipped file 22257 my ($DDir, $DName) = separate_path($DumpPath); 22258 my $DPath = $TMP_DIR."/".$DName; 22259 if(not $Archive) { 22260 $DPath = $DumpPath; 22261 } 22262 22263 mkpath($DDir); 22264 22265 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n"); 22266 print DUMP $ABI_DUMP; 22267 close(DUMP); 22268 22269 if(not -s $DPath) { 22270 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module"); 22271 } 22272 if($Archive) { 22273 $DumpPath = createArchive($DPath, $DDir); 22274 } 22275 22276 if($OutputDumpPath) { 22277 printMsg("INFO", "dump path: $OutputDumpPath"); 22278 } 22279 else { 22280 printMsg("INFO", "dump path: $DumpPath"); 22281 } 22282 # printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor"); 22283 } 22284} 22285 22286sub quickEmptyReports() 22287{ # Quick "empty" reports 22288 # ~4 times faster than merging equal dumps 22289 # NOTE: the dump contains the "LibraryVersion" attribute 22290 # if you change the version, then your dump will be different 22291 # OVERCOME: use -v1 and v2 options for comparing dumps 22292 # and don't change version in the XML descriptor (and dumps) 22293 # OVERCOME 2: separate meta info from the dumps in ACC 2.0 22294 if($Descriptor{1}{"Path"} eq $Descriptor{2}{"Path"} 22295 or -s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) 22296 { 22297 my $FilePath1 = $Descriptor{1}{"Path"}; 22298 my $FilePath2 = $Descriptor{2}{"Path"}; 22299 22300 if(not isDump_U($FilePath1)) { 22301 $FilePath1 = unpackDump($FilePath1); 22302 } 22303 22304 if(not isDump_U($FilePath2)) { 22305 $FilePath2 = unpackDump($FilePath2); 22306 } 22307 22308 if($FilePath1 and $FilePath2) 22309 { 22310 my $Line = readLineNum($FilePath1, 0); 22311 if($Line=~/xml/) 22312 { # XML format 22313 # is not supported yet 22314 return; 22315 } 22316 22317 local $/ = undef; 22318 22319 open(DUMP1, $FilePath1); 22320 my $Content1 = <DUMP1>; 22321 close(DUMP1); 22322 22323 my $Eq = 0; 22324 22325 if($FilePath1 eq $FilePath2) { 22326 $Eq = 1; 22327 } 22328 22329 if(not $Eq) 22330 { 22331 open(DUMP2, $FilePath2); 22332 my $Content2 = <DUMP2>; 22333 close(DUMP2); 22334 22335 if($Content1 eq $Content2) { 22336 $Eq = 1; 22337 } 22338 22339 # clean memory 22340 undef $Content2; 22341 } 22342 22343 if($Eq) 22344 { 22345 printMsg("INFO", "Input ABI dumps are equal, so generating quick empty report"); 22346 # read a number of headers, libs, symbols and types 22347 my $ABIdump = eval($Content1); 22348 22349 # clean memory 22350 undef $Content1; 22351 22352 if(not $ABIdump) { 22353 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 22354 } 22355 if(not $ABIdump->{"TypeInfo"}) 22356 { # support for old dumps 22357 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"}; 22358 } 22359 if(not $ABIdump->{"SymbolInfo"}) 22360 { # support for old dumps 22361 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"}; 22362 } 22363 read_Source_DumpInfo($ABIdump, 1); 22364 22365 foreach (keys(%{$Registered_Headers{1}})) { 22366 $TargetHeaders{1}{$_} = 1; 22367 } 22368 22369 read_Libs_DumpInfo($ABIdump, 1); 22370 read_Machine_DumpInfo($ABIdump, 1); 22371 read_Machine_DumpInfo($ABIdump, 2); 22372 22373 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}}; 22374 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}}; 22375 22376 foreach my $S (keys(%{$ABIdump->{"SymbolInfo"}})) 22377 { 22378 if(my $Class = $ABIdump->{"SymbolInfo"}{$S}{"Class"}) 22379 { 22380 if(defined $ABIdump->{"TypeInfo"}{$Class}{"PrivateABI"}) { 22381 next; 22382 } 22383 } 22384 22385 my $Access = $ABIdump->{"SymbolInfo"}{$S}{"Access"}; 22386 if($Access ne "private") 22387 { 22388 $CheckedSymbols{"Binary"}{$S} = 1; 22389 $CheckedSymbols{"Source"}{$S} = 1; 22390 } 22391 } 22392 22393 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"}; 22394 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"}; 22395 22396 if(not defined $Descriptor{1}{"Version"}) { 22397 $Descriptor{1}{"Version"} = "X"; 22398 } 22399 22400 if(not defined $Descriptor{2}{"Version"}) { 22401 $Descriptor{2}{"Version"} = "Y"; 22402 } 22403 22404 if(defined $ABIdump->{"ABI_DUMPER_VERSION"}) 22405 { 22406 $UsedDump{1}{"DWARF"} = 1; 22407 $UsedDump{2}{"DWARF"} = 1; 22408 22409 $UsedDump{1}{"M"} = $ABIdump->{"LibraryName"}; 22410 $UsedDump{2}{"M"} = $ABIdump->{"LibraryName"}; 22411 } 22412 22413 exitReport(); 22414 } 22415 } 22416 } 22417} 22418 22419sub initLogging($) 22420{ 22421 my $LibVersion = $_[0]; 22422 # create log directory 22423 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt"); 22424 if($OutputLogPath{$LibVersion}) 22425 { # user-defined by -log-path option 22426 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion}); 22427 } 22428 if($LogMode ne "n") { 22429 mkpath($LOG_DIR); 22430 } 22431 $LOG_PATH{$LibVersion} = join_P(get_abs_path($LOG_DIR), $LOG_FILE); 22432 if($Debug) 22433 { # debug directory 22434 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}; 22435 22436 if(not $ExtraInfo) 22437 { # enable --extra-info 22438 $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info"; 22439 } 22440 } 22441 resetLogging($LibVersion); 22442} 22443 22444sub writeLog($$) 22445{ 22446 my ($LibVersion, $Msg) = @_; 22447 if($LogMode ne "n") { 22448 appendFile($LOG_PATH{$LibVersion}, $Msg); 22449 } 22450} 22451 22452sub resetLogging($) 22453{ 22454 my $LibVersion = $_[0]; 22455 if($LogMode!~/a|n/) 22456 { # remove old log 22457 unlink($LOG_PATH{$LibVersion}); 22458 if($Debug) { 22459 rmtree($DEBUG_PATH{$LibVersion}); 22460 } 22461 } 22462} 22463 22464sub printErrorLog($) 22465{ 22466 my $LibVersion = $_[0]; 22467 if($LogMode ne "n") { 22468 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n"); 22469 } 22470} 22471 22472sub isDump($) 22473{ # Modified to include "bdump" - binary dump. 22474 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump|bdump)(\.tar\.gz(\.\w+|)|\.zip|\.xml|)\Z/) 22475 { # NOTE: name.abi.tar.gz.amd64 (dh & cdbs) 22476 return $1; 22477 } 22478 return 0; 22479} 22480 22481sub isDump_U($) 22482{ # Modified to include "bdump" - binary dump. 22483 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump|bdump)(\.xml|)\Z/) { 22484 return $1; 22485 } 22486 return 0; 22487} 22488 22489sub compareInit() 22490{ 22491 # read input XML descriptors or ABI dumps 22492 if(not $Descriptor{1}{"Path"}) { 22493 exitStatus("Error", "-old option is not specified"); 22494 } 22495 if(not -e $Descriptor{1}{"Path"}) { 22496 exitStatus("Access_Error", "can't access \'".$Descriptor{1}{"Path"}."\'"); 22497 } 22498 22499 if(not $Descriptor{2}{"Path"}) { 22500 exitStatus("Error", "-new option is not specified"); 22501 } 22502 if(not -e $Descriptor{2}{"Path"}) { 22503 exitStatus("Access_Error", "can't access \'".$Descriptor{2}{"Path"}."\'"); 22504 } 22505 22506 detect_default_paths("bin"); # to extract dumps 22507 22508 if(not defined $DisableQuickEmptyReport) 22509 { 22510 if(isDump($Descriptor{1}{"Path"}) 22511 and isDump($Descriptor{2}{"Path"})) 22512 { # optimization: equal ABI dumps 22513 quickEmptyReports(); 22514 } 22515 } 22516 22517 printMsg("INFO", "preparation, please wait ..."); 22518 22519 if(isDump($Descriptor{1}{"Path"})) { 22520 read_ABI_Dump(1, $Descriptor{1}{"Path"}); 22521 } 22522 else { 22523 readDescriptor(1, createDescriptor(1, $Descriptor{1}{"Path"})); 22524 } 22525 22526 if(isDump($Descriptor{2}{"Path"})) { 22527 read_ABI_Dump(2, $Descriptor{2}{"Path"}); 22528 } 22529 else { 22530 readDescriptor(2, createDescriptor(2, $Descriptor{2}{"Path"})); 22531 } 22532 22533 if(not $Descriptor{1}{"Version"}) 22534 { # set to default: X 22535 $Descriptor{1}{"Version"} = "X"; 22536 print STDERR "WARNING: version number #1 is not set (use --v1=NUM option)\n"; 22537 } 22538 22539 if(not $Descriptor{2}{"Version"}) 22540 { # set to default: Y 22541 $Descriptor{2}{"Version"} = "Y"; 22542 print STDERR "WARNING: version number #2 is not set (use --v2=NUM option)\n"; 22543 } 22544 22545 if(not $UsedDump{1}{"V"}) { 22546 initLogging(1); 22547 } 22548 22549 if(not $UsedDump{2}{"V"}) { 22550 initLogging(2); 22551 } 22552 22553 # check input data 22554 if(not $Descriptor{1}{"Headers"}) { 22555 exitStatus("Error", "can't find header files info in descriptor d1"); 22556 } 22557 if(not $Descriptor{2}{"Headers"}) { 22558 exitStatus("Error", "can't find header files info in descriptor d2"); 22559 } 22560 22561 if(not $CheckHeadersOnly) 22562 { 22563 if(not $Descriptor{1}{"Libs"}) { 22564 exitStatus("Error", "can't find libraries info in descriptor d1"); 22565 } 22566 if(not $Descriptor{2}{"Libs"}) { 22567 exitStatus("Error", "can't find libraries info in descriptor d2"); 22568 } 22569 } 22570 22571 if($UseDumps) 22572 { # --use-dumps 22573 # parallel processing 22574 my $DumpPath1 = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 22575 my $DumpPath2 = defaultDumpPath($TargetLibraryName, $Descriptor{2}{"Version"}); 22576 22577 unlink($DumpPath1); 22578 unlink($DumpPath2); 22579 22580 my $pid = fork(); 22581 if($pid) 22582 { # dump on two CPU cores 22583 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName); 22584 if($RelativeDirectory{1}) { 22585 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1}); 22586 } 22587 if($OutputLogPath{1}) { 22588 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1}); 22589 } 22590 if($CrossGcc) { 22591 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22592 } 22593 if($Quiet) 22594 { 22595 @PARAMS = (@PARAMS, "-quiet"); 22596 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22597 } 22598 elsif($LogMode and $LogMode ne "w") 22599 { # "w" is default 22600 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22601 } 22602 if($ExtendedCheck) { 22603 @PARAMS = (@PARAMS, "-extended"); 22604 } 22605 if($UserLang) { 22606 @PARAMS = (@PARAMS, "-lang", $UserLang); 22607 } 22608 if($TargetVersion{1}) { 22609 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1}); 22610 } 22611 if($BinaryOnly) { 22612 @PARAMS = (@PARAMS, "-binary"); 22613 } 22614 if($SourceOnly) { 22615 @PARAMS = (@PARAMS, "-source"); 22616 } 22617 if($SortDump) { 22618 @PARAMS = (@PARAMS, "-sort"); 22619 } 22620 if($DumpFormat and $DumpFormat ne "perl") { 22621 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22622 } 22623 if($CheckHeadersOnly) { 22624 @PARAMS = (@PARAMS, "-headers-only"); 22625 } 22626 if($Debug) 22627 { 22628 @PARAMS = (@PARAMS, "-debug"); 22629 printMsg("INFO", "running perl $0 @PARAMS"); 22630 } 22631 system("perl", $0, @PARAMS); 22632 if(not -f $DumpPath1) { 22633 exit(1); 22634 } 22635 } 22636 else 22637 { # child 22638 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName); 22639 if($RelativeDirectory{2}) { 22640 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2}); 22641 } 22642 if($OutputLogPath{2}) { 22643 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2}); 22644 } 22645 if($CrossGcc) { 22646 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22647 } 22648 if($Quiet) 22649 { 22650 @PARAMS = (@PARAMS, "-quiet"); 22651 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22652 } 22653 elsif($LogMode and $LogMode ne "w") 22654 { # "w" is default 22655 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22656 } 22657 if($ExtendedCheck) { 22658 @PARAMS = (@PARAMS, "-extended"); 22659 } 22660 if($UserLang) { 22661 @PARAMS = (@PARAMS, "-lang", $UserLang); 22662 } 22663 if($TargetVersion{2}) { 22664 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2}); 22665 } 22666 if($BinaryOnly) { 22667 @PARAMS = (@PARAMS, "-binary"); 22668 } 22669 if($SourceOnly) { 22670 @PARAMS = (@PARAMS, "-source"); 22671 } 22672 if($SortDump) { 22673 @PARAMS = (@PARAMS, "-sort"); 22674 } 22675 if($DumpFormat and $DumpFormat ne "perl") { 22676 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22677 } 22678 if($CheckHeadersOnly) { 22679 @PARAMS = (@PARAMS, "-headers-only"); 22680 } 22681 if($Debug) 22682 { 22683 @PARAMS = (@PARAMS, "-debug"); 22684 printMsg("INFO", "running perl $0 @PARAMS"); 22685 } 22686 system("perl", $0, @PARAMS); 22687 if(not -f $DumpPath2) { 22688 exit(1); 22689 } 22690 else { 22691 exit(0); 22692 } 22693 } 22694 waitpid($pid, 0); 22695 22696 my @CMP_PARAMS = ("-l", $TargetLibraryName); 22697 @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1); 22698 @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2); 22699 if($TargetTitle ne $TargetLibraryName) { 22700 @CMP_PARAMS = (@CMP_PARAMS, "-title", $TargetTitle); 22701 } 22702 if($ShowRetVal) { 22703 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval"); 22704 } 22705 if($CrossGcc) { 22706 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc); 22707 } 22708 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a"); 22709 if($Quiet) { 22710 @CMP_PARAMS = (@CMP_PARAMS, "-quiet"); 22711 } 22712 if($ReportFormat and $ReportFormat ne "html") 22713 { # HTML is default format 22714 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat); 22715 } 22716 if($OutputReportPath) { 22717 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath); 22718 } 22719 if($BinaryReportPath) { 22720 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath); 22721 } 22722 if($SourceReportPath) { 22723 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath); 22724 } 22725 if($LoggingPath) { 22726 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath); 22727 } 22728 if($CheckHeadersOnly) { 22729 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only"); 22730 } 22731 if($BinaryOnly) { 22732 @CMP_PARAMS = (@CMP_PARAMS, "-binary"); 22733 } 22734 if($SourceOnly) { 22735 @CMP_PARAMS = (@CMP_PARAMS, "-source"); 22736 } 22737 if($Debug) 22738 { 22739 @CMP_PARAMS = (@CMP_PARAMS, "-debug"); 22740 printMsg("INFO", "running perl $0 @CMP_PARAMS"); 22741 } 22742 system("perl", $0, @CMP_PARAMS); 22743 exit($?>>8); 22744 } 22745 if(not $Descriptor{1}{"Dump"} 22746 or not $Descriptor{2}{"Dump"}) 22747 { # need GCC toolchain to analyze 22748 # header files and libraries 22749 detect_default_paths("inc|lib|gcc"); 22750 } 22751 if(not $Descriptor{1}{"Dump"}) 22752 { 22753 if(not $CheckHeadersOnly) { 22754 readLibs(1); 22755 } 22756 if($CheckHeadersOnly) { 22757 setLanguage(1, "C++"); 22758 } 22759 searchForHeaders(1); 22760 $WORD_SIZE{1} = detectWordSize(1); 22761 } 22762 if(not $Descriptor{2}{"Dump"}) 22763 { 22764 if(not $CheckHeadersOnly) { 22765 readLibs(2); 22766 } 22767 if($CheckHeadersOnly) { 22768 setLanguage(2, "C++"); 22769 } 22770 searchForHeaders(2); 22771 $WORD_SIZE{2} = detectWordSize(2); 22772 } 22773 if($WORD_SIZE{1} ne $WORD_SIZE{2}) 22774 { # support for old ABI dumps 22775 # try to synch different WORD sizes 22776 if(not checkDump(1, "2.1")) 22777 { 22778 $WORD_SIZE{1} = $WORD_SIZE{2}; 22779 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes"); 22780 } 22781 elsif(not checkDump(2, "2.1")) 22782 { 22783 $WORD_SIZE{2} = $WORD_SIZE{1}; 22784 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes"); 22785 } 22786 } 22787 elsif(not $WORD_SIZE{1} 22788 and not $WORD_SIZE{2}) 22789 { # support for old ABI dumps 22790 $WORD_SIZE{1} = "4"; 22791 $WORD_SIZE{2} = "4"; 22792 } 22793 if($Descriptor{1}{"Dump"}) 22794 { # support for old ABI dumps 22795 prepareTypes(1); 22796 } 22797 if($Descriptor{2}{"Dump"}) 22798 { # support for old ABI dumps 22799 prepareTypes(2); 22800 } 22801 if($AppPath and not keys(%{$Symbol_Library{1}})) { 22802 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries"); 22803 } 22804 # process input data 22805 if($Descriptor{1}{"Headers"} 22806 and not $Descriptor{1}{"Dump"}) { 22807 readHeaders(1); 22808 } 22809 if($Descriptor{2}{"Headers"} 22810 and not $Descriptor{2}{"Dump"}) { 22811 readHeaders(2); 22812 } 22813 22814 # clean memory 22815 %SystemHeaders = (); 22816 %mangled_name_gcc = (); 22817 22818 prepareSymbols(1); 22819 prepareSymbols(2); 22820 22821 # clean memory 22822 %SymbolInfo = (); 22823 22824 # Virtual Tables 22825 registerVTable(1); 22826 registerVTable(2); 22827 22828 if(not checkDump(1, "1.22") 22829 and checkDump(2, "1.22")) 22830 { # support for old ABI dumps 22831 foreach my $ClassName (keys(%{$VirtualTable{2}})) 22832 { 22833 if($ClassName=~/</) 22834 { # templates 22835 if(not defined $VirtualTable{1}{$ClassName}) 22836 { # synchronize 22837 delete($VirtualTable{2}{$ClassName}); 22838 } 22839 } 22840 } 22841 } 22842 22843 registerOverriding(1); 22844 registerOverriding(2); 22845 22846 setVirtFuncPositions(1); 22847 setVirtFuncPositions(2); 22848 22849 # Other 22850 addParamNames(1); 22851 addParamNames(2); 22852 22853 detectChangedTypedefs(); 22854} 22855 22856sub compareAPIs($) 22857{ 22858 my $Level = $_[0]; 22859 22860 readRules($Level); 22861 loadModule("CallConv"); 22862 22863 if($Level eq "Binary") { 22864 printMsg("INFO", "comparing ABIs ..."); 22865 } 22866 else { 22867 printMsg("INFO", "comparing APIs ..."); 22868 } 22869 22870 if($CheckHeadersOnly 22871 or $Level eq "Source") 22872 { # added/removed in headers 22873 detectAdded_H($Level); 22874 detectRemoved_H($Level); 22875 } 22876 else 22877 { # added/removed in libs 22878 detectAdded($Level); 22879 detectRemoved($Level); 22880 } 22881 22882 mergeSymbols($Level); 22883 22884 if(not defined $DisableConstantsCheck) 22885 { 22886 if(keys(%{$CheckedSymbols{$Level}})) { 22887 mergeConstants($Level); 22888 } 22889 } 22890 22891 $Cache{"mergeTypes"} = (); # free memory 22892 22893 if($CheckHeadersOnly 22894 or $Level eq "Source") 22895 { # added/removed in headers 22896 mergeHeaders($Level); 22897 } 22898 else 22899 { # added/removed in libs 22900 mergeLibs($Level); 22901 } 22902 22903 foreach my $S (keys(%{$CompatProblems{$Level}})) 22904 { 22905 foreach my $K (keys(%{$CompatProblems{$Level}{$S}})) 22906 { 22907 foreach my $L (keys(%{$CompatProblems{$Level}{$S}{$K}})) 22908 { 22909 if(my $T = $CompatProblems{$Level}{$S}{$K}{$L}{"Type_Name"}) { 22910 $TypeProblemsIndex{$Level}{$T}{$S} = 1; 22911 } 22912 } 22913 } 22914 } 22915} 22916 22917sub getSysOpts() 22918{ 22919 my %Opts = ( 22920 "OStarget"=>$OStarget, 22921 "Debug"=>$Debug, 22922 "Quiet"=>$Quiet, 22923 "LogMode"=>$LogMode, 22924 "CheckHeadersOnly"=>$CheckHeadersOnly, 22925 22926 "SystemRoot"=>$SystemRoot, 22927 "GCC_PATH"=>$GCC_PATH, 22928 "TargetSysInfo"=>$TargetSysInfo, 22929 "CrossPrefix"=>$CrossPrefix, 22930 "TargetLibraryName"=>$TargetLibraryName, 22931 "CrossGcc"=>$CrossGcc, 22932 "UseStaticLibs"=>$UseStaticLibs, 22933 "NoStdInc"=>$NoStdInc, 22934 "CxxIncompat"=>$CxxIncompat, 22935 "SkipUnidentified"=>$SkipUnidentified, 22936 "DisableConstantsCheck"=>$DisableConstantsCheck, 22937 22938 "BinaryOnly" => $BinaryOnly, 22939 "SourceOnly" => $SourceOnly 22940 ); 22941 return \%Opts; 22942} 22943 22944sub get_CodeError($) 22945{ 22946 my %CODE_ERROR = reverse(%ERROR_CODE); 22947 return $CODE_ERROR{$_[0]}; 22948} 22949 22950sub scenario() 22951{ 22952 if($StdOut) 22953 { # enable quiet mode 22954 $Quiet = 1; 22955 $JoinReport = 1; 22956 } 22957 if(not $LogMode) 22958 { # default 22959 $LogMode = "w"; 22960 } 22961 if($UserLang) 22962 { # --lang=C++ 22963 $UserLang = uc($UserLang); 22964 $COMMON_LANGUAGE{1}=$UserLang; 22965 $COMMON_LANGUAGE{2}=$UserLang; 22966 } 22967 if($LoggingPath) 22968 { 22969 $OutputLogPath{1} = $LoggingPath; 22970 $OutputLogPath{2} = $LoggingPath; 22971 if($Quiet) { 22972 $COMMON_LOG_PATH = $LoggingPath; 22973 } 22974 } 22975 22976 if($Force) { 22977 $GCC_MISSED_MNGL = 1; 22978 } 22979 22980 if($Quick) { 22981 $ADD_TMPL_INSTANCES = 0; 22982 } 22983 if($OutputDumpPath) 22984 { # validate 22985 if(not isDump($OutputDumpPath)) { 22986 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file"); 22987 } 22988 } 22989 if($BinaryOnly and $SourceOnly) 22990 { # both --binary and --source 22991 # is the default mode 22992 if(not $CmpSystems) 22993 { 22994 $BinaryOnly = 0; 22995 $SourceOnly = 0; 22996 } 22997 22998 $DoubleReport = 1; 22999 $JoinReport = 0; 23000 23001 if($OutputReportPath) 23002 { # --report-path 23003 $DoubleReport = 0; 23004 $JoinReport = 1; 23005 } 23006 } 23007 elsif($BinaryOnly or $SourceOnly) 23008 { # --binary or --source 23009 $DoubleReport = 0; 23010 $JoinReport = 0; 23011 } 23012 if($UseXML) 23013 { # --xml option 23014 $ReportFormat = "xml"; 23015 $DumpFormat = "xml"; 23016 } 23017 if($ReportFormat) 23018 { # validate 23019 $ReportFormat = lc($ReportFormat); 23020 if($ReportFormat!~/\A(xml|html|htm)\Z/) { 23021 exitStatus("Error", "unknown report format \'$ReportFormat\'"); 23022 } 23023 if($ReportFormat eq "htm") 23024 { # HTM == HTML 23025 $ReportFormat = "html"; 23026 } 23027 elsif($ReportFormat eq "xml") 23028 { # --report-format=XML equal to --xml 23029 $UseXML = 1; 23030 } 23031 } 23032 else 23033 { # default: HTML 23034 $ReportFormat = "html"; 23035 } 23036 if($DumpFormat) 23037 { # validate 23038 $DumpFormat = lc($DumpFormat); 23039 if($DumpFormat!~/\A(xml|perl)\Z/) { 23040 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'"); 23041 } 23042 if($DumpFormat eq "xml") 23043 { # --dump-format=XML equal to --xml 23044 $UseXML = 1; 23045 } 23046 } 23047 else 23048 { # default: Perl Data::Dumper 23049 $DumpFormat = "perl"; 23050 } 23051 if($Quiet and $LogMode!~/a|n/) 23052 { # --quiet log 23053 if(-f $COMMON_LOG_PATH) { 23054 unlink($COMMON_LOG_PATH); 23055 } 23056 } 23057 if($ExtraInfo) { 23058 $CheckUndefined = 1; 23059 } 23060 if($TestTool and $UseDumps) 23061 { # --test && --use-dumps == --test-dump 23062 $TestDump = 1; 23063 } 23064 if($Tolerant) 23065 { # enable all 23066 $Tolerance = 1234; 23067 } 23068 if($Help) 23069 { 23070 HELP_MESSAGE(); 23071 exit(0); 23072 } 23073 if($InfoMsg) 23074 { 23075 INFO_MESSAGE(); 23076 exit(0); 23077 } 23078 if($ShowVersion) 23079 { 23080 printMsg("INFO", "ABI Compliance Checker (ABICC) $TOOL_VERSION\nCopyright (C) 2016 Andrey Ponomarenko's ABI Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko."); 23081 exit(0); 23082 } 23083 if($DumpVersion) 23084 { 23085 printMsg("INFO", $TOOL_VERSION); 23086 exit(0); 23087 } 23088 if($ExtendedCheck) { 23089 $CheckHeadersOnly = 1; 23090 } 23091 if($SystemRoot_Opt) 23092 { # user defined root 23093 if(not -e $SystemRoot_Opt) { 23094 exitStatus("Access_Error", "can't access \'$SystemRoot\'"); 23095 } 23096 $SystemRoot = $SystemRoot_Opt; 23097 $SystemRoot=~s/[\/]+\Z//g; 23098 if($SystemRoot) { 23099 $SystemRoot = get_abs_path($SystemRoot); 23100 } 23101 } 23102 $Data::Dumper::Sortkeys = 1; 23103 23104 if($SortDump) 23105 { 23106 $Data::Dumper::Useperl = 1; 23107 $Data::Dumper::Sortkeys = \&dump_sorting; 23108 } 23109 23110 if($TargetLibsPath) 23111 { 23112 if(not -f $TargetLibsPath) { 23113 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'"); 23114 } 23115 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) 23116 { 23117 if($OSgroup eq "windows") { 23118 $TargetLibs{lc($Lib)} = 1; 23119 } 23120 else { 23121 $TargetLibs{$Lib} = 1; 23122 } 23123 } 23124 } 23125 if($TargetHeadersPath) 23126 { # --headers-list 23127 if(not -f $TargetHeadersPath) { 23128 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'"); 23129 } 23130 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath))) 23131 { 23132 $TargetHeaders{1}{get_filename($Header)} = 1; 23133 $TargetHeaders{2}{get_filename($Header)} = 1; 23134 } 23135 } 23136 if($TargetHeader) 23137 { # --header 23138 $TargetHeaders{1}{get_filename($TargetHeader)} = 1; 23139 $TargetHeaders{2}{get_filename($TargetHeader)} = 1; 23140 } 23141 if($TestABIDumper) 23142 { 23143 if($OSgroup ne "linux") { 23144 exitStatus("Error", "-test-abi-dumper option is available on Linux only"); 23145 } 23146 } 23147 if($TestTool 23148 or $TestDump 23149 or $TestABIDumper) 23150 { # --test, --test-dump 23151 detect_default_paths("bin|gcc"); # to compile libs 23152 loadModule("RegTests"); 23153 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, 23154 $LIB_EXT, $GCC_PATH, $SortDump, $CheckHeadersOnly, $OldStyle, $TestABIDumper); 23155 exit(0); 23156 } 23157 if($DumpSystem) 23158 { # --dump-system 23159 if(-d $MODULES_DIR."/Targets/" 23160 and -d $MODULES_DIR."/Targets/".$OStarget) { 23161 $TargetSysInfo = $MODULES_DIR."/Targets/".$OStarget; 23162 } 23163 if(not $TargetSysInfo) { 23164 exitStatus("Error", "-sysinfo option should be specified to dump system ABI"); 23165 } 23166 23167 if(not -d $TargetSysInfo) { 23168 exitStatus("Access_Error", "can't access \'$TargetSysInfo\'"); 23169 } 23170 23171 loadModule("SysCheck"); 23172 if($DumpSystem=~/\.(xml|desc)\Z/) 23173 { # system XML descriptor 23174 if(not -f $DumpSystem) { 23175 exitStatus("Access_Error", "can't access file \'$DumpSystem\'"); 23176 } 23177 23178 my $SDesc = readFile($DumpSystem); 23179 if(my $RelDir = $RelativeDirectory{1}) { 23180 $SDesc =~ s/{RELPATH}/$RelDir/g; 23181 } 23182 23183 my $Ret = readSystemDescriptor($SDesc); 23184 foreach (@{$Ret->{"Tools"}}) 23185 { 23186 push_U($SystemPaths{"bin"}, $_); 23187 $TargetTools{$_} = 1; 23188 } 23189 if($Ret->{"CrossPrefix"}) { 23190 $CrossPrefix = $Ret->{"CrossPrefix"}; 23191 } 23192 } 23193 elsif($SystemRoot_Opt) 23194 { # -sysroot "/" option 23195 # default target: /usr/lib, /usr/include 23196 # search libs: /usr/lib and /lib 23197 if(not -e $SystemRoot."/usr/lib") { 23198 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'"); 23199 } 23200 if(not -e $SystemRoot."/lib") { 23201 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'"); 23202 } 23203 if(not -e $SystemRoot."/usr/include") { 23204 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'"); 23205 } 23206 readSystemDescriptor(" 23207 <name> 23208 $DumpSystem 23209 </name> 23210 <headers> 23211 $SystemRoot/usr/include 23212 </headers> 23213 <libs> 23214 $SystemRoot/usr/lib 23215 </libs> 23216 <search_libs> 23217 $SystemRoot/lib 23218 </search_libs>"); 23219 } 23220 else { 23221 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\""); 23222 } 23223 detect_default_paths("bin|gcc"); # to check symbols 23224 if($OStarget eq "windows") 23225 { # to run dumpbin.exe 23226 # and undname.exe 23227 check_win32_env(); 23228 } 23229 dumpSystem(getSysOpts()); 23230 exit(0); 23231 } 23232 23233 if($CmpSystems) 23234 { # --cmp-systems 23235 detect_default_paths("bin"); # to extract dumps 23236 loadModule("SysCheck"); 23237 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts()); 23238 exit(0); 23239 } 23240 23241 if(not $CountSymbols) 23242 { 23243 if(not $TargetLibraryName) { 23244 exitStatus("Error", "library name is not selected (-l option)"); 23245 } 23246 else 23247 { # validate library name 23248 if($TargetLibraryName=~/[\*\/\\]/) { 23249 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name"); 23250 } 23251 } 23252 } 23253 23254 if(not $TargetTitle) { 23255 $TargetTitle = $TargetLibraryName; 23256 } 23257 23258 if($SymbolsListPath) 23259 { 23260 if(not -f $SymbolsListPath) { 23261 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'"); 23262 } 23263 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) { 23264 $SymbolsList{$Interface} = 1; 23265 } 23266 } 23267 if($TypesListPath) 23268 { 23269 if(not -f $TypesListPath) { 23270 exitStatus("Access_Error", "can't access file \'$TypesListPath\'"); 23271 } 23272 foreach my $Type (split(/\s*\n\s*/, readFile($TypesListPath))) { 23273 $TypesList{$Type} = 1; 23274 } 23275 } 23276 if($SkipSymbolsListPath) 23277 { 23278 if(not -f $SkipSymbolsListPath) { 23279 exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'"); 23280 } 23281 foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) 23282 { 23283 $SkipSymbols{1}{$Interface} = 1; 23284 $SkipSymbols{2}{$Interface} = 1; 23285 } 23286 } 23287 if($SkipTypesListPath) 23288 { 23289 if(not -f $SkipTypesListPath) { 23290 exitStatus("Access_Error", "can't access file \'$SkipTypesListPath\'"); 23291 } 23292 foreach my $Type (split(/\s*\n\s*/, readFile($SkipTypesListPath))) 23293 { 23294 $SkipTypes{1}{$Type} = 1; 23295 $SkipTypes{2}{$Type} = 1; 23296 } 23297 } 23298 if($SkipHeadersPath) 23299 { 23300 if(not -f $SkipHeadersPath) { 23301 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'"); 23302 } 23303 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath))) 23304 { # register for both versions 23305 $SkipHeadersList{1}{$Path} = 1; 23306 $SkipHeadersList{2}{$Path} = 1; 23307 23308 my ($CPath, $Type) = classifyPath($Path); 23309 $SkipHeaders{1}{$Type}{$CPath} = 1; 23310 $SkipHeaders{2}{$Type}{$CPath} = 1; 23311 } 23312 } 23313 if($ParamNamesPath) 23314 { 23315 if(not -f $ParamNamesPath) { 23316 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'"); 23317 } 23318 foreach my $Line (split(/\n/, readFile($ParamNamesPath))) 23319 { 23320 if($Line=~s/\A(\w+)\;//) 23321 { 23322 my $Interface = $1; 23323 if($Line=~/;(\d+);/) 23324 { 23325 while($Line=~s/(\d+);(\w+)//) { 23326 $AddIntParams{$Interface}{$1}=$2; 23327 } 23328 } 23329 else 23330 { 23331 my $Num = 0; 23332 foreach my $Name (split(/;/, $Line)) { 23333 $AddIntParams{$Interface}{$Num++}=$Name; 23334 } 23335 } 23336 } 23337 } 23338 } 23339 23340 if($AppPath) 23341 { 23342 if(not -f $AppPath) { 23343 exitStatus("Access_Error", "can't access file \'$AppPath\'"); 23344 } 23345 23346 detect_default_paths("bin|gcc"); 23347 foreach my $Interface (readSymbols_App($AppPath)) { 23348 $SymbolsList_App{$Interface} = 1; 23349 } 23350 } 23351 23352 if($CountSymbols) 23353 { 23354 if(not -e $CountSymbols) { 23355 exitStatus("Access_Error", "can't access \'$CountSymbols\'"); 23356 } 23357 23358 read_ABI_Dump(1, $CountSymbols); 23359 23360 foreach my $Id (keys(%{$SymbolInfo{1}})) 23361 { 23362 my $MnglName = $SymbolInfo{1}{$Id}{"MnglName"}; 23363 if(not $MnglName) { 23364 $MnglName = $SymbolInfo{1}{$Id}{"ShortName"} 23365 } 23366 23367 if(my $SV = $SymVer{1}{$MnglName}) { 23368 $CompleteSignature{1}{$SV} = $SymbolInfo{1}{$Id}; 23369 } 23370 else { 23371 $CompleteSignature{1}{$MnglName} = $SymbolInfo{1}{$Id}; 23372 } 23373 23374 if(my $Alias = $CompleteSignature{1}{$MnglName}{"Alias"}) { 23375 $CompleteSignature{1}{$Alias} = $SymbolInfo{1}{$Id}; 23376 } 23377 } 23378 23379 my $Count = 0; 23380 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 23381 { 23382 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) { 23383 next; 23384 } 23385 if($CompleteSignature{1}{$Symbol}{"Private"}) { 23386 next; 23387 } 23388 if(not $CompleteSignature{1}{$Symbol}{"Header"}) { 23389 next; 23390 } 23391 23392 $Count += symbolFilter($Symbol, 1, "Affected + InlineVirt", "Binary"); 23393 } 23394 23395 printMsg("INFO", $Count); 23396 exit(0); 23397 } 23398 23399 if($DumpAPI) 23400 { # --dump-abi 23401 # make an API dump 23402 create_ABI_Dump(); 23403 exit($COMPILE_ERRORS); 23404 } 23405 # default: compare APIs 23406 # -d1 <path> 23407 # -d2 <path> 23408 compareInit(); 23409 if($JoinReport or $DoubleReport) 23410 { 23411 compareAPIs("Binary"); 23412 compareAPIs("Source"); 23413 } 23414 elsif($BinaryOnly) { 23415 compareAPIs("Binary"); 23416 } 23417 elsif($SourceOnly) { 23418 compareAPIs("Source"); 23419 } 23420 exitReport(); 23421} 23422 23423scenario(); 23424