abi-compliance-checker.pl revision 6ed91e7e3638a38533dcceda69075ae1d641770e
1#!/usr/bin/perl 2########################################################################### 3# ABI Compliance Checker (ABICC) 1.99.10 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) 2012-2013 ROSA Laboratory 9# Copyright (C) 2013-2015 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 (5.8 or newer) 23# - Ctags (5.8 or newer) 24# 25# Mac OS X 26# - Xcode (g++, c++filt, otool, nm) 27# - Ctags (5.8 or newer) 28# 29# MS Windows 30# - MinGW (3.0-4.7, 4.8.3, 4.9 or newer) 31# - MS Visual C++ (dumpbin, undname, cl) 32# - Active Perl 5 (5.8 or newer) 33# - Sigcheck v1.71 or newer 34# - Info-ZIP 3.0 (zip, unzip) 35# - Ctags (5.8 or newer) 36# - Add tool locations to the PATH environment variable 37# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\) 38# 39# COMPATIBILITY 40# ============= 41# ABI Dumper >= 0.99.9 42# 43# 44# This program is free software: you can redistribute it and/or modify 45# it under the terms of the GNU General Public License or the GNU Lesser 46# General Public License as published by the Free Software Foundation. 47# 48# This program is distributed in the hope that it will be useful, 49# but WITHOUT ANY WARRANTY; without even the implied warranty of 50# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 51# GNU General Public License for more details. 52# 53# You should have received a copy of the GNU General Public License 54# and the GNU Lesser General Public License along with this program. 55# If not, see <http://www.gnu.org/licenses/>. 56########################################################################### 57use Getopt::Long; 58Getopt::Long::Configure ("posix_default", "no_ignore_case"); 59use File::Path qw(mkpath rmtree); 60use File::Temp qw(tempdir); 61use File::Copy qw(copy move); 62use Cwd qw(abs_path cwd realpath); 63use Storable qw(dclone); 64use Data::Dumper; 65use Config; 66 67my $TOOL_VERSION = "1.99.10"; 68my $ABI_DUMP_VERSION = "3.2"; 69my $XML_REPORT_VERSION = "1.2"; 70my $XML_ABI_DUMP_VERSION = "1.2"; 71my $OSgroup = get_OSgroup(); 72my $ORIG_DIR = cwd(); 73my $TMP_DIR = tempdir(CLEANUP=>1); 74 75# Internal modules 76my $MODULES_DIR = get_Modules(); 77push(@INC, get_dirname($MODULES_DIR)); 78# Rules DB 79my %RULES_PATH = ( 80 "Binary" => $MODULES_DIR."/RulesBin.xml", 81 "Source" => $MODULES_DIR."/RulesSrc.xml"); 82 83my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, 84$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps, 85$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath, 86%RelativeDirectory, $TargetTitle, $TestDump, $LoggingPath, 87%TargetVersion, $InfoMsg, $CrossGcc, %OutputLogPath, 88$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem, 89$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc, 90$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet, 91$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, 92$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, 93$SourceReportPath, $UseXML, $SortDump, $DumpFormat, 94$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, 95$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat, $SkipInternal, 96$TargetArch, $GccOptions, $TypesListPath); 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 = "http://lvc.github.io/abi-compliance-checker/"; 150 151my $ShortUsage = "ABI Compliance Checker (ABICC) $TOOL_VERSION 152A tool for checking backward compatibility of a C/C++ library API 153Copyright (C) 2015 Andrey Ponomarenko's ABI Laboratory 154License: GNU LGPL or GNU GPL 155 156Usage: $CmdName [options] 157Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml 158 159OLD.xml and NEW.xml are XML-descriptors: 160 161 <version> 162 1.0 163 </version> 164 165 <headers> 166 /path/to/headers/ 167 </headers> 168 169 <libs> 170 /path/to/libraries/ 171 </libs> 172 173More info: $CmdName --help\n"; 174 175if($#ARGV==-1) 176{ 177 printMsg("INFO", $ShortUsage); 178 exit(0); 179} 180 181foreach (2 .. $#ARGV) 182{ # correct comma separated options 183 if($ARGV[$_-1] eq ",") 184 { 185 $ARGV[$_-2].=",".$ARGV[$_]; 186 splice(@ARGV, $_-1, 2); 187 } 188 elsif($ARGV[$_-1]=~/,\Z/) 189 { 190 $ARGV[$_-1].=$ARGV[$_]; 191 splice(@ARGV, $_, 1); 192 } 193 elsif($ARGV[$_]=~/\A,/ 194 and $ARGV[$_] ne ",") 195 { 196 $ARGV[$_-1].=$ARGV[$_]; 197 splice(@ARGV, $_, 1); 198 } 199} 200 201GetOptions("h|help!" => \$Help, 202 "i|info!" => \$InfoMsg, 203 "v|version!" => \$ShowVersion, 204 "dumpversion!" => \$DumpVersion, 205# general options 206 "l|lib|library=s" => \$TargetLibraryName, 207 "d1|old|o=s" => \$Descriptor{1}{"Path"}, 208 "d2|new|n=s" => \$Descriptor{2}{"Path"}, 209 "dump|dump-abi|dump_abi=s" => \$DumpAPI, 210# extra options 211 "app|application=s" => \$AppPath, 212 "static-libs!" => \$UseStaticLibs, 213 "gcc-path|cross-gcc=s" => \$CrossGcc, 214 "gcc-prefix|cross-prefix=s" => \$CrossPrefix, 215 "gcc-options=s" => \$GccOptions, 216 "sysroot=s" => \$SystemRoot_Opt, 217 "v1|version1|vnum=s" => \$TargetVersion{1}, 218 "v2|version2=s" => \$TargetVersion{2}, 219 "s|strict!" => \$StrictCompat, 220 "symbols-list=s" => \$SymbolsListPath, 221 "types-list=s" => \$TypesListPath, 222 "skip-symbols=s" => \$SkipSymbolsListPath, 223 "headers-list=s" => \$TargetHeadersPath, 224 "skip-headers=s" => \$SkipHeadersPath, 225 "header=s" => \$TargetHeader, 226 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt, 227 "objects-only!" => \$CheckObjectsOnly_Opt, 228 "show-retval!" => \$ShowRetVal, 229 "use-dumps!" => \$UseDumps, 230 "nostdinc!" => \$NoStdInc, 231 "dump-system=s" => \$DumpSystem, 232 "sysinfo=s" => \$TargetSysInfo, 233 "cmp-systems!" => \$CmpSystems, 234 "libs-list=s" => \$TargetLibsPath, 235 "ext|extended!" => \$ExtendedCheck, 236 "q|quiet!" => \$Quiet, 237 "stdout!" => \$StdOut, 238 "report-format=s" => \$ReportFormat, 239 "dump-format=s" => \$DumpFormat, 240 "xml!" => \$UseXML, 241 "lang=s" => \$UserLang, 242 "arch=s" => \$TargetArch, 243 "binary|bin|abi!" => \$BinaryOnly, 244 "source|src|api!" => \$SourceOnly, 245 "limit-affected|affected-limit=s" => \$AffectLimit, 246# other options 247 "test!" => \$TestTool, 248 "test-dump!" => \$TestDump, 249 "debug!" => \$Debug, 250 "cpp-compatible!" => \$CppCompat, 251 "cpp-incompatible!" => \$CppIncompat, 252 "p|params=s" => \$ParamNamesPath, 253 "relpath1|relpath=s" => \$RelativeDirectory{1}, 254 "relpath2=s" => \$RelativeDirectory{2}, 255 "dump-path=s" => \$OutputDumpPath, 256 "sort!" => \$SortDump, 257 "report-path=s" => \$OutputReportPath, 258 "bin-report-path=s" => \$BinaryReportPath, 259 "src-report-path=s" => \$SourceReportPath, 260 "log-path=s" => \$LoggingPath, 261 "log1-path=s" => \$OutputLogPath{1}, 262 "log2-path=s" => \$OutputLogPath{2}, 263 "logging-mode=s" => \$LogMode, 264 "list-affected!" => \$ListAffected, 265 "title|l-full|lib-full=s" => \$TargetTitle, 266 "component=s" => \$TargetComponent_Opt, 267 "extra-info=s" => \$ExtraInfo, 268 "extra-dump!" => \$ExtraDump, 269 "force!" => \$Force, 270 "tolerance=s" => \$Tolerance, 271 "tolerant!" => \$Tolerant, 272 "check!" => \$CheckInfo, 273 "quick!" => \$Quick, 274 "all-affected!" => \$AllAffected, 275 "skip-internal=s" => \$SkipInternal 276) or ERR_MESSAGE(); 277 278sub ERR_MESSAGE() 279{ 280 printMsg("INFO", "\n".$ShortUsage); 281 exit($ERROR_CODE{"Error"}); 282} 283 284my $LIB_TYPE = $UseStaticLibs?"static":"dynamic"; 285my $SLIB_TYPE = $LIB_TYPE; 286if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic") 287{ # show as "shared" library 288 $SLIB_TYPE = "shared"; 289} 290my $LIB_EXT = getLIB_EXT($OSgroup); 291my $AR_EXT = getAR_EXT($OSgroup); 292my $BYTE_SIZE = 8; 293my $COMMON_LOG_PATH = "logs/run.log"; 294 295my $HelpMessage=" 296NAME: 297 ABI Compliance Checker ($CmdName) 298 Check backward compatibility of a C/C++ library API 299 300DESCRIPTION: 301 ABI Compliance Checker (ABICC) is a tool for checking backward binary and 302 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks 303 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and 304 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary 305 and/or source-level compatibility: changes in calling stack, v-table changes, 306 removed symbols, renamed fields, etc. Binary incompatibility may result in 307 crashing or incorrect behavior of applications built with an old version of 308 a library if they run on a new one. Source incompatibility may result in 309 recompilation errors with a new library version. 310 311 The tool is intended for developers of software libraries and maintainers 312 of operating systems who are interested in ensuring backward compatibility, 313 i.e. allow old applications to run or to be recompiled with newer library 314 versions. 315 316 Also the tool can be used by ISVs for checking applications portability to 317 new library versions. Found issues can be taken into account when adapting 318 the application to a new library version. 319 320 This tool is free software: you can redistribute it and/or modify it 321 under the terms of the GNU LGPL or GNU GPL. 322 323USAGE: 324 $CmdName [options] 325 326EXAMPLE: 327 $CmdName -lib NAME -old OLD.xml -new NEW.xml 328 329 OLD.xml and NEW.xml are XML-descriptors: 330 331 <version> 332 1.0 333 </version> 334 335 <headers> 336 /path1/to/header(s)/ 337 /path2/to/header(s)/ 338 ... 339 </headers> 340 341 <libs> 342 /path1/to/library(ies)/ 343 /path2/to/library(ies)/ 344 ... 345 </libs> 346 347INFORMATION OPTIONS: 348 -h|-help 349 Print this help. 350 351 -i|-info 352 Print complete info. 353 354 -v|-version 355 Print version information. 356 357 -dumpversion 358 Print the tool version ($TOOL_VERSION) and don't do anything else. 359 360GENERAL OPTIONS: 361 -l|-lib|-library NAME 362 Library name (without version). 363 364 -d1|-old|-o PATH 365 Descriptor of 1st (old) library version. 366 It may be one of the following: 367 368 1. XML-descriptor (VERSION.xml file): 369 370 <version> 371 1.0 372 </version> 373 374 <headers> 375 /path1/to/header(s)/ 376 /path2/to/header(s)/ 377 ... 378 </headers> 379 380 <libs> 381 /path1/to/library(ies)/ 382 /path2/to/library(ies)/ 383 ... 384 </libs> 385 386 ... (XML-descriptor template 387 can be generated by -d option) 388 389 2. ABI dump generated by -dump option 390 3. Directory with headers and/or $SLIB_TYPE libraries 391 4. Single header file 392 5. Single $SLIB_TYPE library 393 6. Comma separated list of headers and/or libraries 394 395 If you are using an 2-6 descriptor types then you should 396 specify version numbers with -v1 and -v2 options too. 397 398 For more information, please see: 399 http://ispras.linuxbase.org/index.php/Library_Descriptor 400 401 -d2|-new|-n PATH 402 Descriptor of 2nd (new) library version. 403 404 -dump|-dump-abi PATH 405 Create library ABI dump for the input XML descriptor. You can 406 transfer it anywhere and pass instead of the descriptor. Also 407 it can be used for debugging the tool. 408 409 Supported versions of ABI dump: 2.0<=V<=$ABI_DUMP_VERSION\n"; 410 411sub HELP_MESSAGE() { 412 printMsg("INFO", $HelpMessage." 413MORE INFO: 414 $CmdName --info\n"); 415} 416 417sub INFO_MESSAGE() 418{ 419 printMsg("INFO", "$HelpMessage 420EXTRA OPTIONS: 421 -app|-application PATH 422 This option allows to specify the application that should be checked 423 for portability to the new library version. 424 425 -static-libs 426 Check static libraries instead of the shared ones. The <libs> section 427 of the XML-descriptor should point to static libraries location. 428 429 -cross-gcc|-gcc-path PATH 430 Path to the cross GCC compiler to use instead of the usual (host) GCC. 431 432 -cross-prefix|-gcc-prefix PREFIX 433 GCC toolchain prefix. 434 435 -sysroot DIR 436 Specify the alternative root directory. The tool will search for include 437 paths in the DIR/usr/include and DIR/usr/lib directories. 438 439 -v1|-version1 NUM 440 Specify 1st library version outside the descriptor. This option is needed 441 if you have preferred an alternative descriptor type (see -d1 option). 442 443 In general case you should specify it in the XML-descriptor: 444 <version> 445 VERSION 446 </version> 447 448 -v2|-version2 NUM 449 Specify 2nd library version outside the descriptor. 450 451 -vnum NUM 452 Specify the library version in the generated ABI dump. The <version> section 453 of the input XML descriptor will be overwritten in this case. 454 455 -s|-strict 456 Treat all compatibility warnings as problems. Add a number of \"Low\" 457 severity problems to the return value of the tool. 458 459 -headers-only 460 Check header files without $SLIB_TYPE libraries. It is easy to run, but may 461 provide a low quality compatibility report with false positives and 462 without detecting of added/removed symbols. 463 464 Alternatively you can write \"none\" word to the <libs> section 465 in the XML-descriptor: 466 <libs> 467 none 468 </libs> 469 470 -objects-only 471 Check $SLIB_TYPE libraries without header files. It is easy to run, but may 472 provide a low quality compatibility report with false positives and 473 without analysis of changes in parameters and data types. 474 475 Alternatively you can write \"none\" word to the <headers> section 476 in the XML-descriptor: 477 <headers> 478 none 479 </headers> 480 481 -show-retval 482 Show the symbol's return type in the report. 483 484 -symbols-list PATH 485 This option allows to specify a file with a list of symbols (mangled 486 names in C++) that should be checked. Other symbols will not be checked. 487 488 -types-list PATH 489 This option allows to specify a file with a list of types that should 490 be checked. Other types will not be checked. 491 492 -skip-symbols PATH 493 The list of symbols that should NOT be checked. 494 495 -headers-list PATH 496 The file with a list of headers, that should be checked/dumped. 497 498 -skip-headers PATH 499 The file with the list of header files, that should not be checked. 500 501 -header NAME 502 Check/Dump ABI of this header only. 503 504 -use-dumps 505 Make dumps for two versions of a library and compare dumps. This should 506 increase the performance of the tool and decrease the system memory usage. 507 508 -nostdinc 509 Do not search in GCC standard system directories for header files. 510 511 -dump-system NAME -sysroot DIR 512 Find all the shared libraries and header files in DIR directory, 513 create XML descriptors and make ABI dumps for each library. The result 514 set of ABI dumps can be compared (--cmp-systems) with the other one 515 created for other version of operating system in order to check them for 516 compatibility. Do not forget to specify -cross-gcc option if your target 517 system requires some specific version of GCC compiler (different from 518 the host GCC). The system ABI dump will be generated to: 519 sys_dumps/NAME/ARCH 520 521 -dump-system DESCRIPTOR.xml 522 The same as the previous option but takes an XML descriptor of the target 523 system as input, where you should describe it: 524 525 /* Primary sections */ 526 527 <name> 528 /* Name of the system */ 529 </name> 530 531 <headers> 532 /* The list of paths to header files and/or 533 directories with header files, one per line */ 534 </headers> 535 536 <libs> 537 /* The list of paths to shared libraries and/or 538 directories with shared libraries, one per line */ 539 </libs> 540 541 /* Optional sections */ 542 543 <search_headers> 544 /* List of directories to be searched 545 for header files to automatically 546 generate include paths, one per line */ 547 </search_headers> 548 549 <search_libs> 550 /* List of directories to be searched 551 for shared libraries to resolve 552 dependencies, one per line */ 553 </search_libs> 554 555 <tools> 556 /* List of directories with tools used 557 for analysis (GCC toolchain), one per line */ 558 </tools> 559 560 <cross_prefix> 561 /* GCC toolchain prefix. 562 Examples: 563 arm-linux-gnueabi 564 arm-none-symbianelf */ 565 </cross_prefix> 566 567 <gcc_options> 568 /* Additional GCC options, one per line */ 569 </gcc_options> 570 571 -sysinfo DIR 572 This option should be used with -dump-system option to dump 573 ABI of operating systems and configure the dumping process. 574 You can find a sample in the package: 575 modules/Targets/{unix, symbian, windows} 576 577 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH 578 Compare two system ABI dumps. Create compatibility reports for each 579 library and the common HTML report including the summary of test 580 results for all checked libraries. Report will be generated to: 581 sys_compat_reports/NAME1_to_NAME2/ARCH 582 583 -libs-list PATH 584 The file with a list of libraries, that should be dumped by 585 the -dump-system option or should be checked by the -cmp-systems option. 586 587 -ext|-extended 588 If your library A is supposed to be used by other library B and you 589 want to control the ABI of B, then you should enable this option. The 590 tool will check for changes in all data types, even if they are not 591 used by any function in the library A. Such data types are not part 592 of the A library ABI, but may be a part of the ABI of the B library. 593 594 The short scheme is: 595 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI) 596 597 -q|-quiet 598 Print all messages to the file instead of stdout and stderr. 599 Default path (can be changed by -log-path option): 600 $COMMON_LOG_PATH 601 602 -stdout 603 Print analysis results (compatibility reports and ABI dumps) to stdout 604 instead of creating a file. This would allow piping data to other programs. 605 606 -report-format FMT 607 Change format of compatibility report. 608 Formats: 609 htm - HTML format (default) 610 xml - XML format 611 612 -dump-format FMT 613 Change format of ABI dump. 614 Formats: 615 perl - Data::Dumper format (default) 616 xml - XML format 617 618 -xml 619 Alias for: --report-format=xml or --dump-format=xml 620 621 -lang LANG 622 Set library language (C or C++). You can use this option if the tool 623 cannot auto-detect a language. This option may be useful for checking 624 C-library headers (--lang=C) in --headers-only or --extended modes. 625 626 -arch ARCH 627 Set library architecture (x86, x86_64, ia64, arm, ppc32, ppc64, s390, 628 ect.). The option is useful if the tool cannot detect correct architecture 629 of the input objects. 630 631 -binary|-bin|-abi 632 Show \"Binary\" compatibility problems only. 633 Generate report to: 634 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 635 636 -source|-src|-api 637 Show \"Source\" compatibility problems only. 638 Generate report to: 639 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 640 641 -limit-affected LIMIT 642 The maximum number of affected symbols listed under the description 643 of the changed type in the report. 644 645OTHER OPTIONS: 646 -test 647 Run internal tests. Create two binary incompatible versions of a sample 648 library and run the tool to check them for compatibility. This option 649 allows to check if the tool works correctly in the current environment. 650 651 -test-dump 652 Test ability to create, read and compare ABI dumps. 653 654 -debug 655 Debugging mode. Print debug info on the screen. Save intermediate 656 analysis stages in the debug directory: 657 debug/LIB_NAME/VERSION/ 658 659 Also consider using --dump option for debugging the tool. 660 661 -cpp-compatible 662 If your header files are written in C language and can be compiled 663 by the G++ compiler (i.e. don't use C++ keywords), then you can tell 664 the tool about this and speedup the analysis. 665 666 -cpp-incompatible 667 Set this option if input C header files use C++ keywords. 668 669 -p|-params PATH 670 Path to file with the function parameter names. It can be used 671 for improving report view if the library header files have no 672 parameter names. File format: 673 674 func1;param1;param2;param3 ... 675 func2;param1;param2;param3 ... 676 ... 677 678 -relpath PATH 679 Replace {RELPATH} macros to PATH in the XML-descriptor used 680 for dumping the library ABI (see -dump option). 681 682 -relpath1 PATH 683 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1). 684 685 -relpath2 PATH 686 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2). 687 688 -dump-path PATH 689 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump. 690 Default: 691 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT 692 693 -sort 694 Enable sorting of data in ABI dumps. 695 696 -report-path PATH 697 Path to compatibility report. 698 Default: 699 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 700 701 -bin-report-path PATH 702 Path to \"Binary\" compatibility report. 703 Default: 704 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 705 706 -src-report-path PATH 707 Path to \"Source\" compatibility report. 708 Default: 709 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 710 711 -log-path PATH 712 Log path for all messages. 713 Default: 714 logs/LIB_NAME/VERSION/log.txt 715 716 -log1-path PATH 717 Log path for 1st version of a library. 718 Default: 719 logs/LIB_NAME/V1/log.txt 720 721 -log2-path PATH 722 Log path for 2nd version of a library. 723 Default: 724 logs/LIB_NAME/V2/log.txt 725 726 -logging-mode MODE 727 Change logging mode. 728 Modes: 729 w - overwrite old logs (default) 730 a - append old logs 731 n - do not write any logs 732 733 -list-affected 734 Generate file with the list of incompatible 735 symbols beside the HTML compatibility report. 736 Use 'c++filt \@file' command from GNU binutils 737 to unmangle C++ symbols in the generated file. 738 Default names: 739 abi_affected.txt 740 src_affected.txt 741 742 -component NAME 743 The component name in the title and summary of the HTML report. 744 Default: 745 library 746 747 -title NAME 748 Change library name in the report title to NAME. By default 749 will be displayed a name specified by -l option. 750 751 -extra-info DIR 752 Dump extra info to DIR. 753 754 -extra-dump 755 Create extended ABI dump containing all symbols 756 from the translation unit. 757 758 -force 759 Try to use this option if the tool doesn't work. 760 761 -tolerance LEVEL 762 Apply a set of heuristics to successfully compile input 763 header files. You can enable several tolerance levels by 764 joining them into one string (e.g. 13, 124, etc.). 765 Levels: 766 1 - skip non-Linux headers (e.g. win32_*.h, etc.) 767 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.) 768 3 - skip headers that iclude non-Linux headers 769 4 - skip headers included by others 770 771 -tolerant 772 Enable highest tolerance level [1234]. 773 774 -check 775 Check completeness of the ABI dump. 776 777 -quick 778 Quick analysis. Disable check of some template instances. 779 780 -skip-internal PATTERN 781 Do not check internal interfaces matched by the pattern. 782 783REPORT: 784 Compatibility report will be generated to: 785 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 786 787 Log will be generated to: 788 logs/LIB_NAME/V1/log.txt 789 logs/LIB_NAME/V2/log.txt 790 791EXIT CODES: 792 0 - Compatible. The tool has run without any errors. 793 non-zero - Incompatible or the tool has run with errors. 794 795MORE INFORMATION: 796 ".$HomePage."\n"); 797} 798 799my %Operator_Indication = ( 800 "not" => "~", 801 "assign" => "=", 802 "andassign" => "&=", 803 "orassign" => "|=", 804 "xorassign" => "^=", 805 "or" => "|", 806 "xor" => "^", 807 "addr" => "&", 808 "and" => "&", 809 "lnot" => "!", 810 "eq" => "==", 811 "ne" => "!=", 812 "lt" => "<", 813 "lshift" => "<<", 814 "lshiftassign" => "<<=", 815 "rshiftassign" => ">>=", 816 "call" => "()", 817 "mod" => "%", 818 "modassign" => "%=", 819 "subs" => "[]", 820 "land" => "&&", 821 "lor" => "||", 822 "rshift" => ">>", 823 "ref" => "->", 824 "le" => "<=", 825 "deref" => "*", 826 "mult" => "*", 827 "preinc" => "++", 828 "delete" => " delete", 829 "vecnew" => " new[]", 830 "vecdelete" => " delete[]", 831 "predec" => "--", 832 "postinc" => "++", 833 "postdec" => "--", 834 "plusassign" => "+=", 835 "plus" => "+", 836 "minus" => "-", 837 "minusassign" => "-=", 838 "gt" => ">", 839 "ge" => ">=", 840 "new" => " new", 841 "multassign" => "*=", 842 "divassign" => "/=", 843 "div" => "/", 844 "neg" => "-", 845 "pos" => "+", 846 "memref" => "->*", 847 "compound" => "," ); 848 849my %UnknownOperator; 850 851my %NodeType= ( 852 "array_type" => "Array", 853 "binfo" => "Other", 854 "boolean_type" => "Intrinsic", 855 "complex_type" => "Intrinsic", 856 "const_decl" => "Other", 857 "enumeral_type" => "Enum", 858 "field_decl" => "Other", 859 "function_decl" => "Other", 860 "function_type" => "FunctionType", 861 "identifier_node" => "Other", 862 "integer_cst" => "Other", 863 "integer_type" => "Intrinsic", 864 "vector_type" => "Vector", 865 "method_type" => "MethodType", 866 "namespace_decl" => "Other", 867 "parm_decl" => "Other", 868 "pointer_type" => "Pointer", 869 "real_cst" => "Other", 870 "real_type" => "Intrinsic", 871 "record_type" => "Struct", 872 "reference_type" => "Ref", 873 "string_cst" => "Other", 874 "template_decl" => "Other", 875 "template_type_parm" => "TemplateParam", 876 "typename_type" => "TypeName", 877 "sizeof_expr" => "SizeOf", 878 "tree_list" => "Other", 879 "tree_vec" => "Other", 880 "type_decl" => "Other", 881 "union_type" => "Union", 882 "var_decl" => "Other", 883 "void_type" => "Intrinsic", 884 "nop_expr" => "Other", # 885 "addr_expr" => "Other", # 886 "offset_type" => "Other" ); 887 888my %CppKeywords_C = map {$_=>1} ( 889 # C++ 2003 keywords 890 "public", 891 "protected", 892 "private", 893 "default", 894 "template", 895 "new", 896 #"asm", 897 "dynamic_cast", 898 "auto", 899 "try", 900 "namespace", 901 "typename", 902 "using", 903 "reinterpret_cast", 904 "friend", 905 "class", 906 "virtual", 907 "const_cast", 908 "mutable", 909 "static_cast", 910 "export", 911 # C++0x keywords 912 "noexcept", 913 "nullptr", 914 "constexpr", 915 "static_assert", 916 "explicit", 917 # cannot be used as a macro name 918 # as it is an operator in C++ 919 "and", 920 #"and_eq", 921 "not", 922 #"not_eq", 923 "or" 924 #"or_eq", 925 #"bitand", 926 #"bitor", 927 #"xor", 928 #"xor_eq", 929 #"compl" 930); 931 932my %CppKeywords_F = map {$_=>1} ( 933 "delete", 934 "catch", 935 "alignof", 936 "thread_local", 937 "decltype", 938 "typeid" 939); 940 941my %CppKeywords_O = map {$_=>1} ( 942 "bool", 943 "register", 944 "inline", 945 "operator" 946); 947 948my %CppKeywords_A = map {$_=>1} ( 949 "this", 950 "throw", 951 "template" 952); 953 954foreach (keys(%CppKeywords_C), 955keys(%CppKeywords_F), 956keys(%CppKeywords_O)) { 957 $CppKeywords_A{$_}=1; 958} 959 960# Header file extensions as described by gcc 961my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+"; 962 963my %IntrinsicMangling = ( 964 "void" => "v", 965 "bool" => "b", 966 "wchar_t" => "w", 967 "char" => "c", 968 "signed char" => "a", 969 "unsigned char" => "h", 970 "short" => "s", 971 "unsigned short" => "t", 972 "int" => "i", 973 "unsigned int" => "j", 974 "long" => "l", 975 "unsigned long" => "m", 976 "long long" => "x", 977 "__int64" => "x", 978 "unsigned long long" => "y", 979 "__int128" => "n", 980 "unsigned __int128" => "o", 981 "float" => "f", 982 "double" => "d", 983 "long double" => "e", 984 "__float80" => "e", 985 "__float128" => "g", 986 "..." => "z" 987); 988 989my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); 990 991my %StdcxxMangling = ( 992 "3std"=>"St", 993 "3std9allocator"=>"Sa", 994 "3std12basic_string"=>"Sb", 995 "3std12basic_stringIcE"=>"Ss", 996 "3std13basic_istreamIcE"=>"Si", 997 "3std13basic_ostreamIcE"=>"So", 998 "3std14basic_iostreamIcE"=>"Sd" 999); 1000 1001my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; 1002my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); 1003 1004my $ADD_TMPL_INSTANCES = 1; 1005my $EMERGENCY_MODE_48 = 0; 1006 1007my %ConstantSuffix = ( 1008 "unsigned int"=>"u", 1009 "long"=>"l", 1010 "unsigned long"=>"ul", 1011 "long long"=>"ll", 1012 "unsigned long long"=>"ull" 1013); 1014 1015my %ConstantSuffixR = 1016reverse(%ConstantSuffix); 1017 1018my %OperatorMangling = ( 1019 "~" => "co", 1020 "=" => "aS", 1021 "|" => "or", 1022 "^" => "eo", 1023 "&" => "an",#ad (addr) 1024 "==" => "eq", 1025 "!" => "nt", 1026 "!=" => "ne", 1027 "<" => "lt", 1028 "<=" => "le", 1029 "<<" => "ls", 1030 "<<=" => "lS", 1031 ">" => "gt", 1032 ">=" => "ge", 1033 ">>" => "rs", 1034 ">>=" => "rS", 1035 "()" => "cl", 1036 "%" => "rm", 1037 "[]" => "ix", 1038 "&&" => "aa", 1039 "||" => "oo", 1040 "*" => "ml",#de (deref) 1041 "++" => "pp",# 1042 "--" => "mm",# 1043 "new" => "nw", 1044 "delete" => "dl", 1045 "new[]" => "na", 1046 "delete[]" => "da", 1047 "+=" => "pL", 1048 "+" => "pl",#ps (pos) 1049 "-" => "mi",#ng (neg) 1050 "-=" => "mI", 1051 "*=" => "mL", 1052 "/=" => "dV", 1053 "&=" => "aN", 1054 "|=" => "oR", 1055 "%=" => "rM", 1056 "^=" => "eO", 1057 "/" => "dv", 1058 "->*" => "pm", 1059 "->" => "pt",#rf (ref) 1060 "," => "cm", 1061 "?" => "qu", 1062 "." => "dt", 1063 "sizeof"=> "sz"#st 1064); 1065 1066my %Intrinsic_Keywords = map {$_=>1} ( 1067 "true", 1068 "false", 1069 "_Bool", 1070 "_Complex", 1071 "const", 1072 "int", 1073 "long", 1074 "void", 1075 "short", 1076 "float", 1077 "volatile", 1078 "restrict", 1079 "unsigned", 1080 "signed", 1081 "char", 1082 "double", 1083 "class", 1084 "struct", 1085 "union", 1086 "enum" 1087); 1088 1089my %GlibcHeader = map {$_=>1} ( 1090 "aliases.h", 1091 "argp.h", 1092 "argz.h", 1093 "assert.h", 1094 "cpio.h", 1095 "ctype.h", 1096 "dirent.h", 1097 "envz.h", 1098 "errno.h", 1099 "error.h", 1100 "execinfo.h", 1101 "fcntl.h", 1102 "fstab.h", 1103 "ftw.h", 1104 "glob.h", 1105 "grp.h", 1106 "iconv.h", 1107 "ifaddrs.h", 1108 "inttypes.h", 1109 "langinfo.h", 1110 "limits.h", 1111 "link.h", 1112 "locale.h", 1113 "malloc.h", 1114 "math.h", 1115 "mntent.h", 1116 "monetary.h", 1117 "nl_types.h", 1118 "obstack.h", 1119 "printf.h", 1120 "pwd.h", 1121 "regex.h", 1122 "sched.h", 1123 "search.h", 1124 "setjmp.h", 1125 "shadow.h", 1126 "signal.h", 1127 "spawn.h", 1128 "stdarg.h", 1129 "stdint.h", 1130 "stdio.h", 1131 "stdlib.h", 1132 "string.h", 1133 "strings.h", 1134 "tar.h", 1135 "termios.h", 1136 "time.h", 1137 "ulimit.h", 1138 "unistd.h", 1139 "utime.h", 1140 "wchar.h", 1141 "wctype.h", 1142 "wordexp.h" ); 1143 1144my %GlibcDir = map {$_=>1} ( 1145 "arpa", 1146 "bits", 1147 "gnu", 1148 "netinet", 1149 "net", 1150 "nfs", 1151 "rpc", 1152 "sys", 1153 "linux" ); 1154 1155my %WinHeaders = map {$_=>1} ( 1156 "dos.h", 1157 "process.h", 1158 "winsock.h", 1159 "config-win.h", 1160 "mem.h", 1161 "windows.h", 1162 "winsock2.h", 1163 "crtdbg.h", 1164 "ws2tcpip.h" 1165); 1166 1167my %ObsoleteHeaders = map {$_=>1} ( 1168 "iostream.h", 1169 "fstream.h" 1170); 1171 1172my %AlienHeaders = map {$_=>1} ( 1173 # Solaris 1174 "thread.h", 1175 "sys/atomic.h", 1176 # HPUX 1177 "sys/stream.h", 1178 # Symbian 1179 "AknDoc.h", 1180 # Atari ST 1181 "ext.h", 1182 "tos.h", 1183 # MS-DOS 1184 "alloc.h", 1185 # Sparc 1186 "sys/atomic.h" 1187); 1188 1189my %ConfHeaders = map {$_=>1} ( 1190 "atomic", 1191 "conf.h", 1192 "config.h", 1193 "configure.h", 1194 "build.h", 1195 "setup.h" 1196); 1197 1198my %LocalIncludes = map {$_=>1} ( 1199 "/usr/local/include", 1200 "/usr/local" ); 1201 1202my %OS_AddPath=( 1203# These paths are needed if the tool cannot detect them automatically 1204 "macos"=>{ 1205 "include"=>[ 1206 "/Library", 1207 "/Developer/usr/include" 1208 ], 1209 "lib"=>[ 1210 "/Library", 1211 "/Developer/usr/lib" 1212 ], 1213 "bin"=>[ 1214 "/Developer/usr/bin" 1215 ] 1216 }, 1217 "beos"=>{ 1218 # Haiku has GCC 2.95.3 by default 1219 # try to find GCC>=3.0 in /boot/develop/abi 1220 "include"=>[ 1221 "/boot/common", 1222 "/boot/develop" 1223 ], 1224 "lib"=>[ 1225 "/boot/common/lib", 1226 "/boot/system/lib", 1227 "/boot/apps" 1228 ], 1229 "bin"=>[ 1230 "/boot/common/bin", 1231 "/boot/system/bin", 1232 "/boot/develop/abi" 1233 ] 1234 } 1235); 1236 1237my %Slash_Type=( 1238 "default"=>"/", 1239 "windows"=>"\\" 1240); 1241 1242my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"}; 1243 1244# Global Variables 1245my %COMMON_LANGUAGE=( 1246 1 => "C", 1247 2 => "C" ); 1248 1249my $MAX_COMMAND_LINE_ARGUMENTS = 4096; 1250my $MAX_CPPFILT_FILE_SIZE = 50000; 1251my $CPPFILT_SUPPORT_FILE; 1252 1253my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION); 1254 1255my $STDCXX_TESTING = 0; 1256my $GLIBC_TESTING = 0; 1257my $CPP_HEADERS = 0; 1258 1259my $CheckHeadersOnly = $CheckHeadersOnly_Opt; 1260my $CheckObjectsOnly = $CheckObjectsOnly_Opt; 1261 1262my $TargetComponent; 1263 1264my $CheckUndefined = 0; 1265 1266# Set Target Component Name 1267if($TargetComponent_Opt) { 1268 $TargetComponent = lc($TargetComponent_Opt); 1269} 1270else 1271{ # default: library 1272 # other components: header, system, ... 1273 $TargetComponent = "library"; 1274} 1275 1276my $TOP_REF = "<a class='top_ref' href='#Top'>to the top</a>"; 1277 1278my $SystemRoot; 1279 1280my $MAIN_CPP_DIR; 1281my %RESULT; 1282my %LOG_PATH; 1283my %DEBUG_PATH; 1284my %Cache; 1285my %LibInfo; 1286my $COMPILE_ERRORS = 0; 1287my %CompilerOptions; 1288my %CheckedDyLib; 1289my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup); 1290 1291# Constants (#defines) 1292my %Constants; 1293my %SkipConstants; 1294my %EnumConstants; 1295 1296# Extra Info 1297my %SymbolHeader; 1298my %KnownLibs; 1299 1300# Templates 1301my %TemplateInstance; 1302my %BasicTemplate; 1303my %TemplateArg; 1304my %TemplateDecl; 1305my %TemplateMap; 1306 1307# Types 1308my %TypeInfo; 1309my %SkipTypes = ( 1310 "1"=>{}, 1311 "2"=>{} ); 1312my %CheckedTypes; 1313my %TName_Tid; 1314my %EnumMembName_Id; 1315my %NestedNameSpaces = ( 1316 "1"=>{}, 1317 "2"=>{} ); 1318my %VirtualTable; 1319my %VirtualTable_Model; 1320my %ClassVTable; 1321my %ClassVTable_Content; 1322my %VTableClass; 1323my %AllocableClass; 1324my %ClassMethods; 1325my %ClassNames; 1326my %Class_SubClasses; 1327my %OverriddenMethods; 1328my %TypedefToAnon; 1329my $MAX_ID = 0; 1330 1331my %CheckedTypeInfo; 1332 1333# Typedefs 1334my %Typedef_BaseName; 1335my %Typedef_Tr; 1336my %Typedef_Eq; 1337my %StdCxxTypedef; 1338my %MissedTypedef; 1339my %MissedBase; 1340my %MissedBase_R; 1341my %TypeTypedef; 1342 1343# Symbols 1344my %SymbolInfo; 1345my %tr_name; 1346my %mangled_name_gcc; 1347my %mangled_name; 1348my %SkipSymbols = ( 1349 "1"=>{}, 1350 "2"=>{} ); 1351my %SkipNameSpaces = ( 1352 "1"=>{}, 1353 "2"=>{} ); 1354my %AddNameSpaces = ( 1355 "1"=>{}, 1356 "2"=>{} ); 1357my %SymbolsList; 1358my %TypesList; 1359my %SymbolsList_App; 1360my %CheckedSymbols; 1361my %Symbol_Library = ( 1362 "1"=>{}, 1363 "2"=>{} ); 1364my %Library_Symbol = ( 1365 "1"=>{}, 1366 "2"=>{} ); 1367my %DepSymbol_Library = ( 1368 "1"=>{}, 1369 "2"=>{} ); 1370my %DepLibrary_Symbol = ( 1371 "1"=>{}, 1372 "2"=>{} ); 1373my %MangledNames; 1374my %Func_ShortName; 1375my %AddIntParams; 1376my %GlobalDataObject; 1377my %WeakSymbols; 1378my %Library_Needed= ( 1379 "1"=>{}, 1380 "2"=>{} ); 1381 1382# Extra Info 1383my %UndefinedSymbols; 1384my %PreprocessedHeaders; 1385 1386# Headers 1387my %Include_Preamble = ( 1388 "1"=>[], 1389 "2"=>[] ); 1390my %Registered_Headers; 1391my %Registered_Sources; 1392my %HeaderName_Paths; 1393my %Header_Dependency; 1394my %Include_Neighbors; 1395my %Include_Paths = ( 1396 "1"=>[], 1397 "2"=>[] ); 1398my %INC_PATH_AUTODETECT = ( 1399 "1"=>1, 1400 "2"=>1 ); 1401my %Add_Include_Paths = ( 1402 "1"=>[], 1403 "2"=>[] ); 1404my %Skip_Include_Paths; 1405my %RegisteredDirs; 1406my %Header_ErrorRedirect; 1407my %Header_Includes; 1408my %Header_Includes_R; 1409my %Header_ShouldNotBeUsed; 1410my %RecursiveIncludes; 1411my %Header_Include_Prefix; 1412my %SkipHeaders; 1413my %SkipHeadersList=( 1414 "1"=>{}, 1415 "2"=>{} ); 1416my %SkipLibs; 1417my %Include_Order; 1418my %TUnit_NameSpaces; 1419my %TUnit_Classes; 1420my %TUnit_Funcs; 1421my %TUnit_Vars; 1422 1423my %CppMode = ( 1424 "1"=>0, 1425 "2"=>0 ); 1426my %AutoPreambleMode = ( 1427 "1"=>0, 1428 "2"=>0 ); 1429my %MinGWMode = ( 1430 "1"=>0, 1431 "2"=>0 ); 1432my %Cpp0xMode = ( 1433 "1"=>0, 1434 "2"=>0 ); 1435 1436# Shared Objects 1437my %RegisteredObjects; 1438my %RegisteredObjects_Short; 1439my %RegisteredSONAMEs; 1440my %RegisteredObject_Dirs; 1441 1442my %CheckedArch; 1443 1444# System Objects 1445my %SystemObjects; 1446my @DefaultLibPaths; 1447my %DyLib_DefaultPath; 1448 1449# System Headers 1450my %SystemHeaders; 1451my @DefaultCppPaths; 1452my @DefaultGccPaths; 1453my @DefaultIncPaths; 1454my %DefaultCppHeader; 1455my %DefaultGccHeader; 1456my @UsersIncPath; 1457 1458# Merging 1459my %CompleteSignature; 1460my $Version; 1461my %AddedInt; 1462my %RemovedInt; 1463my %AddedInt_Virt; 1464my %RemovedInt_Virt; 1465my %VirtualReplacement; 1466my %ChangedTypedef; 1467my %CompatRules; 1468my %IncompleteRules; 1469my %UnknownRules; 1470my %VTableChanged_M; 1471my %ExtendedSymbols; 1472my %ReturnedClass; 1473my %ParamClass; 1474my %SourceAlternative; 1475my %SourceAlternative_B; 1476my %SourceReplacement; 1477my $CurrentSymbol; # for debugging 1478 1479# Calling Conventions 1480my %UseConv_Real = ( 1481 1=>{ "R"=>0, "P"=>0 }, 1482 2=>{ "R"=>0, "P"=>0 } 1483); 1484 1485# ABI Dump 1486my %UsedDump; 1487 1488# OS Compliance 1489my %TargetLibs; 1490my %TargetHeaders; 1491 1492# OS Specifics 1493my $OStarget = $OSgroup; 1494my %TargetTools; 1495 1496# Compliance Report 1497my %Type_MaxSeverity; 1498 1499# Recursion locks 1500my @RecurLib; 1501my @RecurTypes; 1502my @RecurTypes_Diff; 1503my @RecurInclude; 1504my @RecurConstant; 1505 1506# System 1507my %SystemPaths = ( 1508 "include"=>[], 1509 "lib"=>[], 1510 "bin"=>[] 1511); 1512my @DefaultBinPaths; 1513my $GCC_PATH; 1514 1515# Symbols versioning 1516my %SymVer = ( 1517 "1"=>{}, 1518 "2"=>{} ); 1519 1520# Problem descriptions 1521my %CompatProblems; 1522my %CompatProblems_Constants; 1523my %TotalAffected; 1524 1525# Reports 1526my $ContentID = 1; 1527my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1528my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1529my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1530my $ContentSpanEnd = "</span>\n"; 1531my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n"; 1532my $ContentDivEnd = "</div>\n"; 1533my $Content_Counter = 0; 1534 1535# Modes 1536my $JoinReport = 1; 1537my $DoubleReport = 0; 1538 1539my %Severity_Val=( 1540 "High"=>3, 1541 "Medium"=>2, 1542 "Low"=>1, 1543 "Safe"=>-1 1544); 1545 1546sub get_Modules() 1547{ 1548 my $TOOL_DIR = get_dirname($0); 1549 if(not $TOOL_DIR) 1550 { # patch for MS Windows 1551 $TOOL_DIR = "."; 1552 } 1553 my @SEARCH_DIRS = ( 1554 # tool's directory 1555 abs_path($TOOL_DIR), 1556 # relative path to modules 1557 abs_path($TOOL_DIR)."/../share/abi-compliance-checker", 1558 # install path 1559 'MODULES_INSTALL_PATH' 1560 ); 1561 foreach my $DIR (@SEARCH_DIRS) 1562 { 1563 if(not is_abs($DIR)) 1564 { # relative path 1565 $DIR = abs_path($TOOL_DIR)."/".$DIR; 1566 } 1567 if(-d $DIR."/modules") { 1568 return $DIR."/modules"; 1569 } 1570 } 1571 exitStatus("Module_Error", "can't find modules"); 1572} 1573 1574my %LoadedModules = (); 1575 1576sub loadModule($) 1577{ 1578 my $Name = $_[0]; 1579 if(defined $LoadedModules{$Name}) { 1580 return; 1581 } 1582 my $Path = $MODULES_DIR."/Internals/$Name.pm"; 1583 if(not -f $Path) { 1584 exitStatus("Module_Error", "can't access \'$Path\'"); 1585 } 1586 require $Path; 1587 $LoadedModules{$Name} = 1; 1588} 1589 1590sub readModule($$) 1591{ 1592 my ($Module, $Name) = @_; 1593 my $Path = $MODULES_DIR."/Internals/$Module/".$Name; 1594 if(not -f $Path) { 1595 exitStatus("Module_Error", "can't access \'$Path\'"); 1596 } 1597 return readFile($Path); 1598} 1599 1600sub showPos($) 1601{ 1602 my $Number = $_[0]; 1603 if(not $Number) { 1604 $Number = 1; 1605 } 1606 else { 1607 $Number = int($Number)+1; 1608 } 1609 if($Number>3) { 1610 return $Number."th"; 1611 } 1612 elsif($Number==1) { 1613 return "1st"; 1614 } 1615 elsif($Number==2) { 1616 return "2nd"; 1617 } 1618 elsif($Number==3) { 1619 return "3rd"; 1620 } 1621 else { 1622 return $Number; 1623 } 1624} 1625 1626sub search_Tools($) 1627{ 1628 my $Name = $_[0]; 1629 return "" if(not $Name); 1630 if(my @Paths = keys(%TargetTools)) 1631 { 1632 foreach my $Path (@Paths) 1633 { 1634 if(-f join_P($Path, $Name)) { 1635 return join_P($Path, $Name); 1636 } 1637 if($CrossPrefix) 1638 { # user-defined prefix (arm-none-symbianelf, ...) 1639 my $Candidate = join_P($Path, $CrossPrefix."-".$Name); 1640 if(-f $Candidate) { 1641 return $Candidate; 1642 } 1643 } 1644 } 1645 } 1646 else { 1647 return ""; 1648 } 1649} 1650 1651sub synch_Cmd($) 1652{ 1653 my $Name = $_[0]; 1654 if(not $GCC_PATH) 1655 { # GCC was not found yet 1656 return ""; 1657 } 1658 my $Candidate = $GCC_PATH; 1659 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) { 1660 return $Candidate; 1661 } 1662 return ""; 1663} 1664 1665sub get_CmdPath($) 1666{ 1667 my $Name = $_[0]; 1668 return "" if(not $Name); 1669 if(defined $Cache{"get_CmdPath"}{$Name}) { 1670 return $Cache{"get_CmdPath"}{$Name}; 1671 } 1672 my %BinUtils = map {$_=>1} ( 1673 "c++filt", 1674 "objdump", 1675 "readelf" 1676 ); 1677 if($BinUtils{$Name} and $GCC_PATH) 1678 { 1679 if(my $Dir = get_dirname($GCC_PATH)) { 1680 $TargetTools{$Dir}=1; 1681 } 1682 } 1683 my $Path = search_Tools($Name); 1684 if(not $Path and $OSgroup eq "windows") { 1685 $Path = search_Tools($Name.".exe"); 1686 } 1687 if(not $Path and $BinUtils{$Name}) 1688 { 1689 if($CrossPrefix) 1690 { # user-defined prefix 1691 $Path = search_Cmd($CrossPrefix."-".$Name); 1692 } 1693 } 1694 if(not $Path and $BinUtils{$Name}) 1695 { 1696 if(my $Candidate = synch_Cmd($Name)) 1697 { # synch with GCC 1698 if($Candidate=~/[\/\\]/) 1699 { # command path 1700 if(-f $Candidate) { 1701 $Path = $Candidate; 1702 } 1703 } 1704 elsif($Candidate = search_Cmd($Candidate)) 1705 { # command name 1706 $Path = $Candidate; 1707 } 1708 } 1709 } 1710 if(not $Path) { 1711 $Path = search_Cmd($Name); 1712 } 1713 if(not $Path and $OSgroup eq "windows") 1714 { # search for *.exe file 1715 $Path=search_Cmd($Name.".exe"); 1716 } 1717 if($Path=~/\s/) { 1718 $Path = "\"".$Path."\""; 1719 } 1720 return ($Cache{"get_CmdPath"}{$Name}=$Path); 1721} 1722 1723sub search_Cmd($) 1724{ 1725 my $Name = $_[0]; 1726 return "" if(not $Name); 1727 if(defined $Cache{"search_Cmd"}{$Name}) { 1728 return $Cache{"search_Cmd"}{$Name}; 1729 } 1730 if(my $DefaultPath = get_CmdPath_Default($Name)) { 1731 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath); 1732 } 1733 foreach my $Path (@{$SystemPaths{"bin"}}) 1734 { 1735 my $CmdPath = join_P($Path,$Name); 1736 if(-f $CmdPath) 1737 { 1738 if($Name=~/gcc/) { 1739 next if(not check_gcc($CmdPath, "3")); 1740 } 1741 return ($Cache{"search_Cmd"}{$Name} = $CmdPath); 1742 } 1743 } 1744 return ($Cache{"search_Cmd"}{$Name} = ""); 1745} 1746 1747sub get_CmdPath_Default($) 1748{ # search in PATH 1749 return "" if(not $_[0]); 1750 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) { 1751 return $Cache{"get_CmdPath_Default"}{$_[0]}; 1752 } 1753 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0])); 1754} 1755 1756sub get_CmdPath_Default_I($) 1757{ # search in PATH 1758 my $Name = $_[0]; 1759 if($Name=~/find/) 1760 { # special case: search for "find" utility 1761 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) { 1762 return "find"; 1763 } 1764 } 1765 elsif($Name=~/gcc/) { 1766 return check_gcc($Name, "3"); 1767 } 1768 if(checkCmd($Name)) { 1769 return $Name; 1770 } 1771 if($OSgroup eq "windows") 1772 { 1773 if(`$Name /? 2>\"$TMP_DIR/null\"`) { 1774 return $Name; 1775 } 1776 } 1777 foreach my $Path (@DefaultBinPaths) 1778 { 1779 if(-f $Path."/".$Name) { 1780 return join_P($Path, $Name); 1781 } 1782 } 1783 return ""; 1784} 1785 1786sub classifyPath($) 1787{ 1788 my $Path = $_[0]; 1789 if($Path=~/[\*\[]/) 1790 { # wildcard 1791 $Path=~s/\*/.*/g; 1792 $Path=~s/\\/\\\\/g; 1793 return ($Path, "Pattern"); 1794 } 1795 elsif($Path=~/[\/\\]/) 1796 { # directory or relative path 1797 return (path_format($Path, $OSgroup), "Path"); 1798 } 1799 else { 1800 return ($Path, "Name"); 1801 } 1802} 1803 1804sub readDescriptor($$) 1805{ 1806 my ($LibVersion, $Content) = @_; 1807 return if(not $LibVersion); 1808 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\""; 1809 if(not $Content) { 1810 exitStatus("Error", "$DName is empty"); 1811 } 1812 if($Content!~/\</) { 1813 exitStatus("Error", "incorrect descriptor (see -d1 option)"); 1814 } 1815 $Content=~s/\/\*(.|\n)+?\*\///g; 1816 $Content=~s/<\!--(.|\n)+?-->//g; 1817 1818 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version"); 1819 if($TargetVersion{$LibVersion}) { 1820 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion}; 1821 } 1822 if(not $Descriptor{$LibVersion}{"Version"}) { 1823 exitStatus("Error", "version in the $DName is not specified (<version> section)"); 1824 } 1825 if($Content=~/{RELPATH}/) 1826 { 1827 if(my $RelDir = $RelativeDirectory{$LibVersion}) { 1828 $Content =~ s/{RELPATH}/$RelDir/g; 1829 } 1830 else 1831 { 1832 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion"; 1833 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro"); 1834 } 1835 } 1836 1837 if(not $CheckObjectsOnly_Opt) 1838 { 1839 my $DHeaders = parseTag(\$Content, "headers"); 1840 if(not $DHeaders) { 1841 exitStatus("Error", "header files in the $DName are not specified (<headers> section)"); 1842 } 1843 elsif(lc($DHeaders) ne "none") 1844 { # append the descriptor headers list 1845 if($Descriptor{$LibVersion}{"Headers"}) 1846 { # multiple descriptors 1847 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders; 1848 } 1849 else { 1850 $Descriptor{$LibVersion}{"Headers"} = $DHeaders; 1851 } 1852 foreach my $Path (split(/\s*\n\s*/, $DHeaders)) 1853 { 1854 if(not -e $Path) { 1855 exitStatus("Access_Error", "can't access \'$Path\'"); 1856 } 1857 } 1858 } 1859 } 1860 if(not $CheckHeadersOnly_Opt) 1861 { 1862 my $DObjects = parseTag(\$Content, "libs"); 1863 if(not $DObjects) { 1864 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)"); 1865 } 1866 elsif(lc($DObjects) ne "none") 1867 { # append the descriptor libraries list 1868 if($Descriptor{$LibVersion}{"Libs"}) 1869 { # multiple descriptors 1870 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects; 1871 } 1872 else { 1873 $Descriptor{$LibVersion}{"Libs"} .= $DObjects; 1874 } 1875 foreach my $Path (split(/\s*\n\s*/, $DObjects)) 1876 { 1877 if(not -e $Path) { 1878 exitStatus("Access_Error", "can't access \'$Path\'"); 1879 } 1880 } 1881 } 1882 } 1883 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) 1884 { 1885 if(not -d $Path) { 1886 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1887 } 1888 $Path = get_abs_path($Path); 1889 $Path = path_format($Path, $OSgroup); 1890 push_U($SystemPaths{"include"}, $Path); 1891 } 1892 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) 1893 { 1894 if(not -d $Path) { 1895 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1896 } 1897 $Path = get_abs_path($Path); 1898 $Path = path_format($Path, $OSgroup); 1899 push_U($SystemPaths{"lib"}, $Path); 1900 } 1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) 1902 { 1903 if(not -d $Path) { 1904 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1905 } 1906 $Path = get_abs_path($Path); 1907 $Path = path_format($Path, $OSgroup); 1908 push_U($SystemPaths{"bin"}, $Path); 1909 $TargetTools{$Path}=1; 1910 } 1911 if(my $Prefix = parseTag(\$Content, "cross_prefix")) { 1912 $CrossPrefix = $Prefix; 1913 } 1914 $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //= 1915 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) 1916 { 1917 if(not -d $Path) { 1918 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1919 } 1920 $Path = get_abs_path($Path); 1921 $Path = path_format($Path, $OSgroup); 1922 push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path); 1923 } 1924 $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"}); 1925 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) 1926 { 1927 if(not -d $Path) { 1928 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1929 } 1930 $Path = get_abs_path($Path); 1931 $Path = path_format($Path, $OSgroup); 1932 push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path); 1933 } 1934 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) 1935 { # skip some auto-generated include paths 1936 if(not is_abs($Path)) 1937 { 1938 if(my $P = abs_path($Path)) { 1939 $Path = $P; 1940 } 1941 } 1942 $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1; 1943 } 1944 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) 1945 { # skip direct including of some headers 1946 my ($CPath, $Type) = classifyPath($Path); 1947 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2; 1948 } 1949 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options"); 1950 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) 1951 { 1952 if($Option!~/\A\-(Wl|l|L)/) 1953 { # skip linker options 1954 $CompilerOptions{$LibVersion} .= " ".$Option; 1955 } 1956 } 1957 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers"); 1958 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"})) 1959 { 1960 $SkipHeadersList{$LibVersion}{$Path} = 1; 1961 my ($CPath, $Type) = classifyPath($Path); 1962 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1; 1963 } 1964 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs"); 1965 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"})) 1966 { 1967 my ($CPath, $Type) = classifyPath($Path); 1968 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1; 1969 } 1970 if(my $DDefines = parseTag(\$Content, "defines")) 1971 { 1972 if($Descriptor{$LibVersion}{"Defines"}) 1973 { # multiple descriptors 1974 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines; 1975 } 1976 else { 1977 $Descriptor{$LibVersion}{"Defines"} = $DDefines; 1978 } 1979 } 1980 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) 1981 { 1982 if($Order=~/\A(.+):(.+)\Z/) { 1983 $Include_Order{$LibVersion}{$1} = $2; 1984 } 1985 } 1986 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), 1987 split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) 1988 { # opaque_types renamed to skip_types (1.23.4) 1989 $SkipTypes{$LibVersion}{$Type_Name} = 1; 1990 } 1991 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), 1992 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) 1993 { # skip_interfaces renamed to skip_symbols (1.22.1) 1994 $SkipSymbols{$LibVersion}{$Symbol} = 1; 1995 } 1996 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { 1997 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1; 1998 } 1999 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { 2000 $AddNameSpaces{$LibVersion}{$NameSpace} = 1; 2001 } 2002 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { 2003 $SkipConstants{$LibVersion}{$Constant} = 1; 2004 } 2005 if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) 2006 { 2007 if($Descriptor{$LibVersion}{"IncludePreamble"}) 2008 { # multiple descriptors 2009 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble; 2010 } 2011 else { 2012 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble; 2013 } 2014 } 2015} 2016 2017sub parseTag(@) 2018{ 2019 my $CodeRef = shift(@_); 2020 my $Tag = shift(@_); 2021 if(not $Tag or not $CodeRef) { 2022 return undef; 2023 } 2024 my $Sp = 0; 2025 if(@_) { 2026 $Sp = shift(@_); 2027 } 2028 my $Start = index(${$CodeRef}, "<$Tag>"); 2029 if($Start!=-1) 2030 { 2031 my $End = index(${$CodeRef}, "</$Tag>"); 2032 if($End!=-1) 2033 { 2034 my $TS = length($Tag)+3; 2035 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, ""); 2036 substr($Content, 0, $TS-1, ""); # cut start tag 2037 substr($Content, -$TS, $TS, ""); # cut end tag 2038 if(not $Sp) 2039 { 2040 $Content=~s/\A\s+//g; 2041 $Content=~s/\s+\Z//g; 2042 } 2043 if(substr($Content, 0, 1) ne "<") { 2044 $Content = xmlSpecChars_R($Content); 2045 } 2046 return $Content; 2047 } 2048 } 2049 return undef; 2050} 2051 2052sub getInfo($) 2053{ 2054 my $DumpPath = $_[0]; 2055 return if(not $DumpPath or not -f $DumpPath); 2056 2057 readTUDump($DumpPath); 2058 2059 # processing info 2060 setTemplateParams_All(); 2061 2062 if($ExtraDump) { 2063 setAnonTypedef_All(); 2064 } 2065 2066 getTypeInfo_All(); 2067 simplifyNames(); 2068 simplifyConstants(); 2069 getVarInfo_All(); 2070 getSymbolInfo_All(); 2071 2072 # clean memory 2073 %LibInfo = (); 2074 %TemplateInstance = (); 2075 %BasicTemplate = (); 2076 %MangledNames = (); 2077 %TemplateDecl = (); 2078 %StdCxxTypedef = (); 2079 %MissedTypedef = (); 2080 %Typedef_Tr = (); 2081 %Typedef_Eq = (); 2082 %TypedefToAnon = (); 2083 2084 # clean cache 2085 delete($Cache{"getTypeAttr"}); 2086 delete($Cache{"getTypeDeclId"}); 2087 2088 if($ExtraDump) 2089 { 2090 remove_Unused($Version, "Extra"); 2091 } 2092 else 2093 { # remove unused types 2094 if($BinaryOnly and not $ExtendedCheck) 2095 { # --binary 2096 remove_Unused($Version, "All"); 2097 } 2098 else { 2099 remove_Unused($Version, "Extended"); 2100 } 2101 } 2102 2103 if($CheckInfo) 2104 { 2105 foreach my $Tid (keys(%{$TypeInfo{$Version}})) { 2106 check_Completeness($TypeInfo{$Version}{$Tid}, $Version); 2107 } 2108 2109 foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { 2110 check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); 2111 } 2112 } 2113 2114 if($Debug) { 2115 # debugMangling($Version); 2116 } 2117} 2118 2119sub readTUDump($) 2120{ 2121 my $DumpPath = $_[0]; 2122 2123 open(TU_DUMP, $DumpPath); 2124 local $/ = undef; 2125 my $Content = <TU_DUMP>; 2126 close(TU_DUMP); 2127 2128 unlink($DumpPath); 2129 2130 $Content=~s/\n[ ]+/ /g; 2131 my @Lines = split(/\n/, $Content); 2132 2133 # clean memory 2134 undef $Content; 2135 2136 $MAX_ID = $#Lines+1; # number of lines == number of nodes 2137 2138 foreach (0 .. $#Lines) 2139 { 2140 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i) 2141 { # get a number and attributes of a node 2142 next if(not $NodeType{$2}); 2143 $LibInfo{$Version}{"info_type"}{$1}=$2; 2144 $LibInfo{$Version}{"info"}{$1}=$3; 2145 } 2146 2147 # clean memory 2148 delete($Lines[$_]); 2149 } 2150 2151 # clean memory 2152 undef @Lines; 2153} 2154 2155sub simplifyConstants() 2156{ 2157 foreach my $Constant (keys(%{$Constants{$Version}})) 2158 { 2159 if(defined $Constants{$Version}{$Constant}{"Header"}) 2160 { 2161 my $Value = $Constants{$Version}{$Constant}{"Value"}; 2162 if(defined $EnumConstants{$Version}{$Value}) { 2163 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"}; 2164 } 2165 } 2166 } 2167} 2168 2169sub simplifyNames() 2170{ 2171 foreach my $Base (keys(%{$Typedef_Tr{$Version}})) 2172 { 2173 if($Typedef_Eq{$Version}{$Base}) { 2174 next; 2175 } 2176 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}}); 2177 if($#Translations==0) 2178 { 2179 if(length($Translations[0])<=length($Base)) { 2180 $Typedef_Eq{$Version}{$Base} = $Translations[0]; 2181 } 2182 } 2183 else 2184 { # select most appropriate 2185 foreach my $Tr (@Translations) 2186 { 2187 if($Base=~/\A\Q$Tr\E/) 2188 { 2189 $Typedef_Eq{$Version}{$Base} = $Tr; 2190 last; 2191 } 2192 } 2193 } 2194 } 2195 foreach my $TypeId (keys(%{$TypeInfo{$Version}})) 2196 { 2197 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2198 if(not $TypeName) { 2199 next; 2200 } 2201 next if(index($TypeName,"<")==-1);# template instances only 2202 if($TypeName=~/>(::\w+)+\Z/) 2203 { # skip unused types 2204 next; 2205 } 2206 foreach my $Base (sort {length($b)<=>length($a)} 2207 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}})) 2208 { 2209 next if(not $Base); 2210 next if(index($TypeName,$Base)==-1); 2211 next if(length($TypeName) - length($Base) <= 3); 2212 if(my $Typedef = $Typedef_Eq{$Version}{$Base}) 2213 { 2214 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g; 2215 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g; 2216 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"}) 2217 { 2218 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}})) 2219 { 2220 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"}) 2221 { 2222 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g; 2223 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g; 2224 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T"); 2225 } 2226 } 2227 } 2228 } 2229 } 2230 $TypeName = formatName($TypeName, "T"); 2231 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName; 2232 $TName_Tid{$Version}{$TypeName} = $TypeId; 2233 } 2234} 2235 2236sub setAnonTypedef_All() 2237{ 2238 foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}})) 2239 { 2240 if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl") 2241 { 2242 if(isAnon(getNameByInfo($InfoId))) { 2243 $TypedefToAnon{getTypeId($InfoId)} = 1; 2244 } 2245 } 2246 } 2247} 2248 2249sub setTemplateParams_All() 2250{ 2251 foreach (keys(%{$LibInfo{$Version}{"info"}})) 2252 { 2253 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") { 2254 setTemplateParams($_); 2255 } 2256 } 2257} 2258 2259sub setTemplateParams($) 2260{ 2261 my $Tid = getTypeId($_[0]); 2262 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2263 { 2264 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) 2265 { 2266 my $TmplInst_Id = $2; 2267 setTemplateInstParams($_[0], $TmplInst_Id); 2268 while($TmplInst_Id = getNextElem($TmplInst_Id)) { 2269 setTemplateInstParams($_[0], $TmplInst_Id); 2270 } 2271 } 2272 2273 $BasicTemplate{$Version}{$Tid} = $_[0]; 2274 2275 if(my $Prms = getTreeAttr_Prms($_[0])) 2276 { 2277 if(my $Valu = getTreeAttr_Valu($Prms)) 2278 { 2279 my $Vector = getTreeVec($Valu); 2280 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) 2281 { 2282 if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) 2283 { 2284 if(my $Name = getNameByInfo($Val)) 2285 { 2286 $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; 2287 if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { 2288 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; 2289 } 2290 else { 2291 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); 2292 } 2293 } 2294 } 2295 } 2296 } 2297 } 2298 } 2299 if(my $TypeId = getTreeAttr_Type($_[0])) 2300 { 2301 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) 2302 { 2303 if($IType eq "record_type") { 2304 $TemplateDecl{$Version}{$TypeId} = 1; 2305 } 2306 } 2307 } 2308} 2309 2310sub setTemplateInstParams($$) 2311{ 2312 my ($Tmpl, $Inst) = @_; 2313 2314 if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) 2315 { 2316 my ($Params_InfoId, $ElemId) = (); 2317 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 2318 $Params_InfoId = $1; 2319 } 2320 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 2321 $ElemId = $1; 2322 } 2323 if($Params_InfoId and $ElemId) 2324 { 2325 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId}; 2326 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 2327 { 2328 my ($PPos, $PTypeId) = ($1, $2); 2329 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) 2330 { 2331 if($PType eq "template_type_parm") { 2332 $TemplateDecl{$Version}{$ElemId} = 1; 2333 } 2334 } 2335 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") 2336 { # functions 2337 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; 2338 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2339 } 2340 else 2341 { # types 2342 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; 2343 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2344 } 2345 } 2346 } 2347 } 2348} 2349 2350sub getTypeDeclId($) 2351{ 2352 if($_[0]) 2353 { 2354 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) { 2355 return $Cache{"getTypeDeclId"}{$Version}{$_[0]}; 2356 } 2357 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2358 { 2359 if($Info=~/name[ ]*:[ ]*@(\d+)/) { 2360 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1); 2361 } 2362 } 2363 } 2364 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0); 2365} 2366 2367sub getTypeInfo_All() 2368{ 2369 if(not check_gcc($GCC_PATH, "4.5")) 2370 { # support for GCC < 4.5 2371 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag> 2372 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump 2373 # FIXME: check GCC versions 2374 addMissedTypes_Pre(); 2375 } 2376 2377 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2378 { # forward order only 2379 my $IType = $LibInfo{$Version}{"info_type"}{$_}; 2380 if($IType=~/_type\Z/ and $IType ne "function_type" 2381 and $IType ne "method_type") { 2382 getTypeInfo("$_"); 2383 } 2384 } 2385 2386 # add "..." type 2387 $TypeInfo{$Version}{"-1"} = { 2388 "Name" => "...", 2389 "Type" => "Intrinsic", 2390 "Tid" => "-1" 2391 }; 2392 $TName_Tid{$Version}{"..."} = "-1"; 2393 2394 if(not check_gcc($GCC_PATH, "4.5")) 2395 { # support for GCC < 4.5 2396 addMissedTypes_Post(); 2397 } 2398 2399 if($ADD_TMPL_INSTANCES) 2400 { 2401 # templates 2402 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) 2403 { 2404 if(defined $TemplateMap{$Version}{$Tid} 2405 and not defined $TypeInfo{$Version}{$Tid}{"Template"}) 2406 { 2407 if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) 2408 { 2409 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) 2410 { 2411 if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) 2412 { 2413 if(my %MAttr = getTypeAttr($MembTypeId)) 2414 { 2415 $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; 2416 $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); 2417 } 2418 } 2419 } 2420 } 2421 if(defined $TypeInfo{$Version}{$Tid}{"Base"}) 2422 { 2423 foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) 2424 { 2425 my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); 2426 2427 if($NBid ne $Bid) 2428 { 2429 %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; 2430 delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); 2431 } 2432 } 2433 } 2434 } 2435 } 2436 } 2437} 2438 2439sub createType($$) 2440{ 2441 my ($Attr, $LibVersion) = @_; 2442 my $NewId = ++$MAX_ID; 2443 2444 $Attr->{"Tid"} = $NewId; 2445 $TypeInfo{$Version}{$NewId} = $Attr; 2446 $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; 2447 2448 return "$NewId"; 2449} 2450 2451sub instType($$$) 2452{ # create template instances 2453 my ($Map, $Tid, $LibVersion) = @_; 2454 2455 if(not $TypeInfo{$LibVersion}{$Tid}) { 2456 return undef; 2457 } 2458 my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); 2459 2460 foreach my $Key (sort keys(%{$Map})) 2461 { 2462 if(my $Val = $Map->{$Key}) 2463 { 2464 $Attr->{"Name"}=~s/\b$Key\b/$Val/g; 2465 2466 if(defined $Attr->{"NameSpace"}) { 2467 $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; 2468 } 2469 foreach (keys(%{$Attr->{"TParam"}})) { 2470 $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; 2471 } 2472 } 2473 else 2474 { # remove absent 2475 # _Traits, etc. 2476 $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; 2477 if(defined $Attr->{"NameSpace"}) { 2478 $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; 2479 } 2480 foreach (keys(%{$Attr->{"TParam"}})) 2481 { 2482 if($Attr->{"TParam"}{$_}{"name"} eq $Key) { 2483 delete($Attr->{"TParam"}{$_}); 2484 } 2485 else { 2486 $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; 2487 } 2488 } 2489 } 2490 } 2491 2492 my $Tmpl = 0; 2493 2494 if(defined $Attr->{"TParam"}) 2495 { 2496 foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) 2497 { 2498 my $PName = $Attr->{"TParam"}{$_}{"name"}; 2499 2500 if(my $PTid = $TName_Tid{$LibVersion}{$PName}) 2501 { 2502 my %Base = get_BaseType($PTid, $LibVersion); 2503 2504 if($Base{"Type"} eq "TemplateParam" 2505 or defined $Base{"Template"}) 2506 { 2507 $Tmpl = 1; 2508 last 2509 } 2510 } 2511 } 2512 } 2513 2514 if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { 2515 return "$Id"; 2516 } 2517 else 2518 { 2519 if(not $Tmpl) { 2520 delete($Attr->{"Template"}); 2521 } 2522 2523 my $New = createType($Attr, $LibVersion); 2524 2525 my %EMap = (); 2526 if(defined $TemplateMap{$LibVersion}{$Tid}) { 2527 %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; 2528 } 2529 foreach (keys(%{$Map})) { 2530 $EMap{$_} = $Map->{$_}; 2531 } 2532 2533 if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { 2534 $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); 2535 } 2536 if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) 2537 { 2538 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) 2539 { 2540 my $NBid = instType(\%EMap, $Bid, $LibVersion); 2541 2542 if($NBid ne $Bid) 2543 { 2544 %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; 2545 delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); 2546 } 2547 } 2548 } 2549 2550 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) 2551 { 2552 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) 2553 { 2554 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { 2555 $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); 2556 } 2557 } 2558 } 2559 2560 if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) 2561 { 2562 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { 2563 $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); 2564 } 2565 } 2566 2567 if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { 2568 $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); 2569 } 2570 2571 return $New; 2572 } 2573} 2574 2575sub addMissedTypes_Pre() 2576{ 2577 my %MissedTypes = (); 2578 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2579 { # detecting missed typedefs 2580 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl") 2581 { 2582 my $TypeId = getTreeAttr_Type($MissedTDid); 2583 next if(not $TypeId); 2584 my $TypeType = getTypeType($TypeId); 2585 if($TypeType eq "Unknown") 2586 { # template_type_parm 2587 next; 2588 } 2589 my $TypeDeclId = getTypeDeclId($TypeId); 2590 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId 2591 my $TypedefName = getNameByInfo($MissedTDid); 2592 next if(not $TypedefName); 2593 next if($TypedefName eq "__float80"); 2594 next if(isAnon($TypedefName)); 2595 if(not $TypeDeclId 2596 or getNameByInfo($TypeDeclId) ne $TypedefName) { 2597 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1; 2598 } 2599 } 2600 } 2601 my %AddTypes = (); 2602 foreach my $Tid (keys(%{$MissedTypes{$Version}})) 2603 { # add missed typedefs 2604 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}}); 2605 if(not @Missed or $#Missed>=1) { 2606 next; 2607 } 2608 my $MissedTDid = $Missed[0]; 2609 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid); 2610 if(not $TypedefName) { 2611 next; 2612 } 2613 my $NewId = ++$MAX_ID; 2614 my %MissedInfo = ( # typedef info 2615 "Name" => $TypedefName, 2616 "NameSpace" => $TypedefNS, 2617 "BaseType" => $Tid, 2618 "Type" => "Typedef", 2619 "Tid" => "$NewId" ); 2620 my ($H, $L) = getLocation($MissedTDid); 2621 $MissedInfo{"Header"} = $H; 2622 $MissedInfo{"Line"} = $L; 2623 if($TypedefName=~/\*|\&|\s/) 2624 { # other types 2625 next; 2626 } 2627 if($TypedefName=~/>(::\w+)+\Z/) 2628 { # QFlags<Qt::DropAction>::enum_type 2629 next; 2630 } 2631 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) 2632 { # double-check for the name of typedef 2633 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info 2634 next if(not $TName); 2635 if(length($TypedefName)>=length($TName)) 2636 { # too long typedef 2637 next; 2638 } 2639 if($TName=~/\A\Q$TypedefName\E</) { 2640 next; 2641 } 2642 if($TypedefName=~/\A\Q$TName\E/) 2643 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type 2644 next; 2645 } 2646 if(get_depth($TypedefName)==0 and get_depth($TName)!=0) 2647 { # std::_Vector_base and std::vector::_Base 2648 next; 2649 } 2650 } 2651 2652 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo; 2653 2654 # register typedef 2655 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"}; 2656 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid; 2657 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"}; 2658 } 2659 2660 # add missed & remove other 2661 $TypeInfo{$Version} = \%AddTypes; 2662 delete($Cache{"getTypeAttr"}{$Version}); 2663} 2664 2665sub addMissedTypes_Post() 2666{ 2667 foreach my $BaseId (keys(%{$MissedTypedef{$Version}})) 2668 { 2669 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"}) 2670 { 2671 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"}; 2672 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) { 2673 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"}; 2674 } 2675 } 2676 } 2677} 2678 2679sub getTypeInfo($) 2680{ 2681 my $TypeId = $_[0]; 2682 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId); 2683 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2684 if(not $TName) { 2685 delete($TypeInfo{$Version}{$TypeId}); 2686 } 2687} 2688 2689sub getArraySize($$) 2690{ 2691 my ($TypeId, $BaseName) = @_; 2692 if(my $Size = getSize($TypeId)) 2693 { 2694 my $Elems = $Size/$BYTE_SIZE; 2695 while($BaseName=~s/\s*\[(\d+)\]//) { 2696 $Elems/=$1; 2697 } 2698 if(my $BasicId = $TName_Tid{$Version}{$BaseName}) 2699 { 2700 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) { 2701 $Elems/=$BasicSize; 2702 } 2703 } 2704 return $Elems; 2705 } 2706 return 0; 2707} 2708 2709sub getTParams($$) 2710{ 2711 my ($TypeId, $Kind) = @_; 2712 my @TmplParams = (); 2713 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}}); 2714 foreach my $Pos (@Positions) 2715 { 2716 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos}; 2717 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId}; 2718 if(not $NodeType) 2719 { # typename_type 2720 return (); 2721 } 2722 if($NodeType eq "tree_vec") 2723 { 2724 if($Pos!=$#Positions) 2725 { # select last vector of parameters ( ns<P1>::type<P2> ) 2726 next; 2727 } 2728 } 2729 my @Params = get_TemplateParam($Pos, $Param_TypeId); 2730 foreach my $P (@Params) 2731 { 2732 if($P eq "") { 2733 return (); 2734 } 2735 elsif($P ne "\@skip\@") { 2736 @TmplParams = (@TmplParams, $P); 2737 } 2738 } 2739 } 2740 return @TmplParams; 2741} 2742 2743sub getTypeAttr($) 2744{ 2745 my $TypeId = $_[0]; 2746 my %TypeAttr = (); 2747 if(defined $TypeInfo{$Version}{$TypeId} 2748 and $TypeInfo{$Version}{$TypeId}{"Name"}) 2749 { # already created 2750 return %{$TypeInfo{$Version}{$TypeId}}; 2751 } 2752 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId}) 2753 { # incomplete type 2754 return (); 2755 } 2756 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1; 2757 2758 my $TypeDeclId = getTypeDeclId($TypeId); 2759 $TypeAttr{"Tid"} = $TypeId; 2760 2761 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId)) 2762 { 2763 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 2764 { 2765 if($Info=~/qual[ ]*:/) 2766 { 2767 my $NewId = ++$MAX_ID; 2768 2769 $MissedBase{$Version}{$TypeId} = "$NewId"; 2770 $MissedBase_R{$Version}{$NewId} = $TypeId; 2771 $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; 2772 $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; 2773 } 2774 } 2775 $TypeAttr{"Type"} = "Typedef"; 2776 } 2777 else { 2778 $TypeAttr{"Type"} = getTypeType($TypeId); 2779 } 2780 2781 if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) 2782 { 2783 if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") 2784 { # local code 2785 return (); 2786 } 2787 } 2788 2789 if($TypeAttr{"Type"} eq "Unknown") { 2790 return (); 2791 } 2792 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/) 2793 { 2794 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"}); 2795 if(my $TName = $TypeAttr{"Name"}) 2796 { 2797 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2798 $TName_Tid{$Version}{$TName} = $TypeId; 2799 return %TypeAttr; 2800 } 2801 else { 2802 return (); 2803 } 2804 } 2805 elsif($TypeAttr{"Type"} eq "Array") 2806 { 2807 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2808 if(not $BTid) { 2809 return (); 2810 } 2811 if(my $Algn = getAlgn($TypeId)) { 2812 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 2813 } 2814 $TypeAttr{"BaseType"} = $BTid; 2815 if(my %BTAttr = getTypeAttr($BTid)) 2816 { 2817 if(not $BTAttr{"Name"}) { 2818 return (); 2819 } 2820 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"})) 2821 { 2822 if(my $Size = getSize($TypeId)) { 2823 $TypeAttr{"Size"} = $Size/$BYTE_SIZE; 2824 } 2825 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2826 $TypeAttr{"Name"} = $1."[$NElems]".$2; 2827 } 2828 else { 2829 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]"; 2830 } 2831 } 2832 else 2833 { 2834 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer 2835 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2836 $TypeAttr{"Name"} = $1."[]".$2; 2837 } 2838 else { 2839 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]"; 2840 } 2841 } 2842 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 2843 if($BTAttr{"Header"}) { 2844 $TypeAttr{"Header"} = $BTAttr{"Header"}; 2845 } 2846 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2847 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2848 return %TypeAttr; 2849 } 2850 return (); 2851 } 2852 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) 2853 { 2854 %TypeAttr = getTrivialTypeAttr($TypeId); 2855 if($TypeAttr{"Name"}) 2856 { 2857 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2858 2859 if(not defined $IntrinsicNames{$TypeAttr{"Name"}} 2860 or getTypeDeclId($TypeAttr{"Tid"})) 2861 { # NOTE: register only one int: with built-in decl 2862 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2863 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2864 } 2865 } 2866 return %TypeAttr; 2867 } 2868 else { 2869 return (); 2870 } 2871 } 2872 elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) 2873 { 2874 %TypeAttr = getTrivialTypeAttr($TypeId); 2875 if($TypeAttr{"Name"}) 2876 { 2877 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2878 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2879 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2880 } 2881 return %TypeAttr; 2882 } 2883 else { 2884 return (); 2885 } 2886 } 2887 elsif($TypeAttr{"Type"} eq "SizeOf") 2888 { 2889 $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); 2890 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2891 $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; 2892 if($TypeAttr{"Name"}) 2893 { 2894 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2895 return %TypeAttr; 2896 } 2897 else { 2898 return (); 2899 } 2900 } 2901 else 2902 { # derived types 2903 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2904 if(not $BTid) { 2905 return (); 2906 } 2907 $TypeAttr{"BaseType"} = $BTid; 2908 if(defined $MissedTypedef{$Version}{$BTid}) 2909 { 2910 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"}) 2911 { 2912 if($MissedTDid ne $TypeDeclId) { 2913 $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"}; 2914 } 2915 } 2916 } 2917 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2918 if(not $BTAttr{"Name"}) 2919 { # templates 2920 return (); 2921 } 2922 if($BTAttr{"Type"} eq "Typedef") 2923 { # relinking typedefs 2924 my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version); 2925 if($BTAttr{"Name"} eq $BaseBase{"Name"}) { 2926 $TypeAttr{"BaseType"} = $BaseBase{"Tid"}; 2927 } 2928 } 2929 if($BTSpec) 2930 { 2931 if($TypeAttr{"Type"} eq "Pointer" 2932 and $BTAttr{"Name"}=~/\([\*]+\)/) 2933 { 2934 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2935 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g; 2936 } 2937 else { 2938 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec; 2939 } 2940 } 2941 else { 2942 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2943 } 2944 if($TypeAttr{"Type"} eq "Typedef") 2945 { 2946 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId); 2947 2948 if(index($TypeAttr{"Name"}, "tmp_add_type")==0) { 2949 return (); 2950 } 2951 2952 if(isAnon($TypeAttr{"Name"})) 2953 { # anon typedef to anon type: ._N 2954 return (); 2955 } 2956 2957 if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i) 2958 { # artificial typedef of "struct X" to "X" 2959 $TypeAttr{"Artificial"} = 1; 2960 } 2961 2962 if(my $NS = getNameSpace($TypeDeclId)) 2963 { 2964 my $TypeName = $TypeAttr{"Name"}; 2965 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/) 2966 { # "some_type" is the typedef to "struct some_type" in C++ 2967 if($3) { 2968 $TypeAttr{"Name"} = $3."::".$TypeName; 2969 } 2970 } 2971 else 2972 { 2973 $TypeAttr{"NameSpace"} = $NS; 2974 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 2975 2976 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ 2977 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/) 2978 { 2979 if($BTAttr{"NameSpace"} 2980 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</) 2981 { # types like "std::fpos<__mbstate_t>" are 2982 # not covered by typedefs in the TU dump 2983 # so trying to add such typedefs manually 2984 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 2985 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"})) 2986 { 2987 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) 2988 { # skip "other" in "std" and "type" in "boost" 2989 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"}; 2990 } 2991 } 2992 } 2993 } 2994 } 2995 } 2996 if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"} 2997 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/) 2998 { 2999 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}}) 3000 { # typedef int*const TYPEDEF; // first 3001 # int foo(TYPEDEF p); // const is optimized out 3002 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"}; 3003 if($BTAttr{"Name"}=~/</) 3004 { 3005 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) { 3006 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 3007 } 3008 } 3009 } 3010 } 3011 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId); 3012 } 3013 if(not $TypeAttr{"Size"}) 3014 { 3015 if($TypeAttr{"Type"} eq "Pointer") { 3016 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; 3017 } 3018 elsif($BTAttr{"Size"}) { 3019 $TypeAttr{"Size"} = $BTAttr{"Size"}; 3020 } 3021 } 3022 if(my $Algn = getAlgn($TypeId)) { 3023 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3024 } 3025 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3026 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) { 3027 $TypeAttr{"Header"} = $BTAttr{"Header"}; 3028 } 3029 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 3030 if($TypeAttr{"Name"} ne $BTAttr{"Name"}) 3031 { # typedef to "class Class" 3032 # should not be registered in TName_Tid 3033 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 3034 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 3035 } 3036 } 3037 return %TypeAttr; 3038 } 3039} 3040 3041sub getTreeVec($) 3042{ 3043 my %Vector = (); 3044 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3045 { 3046 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 3047 { # string length is N-1 because of the null terminator 3048 $Vector{$1} = $2; 3049 } 3050 } 3051 return \%Vector; 3052} 3053 3054sub get_TemplateParam($$) 3055{ 3056 my ($Pos, $Type_Id) = @_; 3057 return () if(not $Type_Id); 3058 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id}; 3059 return () if(not $NodeType); 3060 if($NodeType eq "integer_cst") 3061 { # int (1), unsigned (2u), char ('c' as 99), ... 3062 my $CstTid = getTreeAttr_Type($Type_Id); 3063 my %CstType = getTypeAttr($CstTid); # without recursion 3064 my $Num = getNodeIntCst($Type_Id); 3065 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) { 3066 return ($Num.$CstSuffix); 3067 } 3068 else { 3069 return ("(".$CstType{"Name"}.")".$Num); 3070 } 3071 } 3072 elsif($NodeType eq "string_cst") { 3073 return (getNodeStrCst($Type_Id)); 3074 } 3075 elsif($NodeType eq "tree_vec") 3076 { 3077 my $Vector = getTreeVec($Type_Id); 3078 my @Params = (); 3079 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector})) 3080 { 3081 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) { 3082 push(@Params, $P2); 3083 } 3084 } 3085 return @Params; 3086 } 3087 elsif($NodeType eq "parm_decl") 3088 { 3089 (getNameByInfo($Type_Id)); 3090 } 3091 else 3092 { 3093 my %ParamAttr = getTypeAttr($Type_Id); 3094 my $PName = $ParamAttr{"Name"}; 3095 if(not $PName) { 3096 return (); 3097 } 3098 if($PName=~/\>/) 3099 { 3100 if(my $Cover = cover_stdcxx_typedef($PName)) { 3101 $PName = $Cover; 3102 } 3103 } 3104 if($Pos>=1 and 3105 $PName=~/\A$DEFAULT_STD_PARMS\</) 3106 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> > 3107 # template<typename _Key, typename _Compare = std::less<_Key> 3108 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> > 3109 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> > 3110 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> > 3111 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> > 3112 return ("\@skip\@"); 3113 } 3114 return ($PName); 3115 } 3116} 3117 3118sub cover_stdcxx_typedef($) 3119{ 3120 my $TypeName = $_[0]; 3121 if(my @Covers = sort {length($a)<=>length($b)} 3122 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3123 { # take the shortest typedef 3124 # FIXME: there may be more than 3125 # one typedefs to the same type 3126 return $Covers[0]; 3127 } 3128 my $Covered = $TypeName; 3129 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){}; 3130 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3131 { 3132 if(my $Cover = $Covers[0]) 3133 { 3134 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g; 3135 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g; 3136 } 3137 } 3138 return formatName($Covered, "T"); 3139} 3140 3141sub getNodeIntCst($) 3142{ 3143 my $CstId = $_[0]; 3144 my $CstTypeId = getTreeAttr_Type($CstId); 3145 if($EnumMembName_Id{$Version}{$CstId}) { 3146 return $EnumMembName_Id{$Version}{$CstId}; 3147 } 3148 elsif((my $Value = getTreeValue($CstId)) ne "") 3149 { 3150 if($Value eq "0") 3151 { 3152 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3153 return "false"; 3154 } 3155 else { 3156 return "0"; 3157 } 3158 } 3159 elsif($Value eq "1") 3160 { 3161 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3162 return "true"; 3163 } 3164 else { 3165 return "1"; 3166 } 3167 } 3168 else { 3169 return $Value; 3170 } 3171 } 3172 return ""; 3173} 3174 3175sub getNodeStrCst($) 3176{ 3177 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3178 { 3179 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/) 3180 { 3181 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst") 3182 { # string length is N-1 because of the null terminator 3183 return substr($1, 0, $2-1); 3184 } 3185 else 3186 { # identifier_node 3187 return substr($1, 0, $2); 3188 } 3189 } 3190 } 3191 return ""; 3192} 3193 3194sub getMemPtrAttr($$$) 3195{ # function, method and field pointers 3196 my ($PtrId, $TypeId, $Type) = @_; 3197 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId}; 3198 if($Type eq "FieldPtr") { 3199 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId}; 3200 } 3201 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId}; 3202 my $MemPtrName = ""; 3203 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId); 3204 if($Type eq "MethodPtr") 3205 { # size of "method pointer" may be greater than WORD size 3206 if(my $Size = getSize($TypeId)) 3207 { 3208 $Size/=$BYTE_SIZE; 3209 $TypeAttr{"Size"} = "$Size"; 3210 } 3211 } 3212 if(my $Algn = getAlgn($TypeId)) { 3213 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3214 } 3215 # Return 3216 if($Type eq "FieldPtr") 3217 { 3218 my %ReturnAttr = getTypeAttr($PtrId); 3219 if($ReturnAttr{"Name"}) { 3220 $MemPtrName .= $ReturnAttr{"Name"}; 3221 } 3222 $TypeAttr{"Return"} = $PtrId; 3223 } 3224 else 3225 { 3226 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /) 3227 { 3228 my $ReturnTypeId = $1; 3229 my %ReturnAttr = getTypeAttr($ReturnTypeId); 3230 if(not $ReturnAttr{"Name"}) 3231 { # templates 3232 return (); 3233 } 3234 $MemPtrName .= $ReturnAttr{"Name"}; 3235 $TypeAttr{"Return"} = $ReturnTypeId; 3236 } 3237 } 3238 # Class 3239 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /) 3240 { 3241 $TypeAttr{"Class"} = $2; 3242 my %Class = getTypeAttr($TypeAttr{"Class"}); 3243 if($Class{"Name"}) { 3244 $MemPtrName .= " (".$Class{"Name"}."\:\:*)"; 3245 } 3246 else { 3247 $MemPtrName .= " (*)"; 3248 } 3249 } 3250 else { 3251 $MemPtrName .= " (*)"; 3252 } 3253 # Parameters 3254 if($Type eq "FuncPtr" 3255 or $Type eq "MethodPtr") 3256 { 3257 my @ParamTypeName = (); 3258 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /) 3259 { 3260 my $PTypeInfoId = $1; 3261 my ($Pos, $PPos) = (0, 0); 3262 while($PTypeInfoId) 3263 { 3264 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId}; 3265 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /) 3266 { 3267 my $PTypeId = $1; 3268 my %ParamAttr = getTypeAttr($PTypeId); 3269 if(not $ParamAttr{"Name"}) 3270 { # templates (template_type_parm), etc. 3271 return (); 3272 } 3273 if($ParamAttr{"Name"} eq "void") { 3274 last; 3275 } 3276 if($Pos!=0 or $Type ne "MethodPtr") 3277 { 3278 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId; 3279 push(@ParamTypeName, $ParamAttr{"Name"}); 3280 } 3281 if($PTypeInfoId = getNextElem($PTypeInfoId)) { 3282 $Pos+=1; 3283 } 3284 else { 3285 last; 3286 } 3287 } 3288 else { 3289 last; 3290 } 3291 } 3292 } 3293 $MemPtrName .= " (".join(", ", @ParamTypeName).")"; 3294 } 3295 $TypeAttr{"Name"} = formatName($MemPtrName, "T"); 3296 return %TypeAttr; 3297} 3298 3299sub getTreeTypeName($) 3300{ 3301 my $TypeId = $_[0]; 3302 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3303 { 3304 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type") 3305 { 3306 if(my $Name = getNameByInfo($TypeId)) 3307 { # bit_size_type 3308 return $Name; 3309 } 3310 elsif($Info=~/unsigned/) { 3311 return "unsigned int"; 3312 } 3313 else { 3314 return "int"; 3315 } 3316 } 3317 elsif($Info=~/name[ ]*:[ ]*@(\d+) /) { 3318 return getNameByInfo($1); 3319 } 3320 } 3321 return ""; 3322} 3323 3324sub isFuncPtr($) 3325{ 3326 my $Ptd = pointTo($_[0]); 3327 return 0 if(not $Ptd); 3328 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3329 { 3330 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) { 3331 return 0; 3332 } 3333 } 3334 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]} 3335 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd}) 3336 { 3337 if($InfoT1 eq "pointer_type" 3338 and $InfoT2 eq "function_type") { 3339 return 1; 3340 } 3341 } 3342 return 0; 3343} 3344 3345sub isMethodPtr($) 3346{ 3347 my $Ptd = pointTo($_[0]); 3348 return 0 if(not $Ptd); 3349 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3350 { 3351 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type" 3352 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type" 3353 and $Info=~/ ptrmem /) { 3354 return 1; 3355 } 3356 } 3357 return 0; 3358} 3359 3360sub isFieldPtr($) 3361{ 3362 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3363 { 3364 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type" 3365 and $Info=~/ ptrmem /) { 3366 return 1; 3367 } 3368 } 3369 return 0; 3370} 3371 3372sub pointTo($) 3373{ 3374 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3375 { 3376 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) { 3377 return $1; 3378 } 3379 } 3380 return ""; 3381} 3382 3383sub getTypeTypeByTypeId($) 3384{ 3385 my $TypeId = $_[0]; 3386 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId}) 3387 { 3388 my $NType = $NodeType{$TType}; 3389 if($NType eq "Intrinsic") { 3390 return $NType; 3391 } 3392 elsif(isFuncPtr($TypeId)) { 3393 return "FuncPtr"; 3394 } 3395 elsif(isMethodPtr($TypeId)) { 3396 return "MethodPtr"; 3397 } 3398 elsif(isFieldPtr($TypeId)) { 3399 return "FieldPtr"; 3400 } 3401 elsif($NType ne "Other") { 3402 return $NType; 3403 } 3404 } 3405 return "Unknown"; 3406} 3407 3408my %UnQual = ( 3409 "r"=>"restrict", 3410 "v"=>"volatile", 3411 "c"=>"const", 3412 "cv"=>"const volatile" 3413); 3414 3415sub getQual($) 3416{ 3417 my $TypeId = $_[0]; 3418 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3419 { 3420 my ($Qual, $To) = (); 3421 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) { 3422 $Qual = $UnQual{$1}; 3423 } 3424 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { 3425 $To = $1; 3426 } 3427 if($Qual and $To) { 3428 return ($Qual, $To); 3429 } 3430 } 3431 return (); 3432} 3433 3434sub getQualType($) 3435{ 3436 if($_[0] eq "const volatile") { 3437 return "ConstVolatile"; 3438 } 3439 return ucfirst($_[0]); 3440} 3441 3442sub getTypeType($) 3443{ 3444 my $TypeId = $_[0]; 3445 my $TypeDeclId = getTypeDeclId($TypeId); 3446 if(defined $MissedTypedef{$Version}{$TypeId}) 3447 { # support for old GCC versions 3448 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) { 3449 return "Typedef"; 3450 } 3451 } 3452 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3453 my ($Qual, $To) = getQual($TypeId); 3454 if(($Qual or $To) and $TypeDeclId 3455 and (getTypeId($TypeDeclId) ne $TypeId)) 3456 { # qualified types (special) 3457 return getQualType($Qual); 3458 } 3459 elsif(not $MissedBase_R{$Version}{$TypeId} 3460 and isTypedef($TypeId)) { 3461 return "Typedef"; 3462 } 3463 elsif($Qual) 3464 { # qualified types 3465 return getQualType($Qual); 3466 } 3467 3468 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) 3469 { # typedef struct { ... } name 3470 $TypeTypedef{$Version}{$TypeId} = $1; 3471 } 3472 3473 my $TypeType = getTypeTypeByTypeId($TypeId); 3474 if($TypeType eq "Struct") 3475 { 3476 if($TypeDeclId 3477 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") { 3478 return "Template"; 3479 } 3480 } 3481 return $TypeType; 3482} 3483 3484sub isTypedef($) 3485{ 3486 if($_[0]) 3487 { 3488 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") 3489 { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); 3490 return 0; 3491 } 3492 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3493 { 3494 if(my $TDid = getTypeDeclId($_[0])) 3495 { 3496 if(getTypeId($TDid) eq $_[0] 3497 and getNameByInfo($TDid)) 3498 { 3499 if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { 3500 return $1; 3501 } 3502 } 3503 } 3504 } 3505 } 3506 return 0; 3507} 3508 3509sub selectBaseType($) 3510{ 3511 my $TypeId = $_[0]; 3512 if(defined $MissedTypedef{$Version}{$TypeId}) 3513 { # add missed typedefs 3514 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) { 3515 return ($TypeId, ""); 3516 } 3517 } 3518 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3519 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId}; 3520 3521 my $MB_R = $MissedBase_R{$Version}{$TypeId}; 3522 my $MB = $MissedBase{$Version}{$TypeId}; 3523 3524 my ($Qual, $To) = getQual($TypeId); 3525 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) / 3526 and (getTypeId($1) ne $TypeId) 3527 and (not $MB_R or getTypeId($1) ne $MB_R)) 3528 { # qualified types (special) 3529 return (getTypeId($1), $Qual); 3530 } 3531 elsif($MB) 3532 { # add base 3533 return ($MB, ""); 3534 } 3535 elsif(not $MB_R and my $Bid = isTypedef($TypeId)) 3536 { # typedefs 3537 return ($Bid, ""); 3538 } 3539 elsif($Qual or $To) 3540 { # qualified types 3541 return ($To, $Qual); 3542 } 3543 elsif($InfoType eq "reference_type") 3544 { 3545 if($Info=~/refd[ ]*:[ ]*@(\d+) /) { 3546 return ($1, "&"); 3547 } 3548 } 3549 elsif($InfoType eq "array_type") 3550 { 3551 if($Info=~/elts[ ]*:[ ]*@(\d+) /) { 3552 return ($1, ""); 3553 } 3554 } 3555 elsif($InfoType eq "pointer_type") 3556 { 3557 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { 3558 return ($1, "*"); 3559 } 3560 } 3561 3562 return (0, ""); 3563} 3564 3565sub getSymbolInfo_All() 3566{ 3567 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3568 { # reverse order 3569 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") { 3570 getSymbolInfo($_); 3571 } 3572 } 3573 3574 if($ADD_TMPL_INSTANCES) 3575 { 3576 # templates 3577 foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) 3578 { 3579 my %Map = (); 3580 3581 if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) 3582 { 3583 if(defined $TemplateMap{$Version}{$ClassId}) 3584 { 3585 foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { 3586 $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; 3587 } 3588 } 3589 } 3590 3591 if(defined $TemplateMap{$Version}{$Sid}) 3592 { 3593 foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { 3594 $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; 3595 } 3596 } 3597 3598 if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) 3599 { 3600 foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) 3601 { 3602 my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; 3603 $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); 3604 } 3605 } 3606 if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { 3607 $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); 3608 } 3609 } 3610 } 3611} 3612 3613sub getVarInfo_All() 3614{ 3615 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3616 { # reverse order 3617 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") { 3618 getVarInfo($_); 3619 } 3620 } 3621} 3622 3623sub isBuiltIn($) { 3624 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./); 3625} 3626 3627sub getVarInfo($) 3628{ 3629 my $InfoId = $_[0]; 3630 if(my $NSid = getTreeAttr_Scpe($InfoId)) 3631 { 3632 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid}; 3633 if($NSInfoType and $NSInfoType eq "function_decl") { 3634 return; 3635 } 3636 } 3637 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 3638 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 3639 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { 3640 delete($SymbolInfo{$Version}{$InfoId}); 3641 return; 3642 } 3643 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId)); 3644 if(not $ShortName) { 3645 delete($SymbolInfo{$Version}{$InfoId}); 3646 return; 3647 } 3648 if($ShortName=~/\Atmp_add_class_\d+\Z/) { 3649 delete($SymbolInfo{$Version}{$InfoId}); 3650 return; 3651 } 3652 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName; 3653 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 3654 { 3655 if($OSgroup eq "windows") 3656 { # cut the offset 3657 $MnglName=~s/\@\d+\Z//g; 3658 } 3659 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 3660 } 3661 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 3662 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 3663 { # validate mangled name 3664 delete($SymbolInfo{$Version}{$InfoId}); 3665 return; 3666 } 3667 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3668 and index($ShortName, "_Z")==0) 3669 { # _ZTS, etc. 3670 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3671 } 3672 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"})) 3673 { # non-public global data 3674 delete($SymbolInfo{$Version}{$InfoId}); 3675 return; 3676 } 3677 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; 3678 if(my $Rid = getTypeId($InfoId)) 3679 { 3680 if(not defined $TypeInfo{$Version}{$Rid} 3681 or not $TypeInfo{$Version}{$Rid}{"Name"}) 3682 { 3683 delete($SymbolInfo{$Version}{$InfoId}); 3684 return; 3685 } 3686 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid; 3687 my $Val = getDataVal($InfoId, $Rid); 3688 if(defined $Val) { 3689 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val; 3690 } 3691 } 3692 set_Class_And_Namespace($InfoId); 3693 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 3694 { 3695 if(not defined $TypeInfo{$Version}{$ClassId} 3696 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 3697 { 3698 delete($SymbolInfo{$Version}{$InfoId}); 3699 return; 3700 } 3701 } 3702 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 3703 { # extern "C" 3704 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 3705 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3706 } 3707 if($UserLang and $UserLang eq "C") 3708 { # --lang=C option 3709 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3710 } 3711 if(not $CheckHeadersOnly) 3712 { 3713 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}) 3714 { 3715 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3716 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 3717 { 3718 if(link_symbol($ShortName, $Version, "-Deps")) 3719 { # "const" global data is mangled as _ZL... in the TU dump 3720 # but not mangled when compiling a C shared library 3721 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3722 } 3723 } 3724 } 3725 } 3726 if($COMMON_LANGUAGE{$Version} eq "C++") 3727 { 3728 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3729 { # for some symbols (_ZTI) the short name is the mangled name 3730 if(index($ShortName, "_Z")==0) { 3731 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3732 } 3733 } 3734 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3735 { # try to mangle symbol (link with libraries) 3736 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId); 3737 } 3738 if($OStarget eq "windows") 3739 { 3740 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 3741 { # link MS C++ symbols from library with GCC symbols from headers 3742 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 3743 } 3744 } 3745 } 3746 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { 3747 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3748 } 3749 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3750 { 3751 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 3752 { # non-target symbols 3753 delete($SymbolInfo{$Version}{$InfoId}); 3754 return; 3755 } 3756 } 3757 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 3758 { 3759 if(defined $MissedTypedef{$Version}{$Rid}) 3760 { 3761 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 3762 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 3763 } 3764 } 3765 } 3766 setFuncAccess($InfoId); 3767 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) { 3768 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 3769 } 3770 if($ShortName=~/\A(_Z|\?)/) { 3771 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"}); 3772 } 3773 3774 if($ExtraDump) { 3775 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 3776 } 3777} 3778 3779sub isConstType($$) 3780{ 3781 my ($TypeId, $LibVersion) = @_; 3782 my %Base = get_Type($TypeId, $LibVersion); 3783 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { 3784 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion}); 3785 } 3786 return ($Base{"Type"} eq "Const"); 3787} 3788 3789sub getTrivialName($$) 3790{ 3791 my ($TypeInfoId, $TypeId) = @_; 3792 my %TypeAttr = (); 3793 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId); 3794 if(not $TypeAttr{"Name"}) { 3795 $TypeAttr{"Name"} = getTreeTypeName($TypeId); 3796 } 3797 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3798 $TypeAttr{"Type"} = getTypeType($TypeId); 3799 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name 3800 if(isAnon($TypeAttr{"Name"})) 3801 { 3802 my $NameSpaceId = $TypeId; 3803 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId))) 3804 { # searching for a first not anon scope 3805 if($NSId eq $NameSpaceId) { 3806 last; 3807 } 3808 else 3809 { 3810 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId)); 3811 if(not $TypeAttr{"NameSpace"} 3812 or not isAnon($TypeAttr{"NameSpace"})) { 3813 last; 3814 } 3815 } 3816 $NameSpaceId = $NSId; 3817 } 3818 } 3819 else 3820 { 3821 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId)) 3822 { 3823 if($NameSpaceId ne $TypeId) { 3824 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId); 3825 } 3826 } 3827 } 3828 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) { 3829 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3830 } 3831 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3832 if(isAnon($TypeAttr{"Name"})) 3833 { # anon-struct-header.h-line 3834 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-"; 3835 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"}; 3836 if($TypeAttr{"NameSpace"}) { 3837 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3838 } 3839 } 3840 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId} 3841 and getTypeDeclId($TypeId) eq $TypeInfoId) 3842 { 3843 if(my @TParams = getTParams($TypeId, "Type")) { 3844 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); 3845 } 3846 else { 3847 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."<...>", "T"); 3848 } 3849 } 3850 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); 3851} 3852 3853sub getTrivialTypeAttr($) 3854{ 3855 my $TypeId = $_[0]; 3856 my $TypeInfoId = getTypeDeclId($_[0]); 3857 3858 my %TypeAttr = (); 3859 3860 if($TemplateDecl{$Version}{$TypeId}) 3861 { # template_decl 3862 $TypeAttr{"Template"} = 1; 3863 } 3864 3865 setTypeAccess($TypeId, \%TypeAttr); 3866 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3867 if(isBuiltIn($TypeAttr{"Header"})) 3868 { 3869 delete($TypeAttr{"Header"}); 3870 delete($TypeAttr{"Line"}); 3871 } 3872 3873 $TypeAttr{"Type"} = getTypeType($TypeId); 3874 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId); 3875 if(not $TypeAttr{"Name"}) { 3876 return (); 3877 } 3878 if(not $TypeAttr{"NameSpace"}) { 3879 delete($TypeAttr{"NameSpace"}); 3880 } 3881 3882 if($TypeAttr{"Type"} eq "Intrinsic") 3883 { 3884 if(defined $TypeAttr{"Header"}) 3885 { 3886 if($TypeAttr{"Header"}=~/\Adump[1-2]\.[ih]\Z/) 3887 { # support for SUSE 11.2 3888 # integer_type has srcp dump{1-2}.i 3889 delete($TypeAttr{"Header"}); 3890 } 3891 } 3892 } 3893 3894 my $Tmpl = undef; 3895 3896 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 3897 { 3898 $Tmpl = $BasicTemplate{$Version}{$TypeId}; 3899 3900 if(my @TParams = getTParams($TypeId, "Type")) 3901 { 3902 foreach my $Pos (0 .. $#TParams) 3903 { 3904 my $Val = $TParams[$Pos]; 3905 $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; 3906 3907 if(not defined $TypeAttr{"Template"}) 3908 { 3909 my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); 3910 3911 if($Base{"Type"} eq "TemplateParam" 3912 or defined $Base{"Template"}) { 3913 $TypeAttr{"Template"} = 1; 3914 } 3915 } 3916 3917 if($Tmpl) 3918 { 3919 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 3920 { 3921 $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; 3922 3923 if($Val eq $Arg) { 3924 $TypeAttr{"Template"} = 1; 3925 } 3926 } 3927 } 3928 } 3929 3930 if($Tmpl) 3931 { 3932 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 3933 { 3934 if($Pos>$#TParams) 3935 { 3936 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 3937 $TemplateMap{$Version}{$TypeId}{$Arg} = ""; 3938 } 3939 } 3940 } 3941 } 3942 3943 if($ADD_TMPL_INSTANCES) 3944 { 3945 if($Tmpl) 3946 { 3947 if(my $MainInst = getTreeAttr_Type($Tmpl)) 3948 { 3949 if(not getTreeAttr_Flds($TypeId)) 3950 { 3951 if(my $Flds = getTreeAttr_Flds($MainInst)) { 3952 $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; 3953 } 3954 } 3955 if(not getTreeAttr_Binf($TypeId)) 3956 { 3957 if(my $Binf = getTreeAttr_Binf($MainInst)) { 3958 $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; 3959 } 3960 } 3961 } 3962 } 3963 } 3964 } 3965 3966 my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); 3967 3968 if(my $Size = getSize($TypeId)) 3969 { 3970 $Size = $Size/$BYTE_SIZE; 3971 $TypeAttr{"Size"} = "$Size"; 3972 } 3973 else 3974 { 3975 if($ExtraDump) 3976 { 3977 if(not defined $TypeAttr{"Memb"} 3978 and not $Tmpl) 3979 { # declaration only 3980 $TypeAttr{"Forward"} = 1; 3981 } 3982 } 3983 } 3984 3985 if($TypeAttr{"Type"} eq "Struct" 3986 and ($StaticFields or detect_lang($TypeId))) 3987 { 3988 $TypeAttr{"Type"} = "Class"; 3989 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo() 3990 } 3991 if($TypeAttr{"Type"} eq "Struct" 3992 or $TypeAttr{"Type"} eq "Class") 3993 { 3994 my $Skip = setBaseClasses($TypeId, \%TypeAttr); 3995 if($Skip) { 3996 return (); 3997 } 3998 } 3999 if(my $Algn = getAlgn($TypeId)) { 4000 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 4001 } 4002 setSpec($TypeId, \%TypeAttr); 4003 4004 if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) 4005 { 4006 if(not $TypedefToAnon{$TypeId} 4007 and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 4008 { 4009 if(not isAnon($TypeAttr{"Name"})) { 4010 $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; 4011 } 4012 } 4013 } 4014 4015 $TypeAttr{"Tid"} = $TypeId; 4016 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}}) 4017 { 4018 my @Entries = split(/\n/, $VTable); 4019 foreach (1 .. $#Entries) 4020 { 4021 my $Entry = $Entries[$_]; 4022 if($Entry=~/\A(\d+)\s+(.+)\Z/) { 4023 $TypeAttr{"VTable"}{$1} = simplifyVTable($2); 4024 } 4025 } 4026 } 4027 4028 if($TypeAttr{"Type"} eq "Enum") 4029 { 4030 if(not $TypeAttr{"NameSpace"}) 4031 { 4032 foreach my $Pos (keys(%{$TypeAttr{"Memb"}})) 4033 { 4034 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"}; 4035 my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"}; 4036 $EnumConstants{$Version}{$MName} = { 4037 "Value"=>$MVal, 4038 "Header"=>$TypeAttr{"Header"} 4039 }; 4040 if(isAnon($TypeAttr{"Name"})) 4041 { 4042 if($ExtraDump 4043 or is_target_header($TypeAttr{"Header"}, $Version)) 4044 { 4045 %{$Constants{$Version}{$MName}} = ( 4046 "Value" => $MVal, 4047 "Header" => $TypeAttr{"Header"} 4048 ); 4049 } 4050 } 4051 } 4052 } 4053 } 4054 if($ExtraDump) 4055 { 4056 if(defined $TypedefToAnon{$TypeId}) { 4057 $TypeAttr{"AnonTypedef"} = 1; 4058 } 4059 } 4060 4061 return %TypeAttr; 4062} 4063 4064sub simplifyVTable($) 4065{ 4066 my $Content = $_[0]; 4067 if($Content=~s/ \[with (.+)]//) 4068 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>] 4069 if(my @Elems = separate_Params($1, 0, 0)) 4070 { 4071 foreach my $Elem (@Elems) 4072 { 4073 if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) 4074 { 4075 my ($Arg, $Val) = ($1, $2); 4076 4077 if(defined $DEFAULT_STD_ARGS{$Arg}) { 4078 $Content=~s/,\s*$Arg\b//g; 4079 } 4080 else { 4081 $Content=~s/\b$Arg\b/$Val/g; 4082 } 4083 } 4084 } 4085 } 4086 } 4087 4088 return $Content; 4089} 4090 4091sub detect_lang($) 4092{ 4093 my $TypeId = $_[0]; 4094 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4095 if(check_gcc($GCC_PATH, "4")) 4096 { # GCC 4 fncs-node points to only non-artificial methods 4097 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /); 4098 } 4099 else 4100 { # GCC 3 4101 my $Fncs = getTreeAttr_Fncs($TypeId); 4102 while($Fncs) 4103 { 4104 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) { 4105 return 1; 4106 } 4107 $Fncs = getTreeAttr_Chan($Fncs); 4108 } 4109 } 4110 return 0; 4111} 4112 4113sub setSpec($$) 4114{ 4115 my ($TypeId, $TypeAttr) = @_; 4116 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4117 if($Info=~/\s+spec\s+/) { 4118 $TypeAttr->{"Spec"} = 1; 4119 } 4120} 4121 4122sub setBaseClasses($$) 4123{ 4124 my ($TypeId, $TypeAttr) = @_; 4125 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4126 if(my $Binf = getTreeAttr_Binf($TypeId)) 4127 { 4128 my $Info = $LibInfo{$Version}{"info"}{$Binf}; 4129 my $Pos = 0; 4130 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) 4131 { 4132 my ($Access, $BInfoId) = ($1, $2); 4133 my $ClassId = getBinfClassId($BInfoId); 4134 4135 if($ClassId==$TypeId) 4136 { # class A<N>:public A<N-1> 4137 next; 4138 } 4139 4140 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId}; 4141 if(not $CType or $CType eq "template_type_parm" 4142 or $CType eq "typename_type") 4143 { # skip 4144 # return 1; 4145 } 4146 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; 4147 if($Access=~/prot/) { 4148 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected"; 4149 } 4150 elsif($Access=~/priv/) { 4151 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private"; 4152 } 4153 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos"; 4154 if($BaseInfo=~/virt/) 4155 { # virtual base 4156 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1; 4157 } 4158 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1; 4159 $Pos += 1; 4160 } 4161 } 4162 return 0; 4163} 4164 4165sub getBinfClassId($) 4166{ 4167 my $Info = $LibInfo{$Version}{"info"}{$_[0]}; 4168 $Info=~/type[ ]*:[ ]*@(\d+) /; 4169 return $1; 4170} 4171 4172sub unmangledFormat($$) 4173{ 4174 my ($Name, $LibVersion) = @_; 4175 $Name = uncover_typedefs($Name, $LibVersion); 4176 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){}; 4177 $Name=~s/\(\w+\)(\d)/$1/; 4178 return $Name; 4179} 4180 4181sub modelUnmangled($$) 4182{ 4183 my ($InfoId, $Compiler) = @_; 4184 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) { 4185 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}; 4186 } 4187 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 4188 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4189 $PureSignature = "~".$PureSignature; 4190 } 4191 if(not $SymbolInfo{$Version}{$InfoId}{"Data"}) 4192 { 4193 my (@Params, @ParamTypes) = (); 4194 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"} 4195 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4196 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}}); 4197 } 4198 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4199 { # checking parameters 4200 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4201 my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; 4202 my %PType = get_PureType($PId, $TypeInfo{$Version}); 4203 my $PTName = unmangledFormat($PType{"Name"}, $Version); 4204 4205 if($PName eq "this" 4206 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") 4207 { 4208 next; 4209 } 4210 4211 $PTName=~s/\b(restrict|register)\b//g; 4212 if($Compiler eq "MSVC") { 4213 $PTName=~s/\blong long\b/__int64/; 4214 } 4215 @ParamTypes = (@ParamTypes, $PTName); 4216 } 4217 if(@ParamTypes) { 4218 $PureSignature .= "(".join(", ", @ParamTypes).")"; 4219 } 4220 else 4221 { 4222 if($Compiler eq "MSVC") 4223 { 4224 $PureSignature .= "(void)"; 4225 } 4226 else 4227 { # GCC 4228 $PureSignature .= "()"; 4229 } 4230 } 4231 $PureSignature = delete_keywords($PureSignature); 4232 } 4233 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 4234 { 4235 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version); 4236 $PureSignature = $ClassName."::".$PureSignature; 4237 } 4238 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { 4239 $PureSignature = $NS."::".$PureSignature; 4240 } 4241 if($SymbolInfo{$Version}{$InfoId}{"Const"}) { 4242 $PureSignature .= " const"; 4243 } 4244 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) { 4245 $PureSignature .= " volatile"; 4246 } 4247 my $ShowReturn = 0; 4248 if($Compiler eq "MSVC" 4249 and $SymbolInfo{$Version}{$InfoId}{"Data"}) 4250 { 4251 $ShowReturn=1; 4252 } 4253 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId} 4254 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}})) 4255 { 4256 $ShowReturn=1; 4257 } 4258 if($ShowReturn) 4259 { # mangled names for template function specializations include return value 4260 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"}) 4261 { 4262 my %RType = get_PureType($ReturnId, $TypeInfo{$Version}); 4263 my $ReturnName = unmangledFormat($RType{"Name"}, $Version); 4264 $PureSignature = $ReturnName." ".$PureSignature; 4265 } 4266 } 4267 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S")); 4268} 4269 4270sub mangle_symbol($$$) 4271{ # mangling for simple methods 4272 # see gcc-4.6.0/gcc/cp/mangle.c 4273 my ($InfoId, $LibVersion, $Compiler) = @_; 4274 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) { 4275 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}; 4276 } 4277 my $Mangled = ""; 4278 if($Compiler eq "GCC") { 4279 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion); 4280 } 4281 elsif($Compiler eq "MSVC") { 4282 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion); 4283 } 4284 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled); 4285} 4286 4287sub mangle_symbol_MSVC($$) 4288{ # TODO 4289 my ($InfoId, $LibVersion) = @_; 4290 return ""; 4291} 4292 4293sub mangle_symbol_GCC($$) 4294{ # see gcc-4.6.0/gcc/cp/mangle.c 4295 my ($InfoId, $LibVersion) = @_; 4296 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, ""); 4297 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 4298 my %Repl = ();# SN_ replacements 4299 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 4300 { 4301 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl); 4302 if($MangledClass!~/\AN/) { 4303 $MangledClass = "N".$MangledClass; 4304 } 4305 else { 4306 $MangledClass=~s/E\Z//; 4307 } 4308 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) { 4309 $MangledClass=~s/\AN/NV/; 4310 } 4311 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) { 4312 $MangledClass=~s/\AN/NK/; 4313 } 4314 $Mangled .= $MangledClass; 4315 } 4316 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"}) 4317 { # mangled by name due to the absence of structured info 4318 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl); 4319 if($MangledNS!~/\AN/) { 4320 $MangledNS = "N".$MangledNS; 4321 } 4322 else { 4323 $MangledNS=~s/E\Z//; 4324 } 4325 $Mangled .= $MangledNS; 4326 } 4327 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}); 4328 my @TParams = (); 4329 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) 4330 { # parsing mode 4331 foreach (@TPos) { 4332 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"}); 4333 } 4334 } 4335 elsif($TmplParams) 4336 { # remangling mode 4337 # support for old ABI dumps 4338 @TParams = separate_Params($TmplParams, 0, 0); 4339 } 4340 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { 4341 $Mangled .= "C1"; 4342 } 4343 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4344 $Mangled .= "D0"; 4345 } 4346 elsif($ShortName) 4347 { 4348 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4349 { 4350 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 4351 and isConstType($Return, $LibVersion)) 4352 { # "const" global data is mangled as _ZL... 4353 $Mangled .= "L"; 4354 } 4355 } 4356 if($ShortName=~/\Aoperator(\W.*)\Z/) 4357 { 4358 my $Op = $1; 4359 $Op=~s/\A[ ]+//g; 4360 if(my $OpMngl = $OperatorMangling{$Op}) { 4361 $Mangled .= $OpMngl; 4362 } 4363 else { # conversion operator 4364 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl); 4365 } 4366 } 4367 else { 4368 $Mangled .= length($ShortName).$ShortName; 4369 } 4370 if(@TParams) 4371 { # templates 4372 $Mangled .= "I"; 4373 foreach my $TParam (@TParams) { 4374 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl); 4375 } 4376 $Mangled .= "E"; 4377 } 4378 if(not $ClassId and @TParams) { 4379 add_substitution($ShortName, \%Repl, 0); 4380 } 4381 } 4382 if($ClassId or $NameSpace) { 4383 $Mangled .= "E"; 4384 } 4385 if(@TParams) 4386 { 4387 if($Return) { 4388 $Mangled .= mangle_param($Return, $LibVersion, \%Repl); 4389 } 4390 } 4391 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4392 { 4393 my @Params = (); 4394 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 4395 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4396 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 4397 } 4398 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4399 { # checking parameters 4400 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4401 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl); 4402 } 4403 if(not @Params) { 4404 $Mangled .= "v"; 4405 } 4406 } 4407 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled); 4408 $Mangled = write_stdcxx_substitution($Mangled); 4409 if($Mangled eq "_Z") { 4410 return ""; 4411 } 4412 return $Mangled; 4413} 4414 4415sub correct_incharge($$$) 4416{ 4417 my ($InfoId, $LibVersion, $Mangled) = @_; 4418 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) 4419 { 4420 if($MangledNames{$LibVersion}{$Mangled}) { 4421 $Mangled=~s/C1([EI])/C2$1/; 4422 } 4423 } 4424 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 4425 { 4426 if($MangledNames{$LibVersion}{$Mangled}) { 4427 $Mangled=~s/D0([EI])/D1$1/; 4428 } 4429 if($MangledNames{$LibVersion}{$Mangled}) { 4430 $Mangled=~s/D1([EI])/D2$1/; 4431 } 4432 } 4433 return $Mangled; 4434} 4435 4436sub template_Base($) 4437{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl 4438 # NOTE: operators: >>, << 4439 my $Name = $_[0]; 4440 if($Name!~/>\Z/ or $Name!~/</) { 4441 return $Name; 4442 } 4443 my $TParams = $Name; 4444 while(my $CPos = find_center($TParams, "<")) 4445 { # search for the last <T> 4446 $TParams = substr($TParams, $CPos); 4447 } 4448 if($TParams=~s/\A<(.+)>\Z/$1/) { 4449 $Name=~s/<\Q$TParams\E>\Z//; 4450 } 4451 else 4452 { # error 4453 $TParams = ""; 4454 } 4455 return ($Name, $TParams); 4456} 4457 4458sub get_sub_ns($) 4459{ 4460 my $Name = $_[0]; 4461 my @NS = (); 4462 while(my $CPos = find_center($Name, ":")) 4463 { 4464 push(@NS, substr($Name, 0, $CPos)); 4465 $Name = substr($Name, $CPos); 4466 $Name=~s/\A:://; 4467 } 4468 return (join("::", @NS), $Name); 4469} 4470 4471sub mangle_ns($$$) 4472{ 4473 my ($Name, $LibVersion, $Repl) = @_; 4474 if(my $Tid = $TName_Tid{$LibVersion}{$Name}) 4475 { 4476 my $Mangled = mangle_param($Tid, $LibVersion, $Repl); 4477 $Mangled=~s/\AN(.+)E\Z/$1/; 4478 return $Mangled; 4479 4480 } 4481 else 4482 { 4483 my ($MangledNS, $SubNS) = ("", ""); 4484 ($SubNS, $Name) = get_sub_ns($Name); 4485 if($SubNS) { 4486 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4487 } 4488 $MangledNS .= length($Name).$Name; 4489 add_substitution($MangledNS, $Repl, 0); 4490 return $MangledNS; 4491 } 4492} 4493 4494sub mangle_param($$$) 4495{ 4496 my ($PTid, $LibVersion, $Repl) = @_; 4497 my ($MPrefix, $Mangled) = ("", ""); 4498 my %ReplCopy = %{$Repl}; 4499 my %BaseType = get_BaseType($PTid, $LibVersion); 4500 my $BaseType_Name = $BaseType{"Name"}; 4501 $BaseType_Name=~s/\A(struct|union|enum) //g; 4502 if(not $BaseType_Name) { 4503 return ""; 4504 } 4505 my ($ShortName, $TmplParams) = template_Base($BaseType_Name); 4506 my $Suffix = get_BaseTypeQual($PTid, $LibVersion); 4507 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){}; 4508 while($Suffix=~/(&|\*|const)\Z/) 4509 { 4510 if($Suffix=~s/[ ]*&\Z//) { 4511 $MPrefix .= "R"; 4512 } 4513 if($Suffix=~s/[ ]*\*\Z//) { 4514 $MPrefix .= "P"; 4515 } 4516 if($Suffix=~s/[ ]*const\Z//) 4517 { 4518 if($MPrefix=~/R|P/ 4519 or $Suffix=~/&|\*/) { 4520 $MPrefix .= "K"; 4521 } 4522 } 4523 if($Suffix=~s/[ ]*volatile\Z//) { 4524 $MPrefix .= "V"; 4525 } 4526 #if($Suffix=~s/[ ]*restrict\Z//) { 4527 #$MPrefix .= "r"; 4528 #} 4529 } 4530 if(my $Token = $IntrinsicMangling{$BaseType_Name}) { 4531 $Mangled .= $Token; 4532 } 4533 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/) 4534 { 4535 my @TParams = (); 4536 if(my @TPos = keys(%{$BaseType{"TParam"}})) 4537 { # parsing mode 4538 foreach (@TPos) { 4539 push(@TParams, $BaseType{"TParam"}{$_}{"name"}); 4540 } 4541 } 4542 elsif($TmplParams) 4543 { # remangling mode 4544 # support for old ABI dumps 4545 @TParams = separate_Params($TmplParams, 0, 0); 4546 } 4547 my $MangledNS = ""; 4548 my ($SubNS, $SName) = get_sub_ns($ShortName); 4549 if($SubNS) { 4550 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4551 } 4552 $MangledNS .= length($SName).$SName; 4553 if(@TParams) { 4554 add_substitution($MangledNS, $Repl, 0); 4555 } 4556 $Mangled .= "N".$MangledNS; 4557 if(@TParams) 4558 { # templates 4559 $Mangled .= "I"; 4560 foreach my $TParam (@TParams) { 4561 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl); 4562 } 4563 $Mangled .= "E"; 4564 } 4565 $Mangled .= "E"; 4566 } 4567 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/) 4568 { 4569 if($BaseType{"Type"} eq "MethodPtr") { 4570 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F"; 4571 } 4572 else { 4573 $Mangled .= "PF"; 4574 } 4575 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4576 my @Params = keys(%{$BaseType{"Param"}}); 4577 foreach my $Num (sort {int($a)<=>int($b)} @Params) { 4578 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl); 4579 } 4580 if(not @Params) { 4581 $Mangled .= "v"; 4582 } 4583 $Mangled .= "E"; 4584 } 4585 elsif($BaseType{"Type"} eq "FieldPtr") 4586 { 4587 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl); 4588 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4589 } 4590 $Mangled = $MPrefix.$Mangled;# add prefix (RPK) 4591 if(my $Optimized = write_substitution($Mangled, \%ReplCopy)) 4592 { 4593 if($Mangled eq $Optimized) 4594 { 4595 if($ShortName!~/::/) 4596 { # remove "N ... E" 4597 if($MPrefix) { 4598 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g; 4599 } 4600 else { 4601 $Mangled=~s/\AN(.+)E\Z/$1/g; 4602 } 4603 } 4604 } 4605 else { 4606 $Mangled = $Optimized; 4607 } 4608 } 4609 add_substitution($Mangled, $Repl, 1); 4610 return $Mangled; 4611} 4612 4613sub mangle_template_param($$$) 4614{ # types + literals 4615 my ($TParam, $LibVersion, $Repl) = @_; 4616 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) { 4617 return mangle_param($TPTid, $LibVersion, $Repl); 4618 } 4619 elsif($TParam=~/\A(\d+)(\w+)\Z/) 4620 { # class_name<1u>::method(...) 4621 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E"; 4622 } 4623 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/) 4624 { # class_name<(signed char)1>::method(...) 4625 return "L".$IntrinsicMangling{$1}.$2."E"; 4626 } 4627 elsif($TParam eq "true") 4628 { # class_name<true>::method(...) 4629 return "Lb1E"; 4630 } 4631 elsif($TParam eq "false") 4632 { # class_name<true>::method(...) 4633 return "Lb0E"; 4634 } 4635 else { # internal error 4636 return length($TParam).$TParam; 4637 } 4638} 4639 4640sub add_substitution($$$) 4641{ 4642 my ($Value, $Repl, $Rec) = @_; 4643 if($Rec) 4644 { # subtypes 4645 my @Subs = ($Value); 4646 while($Value=~s/\A(R|P|K)//) { 4647 push(@Subs, $Value); 4648 } 4649 foreach (reverse(@Subs)) { 4650 add_substitution($_, $Repl, 0); 4651 } 4652 return; 4653 } 4654 return if($Value=~/\AS(\d*)_\Z/); 4655 $Value=~s/\AN(.+)E\Z/$1/g; 4656 return if(defined $Repl->{$Value}); 4657 return if(length($Value)<=1); 4658 return if($StdcxxMangling{$Value}); 4659 # check for duplicates 4660 my $Base = $Value; 4661 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4662 { 4663 my $Num = $Repl->{$Type}; 4664 my $Replace = macro_mangle($Num); 4665 $Base=~s/\Q$Replace\E/$Type/; 4666 } 4667 if(my $OldNum = $Repl->{$Base}) 4668 { 4669 $Repl->{$Value} = $OldNum; 4670 return; 4671 } 4672 my @Repls = sort {$b<=>$a} values(%{$Repl}); 4673 if(@Repls) { 4674 $Repl->{$Value} = $Repls[0]+1; 4675 } 4676 else { 4677 $Repl->{$Value} = -1; 4678 } 4679 # register duplicates 4680 # upward 4681 $Base = $Value; 4682 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4683 { 4684 next if($Base eq $Type); 4685 my $Num = $Repl->{$Type}; 4686 my $Replace = macro_mangle($Num); 4687 $Base=~s/\Q$Type\E/$Replace/; 4688 $Repl->{$Base} = $Repl->{$Value}; 4689 } 4690} 4691 4692sub macro_mangle($) 4693{ 4694 my $Num = $_[0]; 4695 if($Num==-1) { 4696 return "S_"; 4697 } 4698 else 4699 { 4700 my $Code = ""; 4701 if($Num<10) 4702 { # S0_, S1_, S2_, ... 4703 $Code = $Num; 4704 } 4705 elsif($Num>=10 and $Num<=35) 4706 { # SA_, SB_, SC_, ... 4707 $Code = chr(55+$Num); 4708 } 4709 else 4710 { # S10_, S11_, S12_ 4711 $Code = $Num-26; # 26 is length of english alphabet 4712 } 4713 return "S".$Code."_"; 4714 } 4715} 4716 4717sub write_stdcxx_substitution($) 4718{ 4719 my $Mangled = $_[0]; 4720 if($StdcxxMangling{$Mangled}) { 4721 return $StdcxxMangling{$Mangled}; 4722 } 4723 else 4724 { 4725 my @Repls = keys(%StdcxxMangling); 4726 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4727 foreach my $MangledType (@Repls) 4728 { 4729 my $Replace = $StdcxxMangling{$MangledType}; 4730 #if($Mangled!~/$Replace/) { 4731 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4732 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4733 #} 4734 } 4735 } 4736 return $Mangled; 4737} 4738 4739sub write_substitution($$) 4740{ 4741 my ($Mangled, $Repl) = @_; 4742 if(defined $Repl->{$Mangled} 4743 and my $MnglNum = $Repl->{$Mangled}) { 4744 $Mangled = macro_mangle($MnglNum); 4745 } 4746 else 4747 { 4748 my @Repls = keys(%{$Repl}); 4749 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls; 4750 # FIXME: how to apply replacements? by num or by pos 4751 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4752 foreach my $MangledType (@Repls) 4753 { 4754 my $Replace = macro_mangle($Repl->{$MangledType}); 4755 if($Mangled!~/$Replace/) { 4756 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4757 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4758 } 4759 } 4760 } 4761 return $Mangled; 4762} 4763 4764sub delete_keywords($) 4765{ 4766 my $TypeName = $_[0]; 4767 $TypeName=~s/\b(enum|struct|union|class) //g; 4768 return $TypeName; 4769} 4770 4771sub uncover_typedefs($$) 4772{ 4773 my ($TypeName, $LibVersion) = @_; 4774 return "" if(not $TypeName); 4775 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) { 4776 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}; 4777 } 4778 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), ""); 4779 while($TypeName_New ne $TypeName_Pre) 4780 { 4781 $TypeName_Pre = $TypeName_New; 4782 my $TypeName_Copy = $TypeName_New; 4783 my %Words = (); 4784 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io) 4785 { 4786 if(not $Intrinsic_Keywords{$1}) { 4787 $Words{$1} = 1; 4788 } 4789 } 4790 foreach my $Word (keys(%Words)) 4791 { 4792 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word}; 4793 next if(not $BaseType_Name); 4794 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/); 4795 if($BaseType_Name=~/\([\*]+\)/) 4796 { # FuncPtr 4797 if($TypeName_New=~/\Q$Word\E(.*)\Z/) 4798 { 4799 my $Type_Suffix = $1; 4800 $TypeName_New = $BaseType_Name; 4801 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) { 4802 $TypeName_New = formatName($TypeName_New, "T"); 4803 } 4804 } 4805 } 4806 else 4807 { 4808 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) { 4809 $TypeName_New = formatName($TypeName_New, "T"); 4810 } 4811 } 4812 } 4813 } 4814 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New); 4815} 4816 4817sub isInternal($) 4818{ 4819 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 4820 { 4821 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) 4822 { 4823 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/) 4824 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL* 4825 return 1; 4826 } 4827 } 4828 } 4829 return 0; 4830} 4831 4832sub getDataVal($$) 4833{ 4834 my ($InfoId, $TypeId) = @_; 4835 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4836 { 4837 if($Info=~/init[ ]*:[ ]*@(\d+) /) 4838 { 4839 if(defined $LibInfo{$Version}{"info_type"}{$1} 4840 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr") 4841 { 4842 if(my $Nop = getTreeAttr_Op($1)) 4843 { 4844 if(defined $LibInfo{$Version}{"info_type"}{$Nop} 4845 and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr") 4846 { 4847 if(my $Addr = getTreeAttr_Op($1)) { 4848 return getInitVal($Addr, $TypeId); 4849 } 4850 } 4851 } 4852 } 4853 else { 4854 return getInitVal($1, $TypeId); 4855 } 4856 } 4857 } 4858 return undef; 4859} 4860 4861sub getInitVal($$) 4862{ 4863 my ($InfoId, $TypeId) = @_; 4864 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4865 { 4866 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId}) 4867 { 4868 if($InfoType eq "integer_cst") 4869 { 4870 my $Val = getNodeIntCst($InfoId); 4871 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/) 4872 { # characters 4873 $Val = chr($Val); 4874 } 4875 return $Val; 4876 } 4877 elsif($InfoType eq "string_cst") { 4878 return getNodeStrCst($InfoId); 4879 } 4880 elsif($InfoType eq "var_decl") 4881 { 4882 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) { 4883 return $Name; 4884 } 4885 } 4886 } 4887 } 4888 return undef; 4889} 4890 4891sub set_Class_And_Namespace($) 4892{ 4893 my $InfoId = $_[0]; 4894 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4895 { 4896 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) 4897 { 4898 my $NSInfoId = $1; 4899 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 4900 { 4901 if($InfoType eq "namespace_decl") { 4902 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId); 4903 } 4904 elsif($InfoType eq "record_type") { 4905 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId; 4906 } 4907 } 4908 } 4909 } 4910 if($SymbolInfo{$Version}{$InfoId}{"Class"} 4911 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) 4912 { 4913 if($COMMON_LANGUAGE{$Version} ne "C++") 4914 { # skip 4915 return 1; 4916 } 4917 } 4918 4919 return 0; 4920} 4921 4922sub debugMangling($) 4923{ 4924 my $LibVersion = $_[0]; 4925 my %Mangled = (); 4926 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 4927 { 4928 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 4929 { 4930 if($Mngl=~/\A(_Z|\?)/) { 4931 $Mangled{$Mngl}=$InfoId; 4932 } 4933 } 4934 } 4935 translateSymbols(keys(%Mangled), $LibVersion); 4936 foreach my $Mngl (keys(%Mangled)) 4937 { 4938 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC"); 4939 my $U2 = $tr_name{$Mngl}; 4940 if($U1 ne $U2) { 4941 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n"); 4942 } 4943 } 4944} 4945 4946sub linkSymbol($) 4947{ # link symbols from shared libraries 4948 # with the symbols from header files 4949 my $InfoId = $_[0]; 4950 # try to mangle symbol 4951 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"}) 4952 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 4953 or $EMERGENCY_MODE_48) 4954 { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) 4955 # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions 4956 # GCC 4.8 doesn't mangle anything 4957 if(not $CheckHeadersOnly) 4958 { 4959 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) { 4960 return correct_incharge($InfoId, $Version, $Mangled); 4961 } 4962 } 4963 if($CheckHeadersOnly 4964 or not $BinaryOnly 4965 or $EMERGENCY_MODE_48) 4966 { # 1. --headers-only mode 4967 # 2. not mangled src-only symbols 4968 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) { 4969 return $Mangled; 4970 } 4971 } 4972 } 4973 return ""; 4974} 4975 4976sub setLanguage($$) 4977{ 4978 my ($LibVersion, $Lang) = @_; 4979 if(not $UserLang) { 4980 $COMMON_LANGUAGE{$LibVersion} = $Lang; 4981 } 4982} 4983 4984sub getSymbolInfo($) 4985{ 4986 my $InfoId = $_[0]; 4987 if(isInternal($InfoId)) { 4988 return; 4989 } 4990 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 4991 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 4992 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) 4993 { 4994 delete($SymbolInfo{$Version}{$InfoId}); 4995 return; 4996 } 4997 setFuncAccess($InfoId); 4998 setFuncKind($InfoId); 4999 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) 5000 { 5001 delete($SymbolInfo{$Version}{$InfoId}); 5002 return; 5003 } 5004 5005 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId); 5006 if(my $Return = getFuncReturn($InfoId)) 5007 { 5008 if(not defined $TypeInfo{$Version}{$Return} 5009 or not $TypeInfo{$Version}{$Return}{"Name"}) 5010 { 5011 delete($SymbolInfo{$Version}{$InfoId}); 5012 return; 5013 } 5014 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return; 5015 } 5016 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 5017 { 5018 if(defined $MissedTypedef{$Version}{$Rid}) 5019 { 5020 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 5021 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 5022 } 5023 } 5024 } 5025 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) { 5026 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5027 } 5028 my $Orig = getFuncOrig($InfoId); 5029 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig); 5030 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1) 5031 { 5032 delete($SymbolInfo{$Version}{$InfoId}); 5033 return; 5034 } 5035 5036 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0) 5037 { 5038 delete($SymbolInfo{$Version}{$InfoId}); 5039 return; 5040 } 5041 5042 if(defined $TemplateInstance{$Version}{"Func"}{$Orig}) 5043 { 5044 my $Tmpl = $BasicTemplate{$Version}{$InfoId}; 5045 5046 my @TParams = getTParams($Orig, "Func"); 5047 if(not @TParams) 5048 { 5049 delete($SymbolInfo{$Version}{$InfoId}); 5050 return; 5051 } 5052 foreach my $Pos (0 .. $#TParams) 5053 { 5054 my $Val = $TParams[$Pos]; 5055 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val; 5056 5057 if($Tmpl) 5058 { 5059 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 5060 { 5061 $TemplateMap{$Version}{$InfoId}{$Arg} = $Val; 5062 } 5063 } 5064 } 5065 5066 if($Tmpl) 5067 { 5068 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 5069 { 5070 if($Pos>$#TParams) 5071 { 5072 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 5073 $TemplateMap{$Version}{$InfoId}{$Arg} = ""; 5074 } 5075 } 5076 } 5077 5078 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/) 5079 { # operator<< <T>, operator>> <T> 5080 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " "; 5081 } 5082 if(@TParams) { 5083 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".join(", ", @TParams).">"; 5084 } 5085 else { 5086 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<...>"; 5087 } 5088 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S"); 5089 } 5090 else 5091 { # support for GCC 3.4 5092 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5093 } 5094 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 5095 { 5096 if($OSgroup eq "windows") 5097 { # cut the offset 5098 $MnglName=~s/\@\d+\Z//g; 5099 } 5100 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 5101 5102 # NOTE: mangling of some symbols may change depending on GCC version 5103 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E 5104 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_ 5105 } 5106 5107 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 5108 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 5109 { 5110 delete($SymbolInfo{$Version}{$InfoId}); 5111 return; 5112 } 5113 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) 5114 { # destructors have an empty parameter list 5115 my $Skip = setFuncParams($InfoId); 5116 if($Skip) 5117 { 5118 delete($SymbolInfo{$Version}{$InfoId}); 5119 return; 5120 } 5121 } 5122 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) { 5123 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1; 5124 } 5125 5126 if(set_Class_And_Namespace($InfoId)) 5127 { 5128 delete($SymbolInfo{$Version}{$InfoId}); 5129 return; 5130 } 5131 5132 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5133 { 5134 if(not defined $TypeInfo{$Version}{$ClassId} 5135 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 5136 { 5137 delete($SymbolInfo{$Version}{$InfoId}); 5138 return; 5139 } 5140 } 5141 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 5142 { # extern "C" 5143 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 5144 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5145 } 5146 if($UserLang and $UserLang eq "C") 5147 { # --lang=C option 5148 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5149 } 5150 if($COMMON_LANGUAGE{$Version} eq "C++") 5151 { # correct mangled & short names 5152 # C++ or --headers-only mode 5153 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/) 5154 { # support for old GCC versions: reconstruct real names for constructors and destructors 5155 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"})); 5156 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5157 } 5158 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5159 { # try to mangle symbol (link with libraries) 5160 if(my $Mangled = linkSymbol($InfoId)) { 5161 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 5162 } 5163 } 5164 if($OStarget eq "windows") 5165 { # link MS C++ symbols from library with GCC symbols from headers 5166 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 5167 { # exported symbols 5168 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1; 5169 } 5170 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC")) 5171 { # pure virtual symbols 5172 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2; 5173 } 5174 } 5175 } 5176 else 5177 { # not mangled in C 5178 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5179 } 5180 if(not $CheckHeadersOnly 5181 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function" 5182 and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 5183 { 5184 my $Incorrect = 0; 5185 5186 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5187 { 5188 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0 5189 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 5190 { # mangled in the TU dump, but not mangled in the library 5191 $Incorrect = 1; 5192 } 5193 } 5194 else 5195 { 5196 if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C") 5197 { # all C++ functions are not mangled in the TU dump 5198 $Incorrect = 1; 5199 } 5200 } 5201 if($Incorrect) 5202 { 5203 if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) { 5204 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5205 } 5206 } 5207 } 5208 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5209 { # can't detect symbol name 5210 delete($SymbolInfo{$Version}{$InfoId}); 5211 return; 5212 } 5213 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5214 and my $Spec = getVirtSpec($Orig)) 5215 { # identify virtual and pure virtual functions 5216 # NOTE: constructors cannot be virtual 5217 # NOTE: in GCC 4.7 D1 destructors have no virtual spec 5218 # in the TU dump, so taking it from the original symbol 5219 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"} 5220 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/)) 5221 { # NOTE: D2 destructors are not present in a v-table 5222 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1; 5223 } 5224 } 5225 if(isInline($InfoId)) { 5226 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1; 5227 } 5228 if(hasThrow($InfoId)) { 5229 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1; 5230 } 5231 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5232 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5233 { 5234 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"} 5235 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"}) 5236 { # inline or auto-generated constructor 5237 delete($TypeInfo{$Version}{$ClassId}{"Copied"}); 5238 } 5239 } 5240 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5241 { 5242 if(not $ExtraDump) 5243 { 5244 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 5245 { # non-target symbols 5246 delete($SymbolInfo{$Version}{$InfoId}); 5247 return; 5248 } 5249 } 5250 } 5251 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method" 5252 or $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5253 or $SymbolInfo{$Version}{$InfoId}{"Destructor"} 5254 or $SymbolInfo{$Version}{$InfoId}{"Class"}) 5255 { 5256 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) 5257 { 5258 delete($SymbolInfo{$Version}{$InfoId}); 5259 return; 5260 } 5261 } 5262 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5263 { 5264 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5265 { # one instance for one mangled name only 5266 delete($SymbolInfo{$Version}{$InfoId}); 5267 return; 5268 } 5269 else { 5270 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1; 5271 } 5272 } 5273 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5274 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 5275 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5276 } 5277 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/ 5278 and $SymbolInfo{$Version}{$InfoId}{"Class"}) 5279 { 5280 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function") 5281 { # static methods 5282 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5283 } 5284 } 5285 if(getFuncLink($InfoId) eq "Static") { 5286 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5287 } 5288 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/) 5289 { 5290 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5291 { 5292 if($Unmangled=~/\.\_\d/) 5293 { 5294 delete($SymbolInfo{$Version}{$InfoId}); 5295 return; 5296 } 5297 } 5298 } 5299 5300 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) { 5301 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5302 } 5303 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) { 5304 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5305 } 5306 5307 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { 5308 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1; 5309 } 5310 5311 if($ExtraDump) { 5312 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 5313 } 5314} 5315 5316sub guessHeader($) 5317{ 5318 my $InfoId = $_[0]; 5319 my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5320 my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}; 5321 my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):""; 5322 my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"}; 5323 if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName}) 5324 { 5325 if(get_filename($HPath) eq $Header) 5326 { 5327 my $HDir = get_filename(get_dirname($HPath)); 5328 if($HDir ne "include" 5329 and $HDir=~/\A[a-z]+\Z/i) { 5330 return join_P($HDir, $Header); 5331 } 5332 } 5333 } 5334 return $Header; 5335} 5336 5337sub isInline($) 5338{ # "body: undefined" in the tree 5339 # -fkeep-inline-functions GCC option should be specified 5340 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5341 { 5342 if($Info=~/ undefined /i) { 5343 return 0; 5344 } 5345 } 5346 return 1; 5347} 5348 5349sub hasThrow($) 5350{ 5351 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5352 { 5353 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5354 return getTreeAttr_Unql($1, "unql"); 5355 } 5356 } 5357 return 1; 5358} 5359 5360sub getTypeId($) 5361{ 5362 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5363 { 5364 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5365 return $1; 5366 } 5367 } 5368 return ""; 5369} 5370 5371sub setTypeMemb($$) 5372{ 5373 my ($TypeId, $TypeAttr) = @_; 5374 my $TypeType = $TypeAttr->{"Type"}; 5375 my ($Pos, $UnnamedPos) = (0, 0); 5376 my $StaticFields = 0; 5377 if($TypeType eq "Enum") 5378 { 5379 my $MInfoId = getTreeAttr_Csts($TypeId); 5380 while($MInfoId) 5381 { 5382 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId); 5383 my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId)); 5384 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName; 5385 $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName; 5386 $MInfoId = getNextElem($MInfoId); 5387 $Pos += 1; 5388 } 5389 } 5390 elsif($TypeType=~/\A(Struct|Class|Union)\Z/) 5391 { 5392 my $MInfoId = getTreeAttr_Flds($TypeId); 5393 while($MInfoId) 5394 { 5395 my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId}; 5396 my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId}; 5397 if(not $IType or $IType ne "field_decl") 5398 { # search for fields, skip other stuff in the declaration 5399 5400 if($IType eq "var_decl") 5401 { # static field 5402 $StaticFields = 1; 5403 } 5404 5405 $MInfoId = getNextElem($MInfoId); 5406 next; 5407 } 5408 my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId)); 5409 if(index($StructMembName, "_vptr.")==0) 5410 { # virtual tables 5411 $StructMembName = "_vptr"; 5412 } 5413 if(not $StructMembName) 5414 { # unnamed fields 5415 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1) 5416 { 5417 my $UnnamedTid = getTreeAttr_Type($MInfoId); 5418 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid)); 5419 if(isAnon($UnnamedTName)) 5420 { # rename unnamed fields to unnamed0, unnamed1, ... 5421 $StructMembName = "unnamed".($UnnamedPos++); 5422 } 5423 } 5424 } 5425 if(not $StructMembName) 5426 { # unnamed fields and base classes 5427 $MInfoId = getNextElem($MInfoId); 5428 next; 5429 } 5430 my $MembTypeId = getTreeAttr_Type($MInfoId); 5431 if(defined $MissedTypedef{$Version}{$MembTypeId}) 5432 { 5433 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) { 5434 $MembTypeId = $AddedTid; 5435 } 5436 } 5437 5438 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId; 5439 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName; 5440 if((my $Access = getTreeAccess($MInfoId)) ne "public") 5441 { # marked only protected and private, public by default 5442 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access; 5443 } 5444 if($MInfo=~/spec:\s*mutable /) 5445 { # mutable fields 5446 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1; 5447 } 5448 if(my $Algn = getAlgn($MInfoId)) { 5449 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn; 5450 } 5451 if(my $BFSize = getBitField($MInfoId)) 5452 { # in bits 5453 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize; 5454 } 5455 else 5456 { # in bytes 5457 if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1) 5458 { # template 5459 delete($TypeAttr->{"Memb"}{$Pos}{"algn"}); 5460 } 5461 else { 5462 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; 5463 } 5464 } 5465 5466 $MInfoId = getNextElem($MInfoId); 5467 $Pos += 1; 5468 } 5469 } 5470 5471 return $StaticFields; 5472} 5473 5474sub setFuncParams($) 5475{ 5476 my $InfoId = $_[0]; 5477 my $ParamInfoId = getTreeAttr_Args($InfoId); 5478 5479 my $FType = getFuncType($InfoId); 5480 5481 if($FType eq "Method") 5482 { # check type of "this" pointer 5483 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId); 5484 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"}) 5485 { 5486 if($ObjectName=~/\bconst(| volatile)\*const\b/) { 5487 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5488 } 5489 if($ObjectName=~/\bvolatile\b/) { 5490 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5491 } 5492 } 5493 else 5494 { # skip 5495 return 1; 5496 } 5497 # skip "this"-parameter 5498 # $ParamInfoId = getNextElem($ParamInfoId); 5499 } 5500 my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1); 5501 while($ParamInfoId) 5502 { # formal args 5503 my $ParamTypeId = getTreeAttr_Type($ParamInfoId); 5504 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId)); 5505 if(not $ParamName) 5506 { # unnamed 5507 $ParamName = "p".($PPos+1); 5508 } 5509 if(defined $MissedTypedef{$Version}{$ParamTypeId}) 5510 { 5511 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) { 5512 $ParamTypeId = $AddedTid; 5513 } 5514 } 5515 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"}; 5516 if(not $PType or $PType eq "Unknown") { 5517 return 1; 5518 } 5519 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"}; 5520 if(not $PTName) { 5521 return 1; 5522 } 5523 if($PTName eq "void") { 5524 last; 5525 } 5526 if($ParamName eq "__vtt_parm" 5527 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**") 5528 { 5529 $Vtt_Pos = $Pos; 5530 $ParamInfoId = getNextElem($ParamInfoId); 5531 next; 5532 } 5533 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5534 5535 if(my %Base = get_BaseType($ParamTypeId, $Version)) 5536 { 5537 if(defined $Base{"Template"}) { 5538 return 1; 5539 } 5540 } 5541 5542 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName; 5543 if(my $Algn = getAlgn($ParamInfoId)) { 5544 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE; 5545 } 5546 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /) 5547 { # foo(register type arg) 5548 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1; 5549 } 5550 $ParamInfoId = getNextElem($ParamInfoId); 5551 $Pos += 1; 5552 if($ParamName ne "this" or $FType ne "Method") { 5553 $PPos += 1; 5554 } 5555 } 5556 if(setFuncArgs($InfoId, $Vtt_Pos)) { 5557 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1"; 5558 } 5559 return 0; 5560} 5561 5562sub setFuncArgs($$) 5563{ 5564 my ($InfoId, $Vtt_Pos) = @_; 5565 my $FuncTypeId = getFuncTypeId($InfoId); 5566 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId); 5567 my $FType = getFuncType($InfoId); 5568 5569 if($FType eq "Method") 5570 { 5571 # skip "this"-parameter 5572 # $ParamListElemId = getNextElem($ParamListElemId); 5573 } 5574 if(not $ParamListElemId) 5575 { # foo(...) 5576 return 1; 5577 } 5578 my $HaveVoid = 0; 5579 my ($Pos, $PPos) = (0, 0); 5580 while($ParamListElemId) 5581 { # actual params: may differ from formal args 5582 # formal int*const 5583 # actual: int* 5584 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos) 5585 { 5586 $Vtt_Pos=-1; 5587 $ParamListElemId = getNextElem($ParamListElemId); 5588 next; 5589 } 5590 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId); 5591 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void") 5592 { 5593 $HaveVoid = 1; 5594 last; 5595 } 5596 else 5597 { 5598 if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5599 { 5600 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5601 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) 5602 { # unnamed 5603 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1); 5604 } 5605 } 5606 elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5607 { 5608 if($Pos>0 or getFuncType($InfoId) ne "Method") 5609 { # params 5610 if($OldId ne $ParamTypeId) 5611 { 5612 my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version}); 5613 my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version}); 5614 5615 if($Old_Pure{"Name"} ne $New_Pure{"Name"}) { 5616 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5617 } 5618 } 5619 } 5620 } 5621 } 5622 if(my $PurpId = getTreeAttr_Purp($ParamListElemId)) 5623 { # default arguments 5624 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) 5625 { 5626 if($PurpType eq "nop_expr") 5627 { # func ( const char* arg = (const char*)(void*)0 ) 5628 $PurpId = getTreeAttr_Op($PurpId); 5629 } 5630 my $Val = getInitVal($PurpId, $ParamTypeId); 5631 if(defined $Val) { 5632 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val; 5633 } 5634 } 5635 } 5636 $ParamListElemId = getNextElem($ParamListElemId); 5637 if($Pos!=0 or $FType ne "Method") { 5638 $PPos += 1; 5639 } 5640 $Pos += 1; 5641 } 5642 return ($Pos>=1 and not $HaveVoid); 5643} 5644 5645sub getTreeAttr_Chan($) 5646{ 5647 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5648 { 5649 if($Info=~/chan[ ]*:[ ]*@(\d+) /) { 5650 return $1; 5651 } 5652 } 5653 return ""; 5654} 5655 5656sub getTreeAttr_Chain($) 5657{ 5658 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5659 { 5660 if($Info=~/chain[ ]*:[ ]*@(\d+) /) { 5661 return $1; 5662 } 5663 } 5664 return ""; 5665} 5666 5667sub getTreeAttr_Unql($) 5668{ 5669 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5670 { 5671 if($Info=~/unql[ ]*:[ ]*@(\d+) /) { 5672 return $1; 5673 } 5674 } 5675 return ""; 5676} 5677 5678sub getTreeAttr_Scpe($) 5679{ 5680 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5681 { 5682 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) { 5683 return $1; 5684 } 5685 } 5686 return ""; 5687} 5688 5689sub getTreeAttr_Type($) 5690{ 5691 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5692 { 5693 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5694 return $1; 5695 } 5696 } 5697 return ""; 5698} 5699 5700sub getTreeAttr_Name($) 5701{ 5702 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5703 { 5704 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 5705 return $1; 5706 } 5707 } 5708 return ""; 5709} 5710 5711sub getTreeAttr_Mngl($) 5712{ 5713 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5714 { 5715 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) { 5716 return $1; 5717 } 5718 } 5719 return ""; 5720} 5721 5722sub getTreeAttr_Prms($) 5723{ 5724 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5725 { 5726 if($Info=~/prms[ ]*:[ ]*@(\d+) /) { 5727 return $1; 5728 } 5729 } 5730 return ""; 5731} 5732 5733sub getTreeAttr_Fncs($) 5734{ 5735 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5736 { 5737 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) { 5738 return $1; 5739 } 5740 } 5741 return ""; 5742} 5743 5744sub getTreeAttr_Csts($) 5745{ 5746 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5747 { 5748 if($Info=~/csts[ ]*:[ ]*@(\d+) /) { 5749 return $1; 5750 } 5751 } 5752 return ""; 5753} 5754 5755sub getTreeAttr_Purp($) 5756{ 5757 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5758 { 5759 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 5760 return $1; 5761 } 5762 } 5763 return ""; 5764} 5765 5766sub getTreeAttr_Op($) 5767{ 5768 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5769 { 5770 if($Info=~/op 0[ ]*:[ ]*@(\d+) /) { 5771 return $1; 5772 } 5773 } 5774 return ""; 5775} 5776 5777sub getTreeAttr_Valu($) 5778{ 5779 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5780 { 5781 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 5782 return $1; 5783 } 5784 } 5785 return ""; 5786} 5787 5788sub getTreeAttr_Flds($) 5789{ 5790 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5791 { 5792 if($Info=~/flds[ ]*:[ ]*@(\d+) /) { 5793 return $1; 5794 } 5795 } 5796 return ""; 5797} 5798 5799sub getTreeAttr_Binf($) 5800{ 5801 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5802 { 5803 if($Info=~/binf[ ]*:[ ]*@(\d+) /) { 5804 return $1; 5805 } 5806 } 5807 return ""; 5808} 5809 5810sub getTreeAttr_Args($) 5811{ 5812 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5813 { 5814 if($Info=~/args[ ]*:[ ]*@(\d+) /) { 5815 return $1; 5816 } 5817 } 5818 return ""; 5819} 5820 5821sub getTreeValue($) 5822{ 5823 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5824 { 5825 if($Info=~/low[ ]*:[ ]*([^ ]+) /) { 5826 return $1; 5827 } 5828 } 5829 return ""; 5830} 5831 5832sub getTreeAccess($) 5833{ 5834 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5835 { 5836 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /) 5837 { 5838 my $Access = $1; 5839 if($Access eq "prot") { 5840 return "protected"; 5841 } 5842 elsif($Access eq "priv") { 5843 return "private"; 5844 } 5845 } 5846 elsif($Info=~/ protected /) 5847 { # support for old GCC versions 5848 return "protected"; 5849 } 5850 elsif($Info=~/ private /) 5851 { # support for old GCC versions 5852 return "private"; 5853 } 5854 } 5855 return "public"; 5856} 5857 5858sub setFuncAccess($) 5859{ 5860 my $Access = getTreeAccess($_[0]); 5861 if($Access eq "protected") { 5862 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1; 5863 } 5864 elsif($Access eq "private") { 5865 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1; 5866 } 5867} 5868 5869sub setTypeAccess($$) 5870{ 5871 my ($TypeId, $TypeAttr) = @_; 5872 my $Access = getTreeAccess($TypeId); 5873 if($Access eq "protected") { 5874 $TypeAttr->{"Protected"} = 1; 5875 } 5876 elsif($Access eq "private") { 5877 $TypeAttr->{"Private"} = 1; 5878 } 5879} 5880 5881sub setFuncKind($) 5882{ 5883 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5884 { 5885 if($Info=~/pseudo tmpl/) { 5886 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1; 5887 } 5888 elsif($Info=~/ constructor /) { 5889 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1; 5890 } 5891 elsif($Info=~/ destructor /) { 5892 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1; 5893 } 5894 } 5895} 5896 5897sub getVirtSpec($) 5898{ 5899 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5900 { 5901 if($Info=~/spec[ ]*:[ ]*pure /) { 5902 return "PureVirt"; 5903 } 5904 elsif($Info=~/spec[ ]*:[ ]*virt /) { 5905 return "Virt"; 5906 } 5907 elsif($Info=~/ pure\s+virtual /) 5908 { # support for old GCC versions 5909 return "PureVirt"; 5910 } 5911 elsif($Info=~/ virtual /) 5912 { # support for old GCC versions 5913 return "Virt"; 5914 } 5915 } 5916 return ""; 5917} 5918 5919sub getFuncLink($) 5920{ 5921 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5922 { 5923 if($Info=~/link[ ]*:[ ]*static /) { 5924 return "Static"; 5925 } 5926 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) { 5927 return $1; 5928 } 5929 } 5930 return ""; 5931} 5932 5933sub select_Symbol_NS($$) 5934{ 5935 my ($Symbol, $LibVersion) = @_; 5936 return "" if(not $Symbol or not $LibVersion); 5937 my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 5938 if(not $NS) 5939 { 5940 if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { 5941 $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"}; 5942 } 5943 } 5944 if($NS) 5945 { 5946 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5947 return $NS; 5948 } 5949 else 5950 { 5951 while($NS=~s/::[^:]+\Z//) 5952 { 5953 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5954 return $NS; 5955 } 5956 } 5957 } 5958 } 5959 5960 return ""; 5961} 5962 5963sub select_Type_NS($$) 5964{ 5965 my ($TypeName, $LibVersion) = @_; 5966 return "" if(not $TypeName or not $LibVersion); 5967 if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"}) 5968 { 5969 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5970 return $NS; 5971 } 5972 else 5973 { 5974 while($NS=~s/::[^:]+\Z//) 5975 { 5976 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5977 return $NS; 5978 } 5979 } 5980 } 5981 } 5982 return ""; 5983} 5984 5985sub getNameSpace($) 5986{ 5987 my $InfoId = $_[0]; 5988 if(my $NSInfoId = getTreeAttr_Scpe($InfoId)) 5989 { 5990 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 5991 { 5992 if($InfoType eq "namespace_decl") 5993 { 5994 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /) 5995 { 5996 my $NameSpace = getTreeStr($1); 5997 if($NameSpace eq "::") 5998 { # global namespace 5999 return ""; 6000 } 6001 if(my $BaseNameSpace = getNameSpace($NSInfoId)) { 6002 $NameSpace = $BaseNameSpace."::".$NameSpace; 6003 } 6004 $NestedNameSpaces{$Version}{$NameSpace} = 1; 6005 return $NameSpace; 6006 } 6007 else { 6008 return ""; 6009 } 6010 } 6011 elsif($InfoType ne "function_decl") 6012 { # inside data type 6013 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId); 6014 return $Name; 6015 } 6016 } 6017 } 6018 return ""; 6019} 6020 6021sub getEnumMembVal($) 6022{ 6023 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6024 { 6025 if($Info=~/valu[ ]*:[ ]*\@(\d+)/) 6026 { 6027 if(my $VInfo = $LibInfo{$Version}{"info"}{$1}) 6028 { 6029 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/) 6030 { # in newer versions of GCC the value is in the "const_decl->cnst" node 6031 return getTreeValue($1); 6032 } 6033 else 6034 { # some old versions of GCC (3.3) have the value in the "integer_cst" node 6035 return getTreeValue($1); 6036 } 6037 } 6038 } 6039 } 6040 return ""; 6041} 6042 6043sub getSize($) 6044{ 6045 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6046 { 6047 if($Info=~/size[ ]*:[ ]*\@(\d+)/) { 6048 return getTreeValue($1); 6049 } 6050 } 6051 return 0; 6052} 6053 6054sub getAlgn($) 6055{ 6056 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6057 { 6058 if($Info=~/algn[ ]*:[ ]*(\d+) /) { 6059 return $1; 6060 } 6061 } 6062 return ""; 6063} 6064 6065sub getBitField($) 6066{ 6067 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6068 { 6069 if($Info=~/ bitfield /) { 6070 return getSize($_[0]); 6071 } 6072 } 6073 return 0; 6074} 6075 6076sub getNextElem($) 6077{ 6078 if(my $Chan = getTreeAttr_Chan($_[0])) { 6079 return $Chan; 6080 } 6081 elsif(my $Chain = getTreeAttr_Chain($_[0])) { 6082 return $Chain; 6083 } 6084 return ""; 6085} 6086 6087sub registerHeader($$) 6088{ # input: absolute path of header, relative path or name 6089 my ($Header, $LibVersion) = @_; 6090 if(not $Header) { 6091 return ""; 6092 } 6093 if(is_abs($Header) and not -f $Header) 6094 { # incorrect absolute path 6095 exitStatus("Access_Error", "can't access \'$Header\'"); 6096 } 6097 if(skipHeader($Header, $LibVersion)) 6098 { # skip 6099 return ""; 6100 } 6101 if(my $Header_Path = identifyHeader($Header, $LibVersion)) 6102 { 6103 detect_header_includes($Header_Path, $LibVersion); 6104 6105 if(defined $Tolerance and $Tolerance=~/3/) 6106 { # 3 - skip headers that include non-Linux headers 6107 if($OSgroup ne "windows") 6108 { 6109 foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}})) 6110 { 6111 if(specificHeader($Inc, "windows")) { 6112 return ""; 6113 } 6114 } 6115 } 6116 } 6117 6118 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path}) 6119 { # redirect 6120 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"} 6121 or skipHeader($RHeader_Path, $LibVersion)) 6122 { # skip 6123 return ""; 6124 } 6125 $Header_Path = $RHeader_Path; 6126 } 6127 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) 6128 { # skip 6129 return ""; 6130 } 6131 6132 if(my $HName = get_filename($Header_Path)) 6133 { # register 6134 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName; 6135 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1; 6136 } 6137 6138 if(($Header=~/\.(\w+)\Z/ and $1 ne "h") 6139 or $Header!~/\.(\w+)\Z/) 6140 { # hpp, hh, etc. 6141 setLanguage($LibVersion, "C++"); 6142 $CPP_HEADERS = 1; 6143 } 6144 6145 if($CheckHeadersOnly 6146 and $Header=~/(\A|\/)c\+\+(\/|\Z)/) 6147 { # /usr/include/c++/4.6.1/... 6148 $STDCXX_TESTING = 1; 6149 } 6150 6151 return $Header_Path; 6152 } 6153 return ""; 6154} 6155 6156sub registerDir($$$) 6157{ 6158 my ($Dir, $WithDeps, $LibVersion) = @_; 6159 $Dir=~s/[\/\\]+\Z//g; 6160 return if(not $LibVersion or not $Dir or not -d $Dir); 6161 $Dir = get_abs_path($Dir); 6162 6163 my $Mode = "All"; 6164 if($WithDeps) 6165 { 6166 if($RegisteredDirs{$LibVersion}{$Dir}{1}) { 6167 return; 6168 } 6169 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) { 6170 $Mode = "DepsOnly"; 6171 } 6172 } 6173 else 6174 { 6175 if($RegisteredDirs{$LibVersion}{$Dir}{1} 6176 or $RegisteredDirs{$LibVersion}{$Dir}{0}) { 6177 return; 6178 } 6179 } 6180 $Header_Dependency{$LibVersion}{$Dir} = 1; 6181 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1; 6182 if($Mode eq "DepsOnly") 6183 { 6184 foreach my $Path (cmd_find($Dir,"d")) { 6185 $Header_Dependency{$LibVersion}{$Path} = 1; 6186 } 6187 return; 6188 } 6189 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f")) 6190 { 6191 if($WithDeps) 6192 { 6193 my $SubDir = $Path; 6194 while(($SubDir = get_dirname($SubDir)) ne $Dir) 6195 { # register all sub directories 6196 $Header_Dependency{$LibVersion}{$SubDir} = 1; 6197 } 6198 } 6199 next if(is_not_header($Path)); 6200 next if(ignore_path($Path)); 6201 # Neighbors 6202 foreach my $Part (get_prefixes($Path)) { 6203 $Include_Neighbors{$LibVersion}{$Part} = $Path; 6204 } 6205 } 6206 if(get_filename($Dir) eq "include") 6207 { # search for "lib/include/" directory 6208 my $LibDir = $Dir; 6209 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) { 6210 registerDir($LibDir, $WithDeps, $LibVersion); 6211 } 6212 } 6213} 6214 6215sub parse_redirect($$$) 6216{ 6217 my ($Content, $Path, $LibVersion) = @_; 6218 my @Errors = (); 6219 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) { 6220 push(@Errors, $1); 6221 } 6222 my $Redirect = ""; 6223 foreach (@Errors) 6224 { 6225 s/\s{2,}/ /g; 6226 if(/(only|must\ include 6227 |update\ to\ include 6228 |replaced\ with 6229 |replaced\ by|renamed\ to 6230 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix) 6231 { 6232 $Redirect = $2; 6233 last; 6234 } 6235 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i) 6236 { 6237 $Redirect = $2; 6238 last; 6239 } 6240 elsif(/this\ header\ should\ not\ be\ used 6241 |programs\ should\ not\ directly\ include 6242 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header)) 6243 |is\ not\ supported\ API\ for\ general\ use 6244 |do\ not\ use 6245 |should\ not\ be\ (used|using) 6246 |cannot\ be\ included\ directly/ix and not /\ from\ /i) { 6247 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6248 } 6249 } 6250 if($Redirect) 6251 { 6252 $Redirect=~s/\A<//g; 6253 $Redirect=~s/>\Z//g; 6254 } 6255 return $Redirect; 6256} 6257 6258sub parse_includes($$) 6259{ 6260 my ($Content, $Path) = @_; 6261 my %Includes = (); 6262 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m) 6263 { # C/C++: include, Objective C/C++: import directive 6264 my $Header = $2; 6265 my $Method = substr($Header, 0, 1, ""); 6266 substr($Header, length($Header)-1, 1, ""); 6267 $Header = path_format($Header, $OSgroup); 6268 if($Method eq "\"" or is_abs($Header)) 6269 { 6270 if(-e join_P(get_dirname($Path), $Header)) 6271 { # relative path exists 6272 $Includes{$Header} = -1; 6273 } 6274 else 6275 { # include "..." that doesn't exist is equal to include <...> 6276 $Includes{$Header} = 2; 6277 } 6278 } 6279 else { 6280 $Includes{$Header} = 1; 6281 } 6282 } 6283 if($ExtraInfo) 6284 { 6285 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m) 6286 { # FT_FREETYPE_H 6287 $Includes{$2} = 0; 6288 } 6289 } 6290 return \%Includes; 6291} 6292 6293sub ignore_path($) 6294{ 6295 my $Path = $_[0]; 6296 if($Path=~/\~\Z/) 6297 {# skipping system backup files 6298 return 1; 6299 } 6300 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/) 6301 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories 6302 return 1; 6303 } 6304 return 0; 6305} 6306 6307sub sortByWord($$) 6308{ 6309 my ($ArrRef, $W) = @_; 6310 return if(length($W)<2); 6311 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef}; 6312} 6313 6314sub sortHeaders($$) 6315{ 6316 my ($H1, $H2) = @_; 6317 6318 $H1=~s/\.[a-z]+\Z//ig; 6319 $H2=~s/\.[a-z]+\Z//ig; 6320 6321 my $Hname1 = get_filename($H1); 6322 my $Hname2 = get_filename($H2); 6323 my $HDir1 = get_dirname($H1); 6324 my $HDir2 = get_dirname($H2); 6325 my $Dirname1 = get_filename($HDir1); 6326 my $Dirname2 = get_filename($HDir2); 6327 6328 $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6329 $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6330 6331 if($_[0] eq $_[1] 6332 or $H1 eq $H2) { 6333 return 0; 6334 } 6335 elsif($H1=~/\A\Q$H2\E/) { 6336 return 1; 6337 } 6338 elsif($H2=~/\A\Q$H1\E/) { 6339 return -1; 6340 } 6341 elsif($HDir1=~/\Q$Hname1\E/i 6342 and $HDir2!~/\Q$Hname2\E/i) 6343 { # include/glib-2.0/glib.h 6344 return -1; 6345 } 6346 elsif($HDir2=~/\Q$Hname2\E/i 6347 and $HDir1!~/\Q$Hname1\E/i) 6348 { # include/glib-2.0/glib.h 6349 return 1; 6350 } 6351 elsif($Hname1=~/\Q$Dirname1\E/i 6352 and $Hname2!~/\Q$Dirname2\E/i) 6353 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6354 return -1; 6355 } 6356 elsif($Hname2=~/\Q$Dirname2\E/i 6357 and $Hname1!~/\Q$Dirname1\E/i) 6358 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6359 return 1; 6360 } 6361 elsif($Hname1=~/(config|lib|util)/i 6362 and $Hname2!~/(config|lib|util)/i) 6363 { # include/alsa/asoundlib.h 6364 return -1; 6365 } 6366 elsif($Hname2=~/(config|lib|util)/i 6367 and $Hname1!~/(config|lib|util)/i) 6368 { # include/alsa/asoundlib.h 6369 return 1; 6370 } 6371 else 6372 { 6373 my $R1 = checkRelevance($H1); 6374 my $R2 = checkRelevance($H2); 6375 if($R1 and not $R2) 6376 { # libebook/e-book.h 6377 return -1; 6378 } 6379 elsif($R2 and not $R1) 6380 { # libebook/e-book.h 6381 return 1; 6382 } 6383 else 6384 { 6385 return (lc($H1) cmp lc($H2)); 6386 } 6387 } 6388} 6389 6390sub searchForHeaders($) 6391{ 6392 my $LibVersion = $_[0]; 6393 6394 # gcc standard include paths 6395 registerGccHeaders(); 6396 6397 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING) 6398 { # c++ standard include paths 6399 registerCppHeaders(); 6400 } 6401 6402 # processing header paths 6403 foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}}, 6404 @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) 6405 { 6406 my $IPath = $Path; 6407 if($SystemRoot) 6408 { 6409 if(is_abs($Path)) { 6410 $Path = $SystemRoot.$Path; 6411 } 6412 } 6413 if(not -e $Path) { 6414 exitStatus("Access_Error", "can't access \'$Path\'"); 6415 } 6416 elsif(-f $Path) { 6417 exitStatus("Access_Error", "\'$Path\' - not a directory"); 6418 } 6419 elsif(-d $Path) 6420 { 6421 $Path = get_abs_path($Path); 6422 registerDir($Path, 0, $LibVersion); 6423 if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) { 6424 push(@{$Add_Include_Paths{$LibVersion}}, $Path); 6425 } 6426 else { 6427 push(@{$Include_Paths{$LibVersion}}, $Path); 6428 } 6429 } 6430 } 6431 if(@{$Include_Paths{$LibVersion}}) { 6432 $INC_PATH_AUTODETECT{$LibVersion} = 0; 6433 } 6434 6435 # registering directories 6436 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6437 { 6438 next if(not -e $Path); 6439 $Path = get_abs_path($Path); 6440 $Path = path_format($Path, $OSgroup); 6441 if(-d $Path) { 6442 registerDir($Path, 1, $LibVersion); 6443 } 6444 elsif(-f $Path) 6445 { 6446 my $Dir = get_dirname($Path); 6447 if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}}) 6448 and not $LocalIncludes{$Dir}) 6449 { 6450 registerDir($Dir, 1, $LibVersion); 6451 # if(my $OutDir = get_dirname($Dir)) 6452 # { # registering the outer directory 6453 # if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}}) 6454 # and not $LocalIncludes{$OutDir}) { 6455 # registerDir($OutDir, 0, $LibVersion); 6456 # } 6457 # } 6458 } 6459 } 6460 } 6461 6462 # clean memory 6463 %RegisteredDirs = (); 6464 6465 # registering headers 6466 my $Position = 0; 6467 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6468 { 6469 if(is_abs($Dest) and not -e $Dest) { 6470 exitStatus("Access_Error", "can't access \'$Dest\'"); 6471 } 6472 $Dest = path_format($Dest, $OSgroup); 6473 if(is_header($Dest, 1, $LibVersion)) 6474 { 6475 if(my $HPath = registerHeader($Dest, $LibVersion)) { 6476 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++; 6477 } 6478 } 6479 elsif(-d $Dest) 6480 { 6481 my @Registered = (); 6482 foreach my $Path (cmd_find($Dest,"f")) 6483 { 6484 next if(ignore_path($Path)); 6485 next if(not is_header($Path, 0, $LibVersion)); 6486 if(my $HPath = registerHeader($Path, $LibVersion)) { 6487 push(@Registered, $HPath); 6488 } 6489 } 6490 @Registered = sort {sortHeaders($a, $b)} @Registered; 6491 sortByWord(\@Registered, $TargetLibraryShortName); 6492 foreach my $Path (@Registered) { 6493 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++; 6494 } 6495 } 6496 else { 6497 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file"); 6498 } 6499 } 6500 6501 if(defined $Tolerance and $Tolerance=~/4/) 6502 { # 4 - skip headers included by others 6503 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 6504 { 6505 if(defined $Header_Includes_R{$LibVersion}{$Path}) { 6506 delete($Registered_Headers{$LibVersion}{$Path}); 6507 } 6508 } 6509 } 6510 6511 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"}) 6512 { # preparing preamble headers 6513 foreach my $Header (split(/\s*\n\s*/, $HList)) 6514 { 6515 if(is_abs($Header) and not -f $Header) { 6516 exitStatus("Access_Error", "can't access file \'$Header\'"); 6517 } 6518 $Header = path_format($Header, $OSgroup); 6519 if(my $Header_Path = is_header($Header, 1, $LibVersion)) 6520 { 6521 next if(skipHeader($Header_Path, $LibVersion)); 6522 push_U($Include_Preamble{$LibVersion}, $Header_Path); 6523 } 6524 else { 6525 exitStatus("Access_Error", "can't identify \'$Header\' as a header file"); 6526 } 6527 } 6528 } 6529 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}})) 6530 { # set relative paths (for duplicates) 6531 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2) 6532 { # search for duplicates 6533 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0]; 6534 my $Prefix = get_dirname($FirstPath); 6535 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/) 6536 { # detect a shortest distinguishing prefix 6537 my $NewPrefix = $1; 6538 my %Identity = (); 6539 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6540 { 6541 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) { 6542 $Identity{$Path} = $1; 6543 } 6544 } 6545 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6546 { # all names are differend with current prefix 6547 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { 6548 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path}; 6549 } 6550 last; 6551 } 6552 $Prefix = $NewPrefix; # increase prefix 6553 } 6554 } 6555 } 6556 6557 # clean memory 6558 %HeaderName_Paths = (); 6559 6560 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}})) 6561 { # ordering headers according to descriptor 6562 my $PairName = $Include_Order{$LibVersion}{$HeaderName}; 6563 my ($Pos, $PairPos) = (-1, -1); 6564 my ($Path, $PairPath) = (); 6565 my @Paths = keys(%{$Registered_Headers{$LibVersion}}); 6566 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths; 6567 foreach my $Header_Path (@Paths) 6568 { 6569 if(get_filename($Header_Path) eq $PairName) 6570 { 6571 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6572 $PairPath = $Header_Path; 6573 } 6574 if(get_filename($Header_Path) eq $HeaderName) 6575 { 6576 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6577 $Path = $Header_Path; 6578 } 6579 } 6580 if($PairPos!=-1 and $Pos!=-1 6581 and int($PairPos)<int($Pos)) 6582 { 6583 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}}; 6584 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}}; 6585 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp; 6586 } 6587 } 6588 if(not keys(%{$Registered_Headers{$LibVersion}})) { 6589 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"}); 6590 } 6591} 6592 6593sub detect_real_includes($$) 6594{ 6595 my ($AbsPath, $LibVersion) = @_; 6596 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath); 6597 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath} 6598 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6599 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6600 } 6601 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1; 6602 6603 my $Path = callPreprocessor($AbsPath, "", $LibVersion); 6604 return () if(not $Path); 6605 open(PREPROC, $Path); 6606 while(<PREPROC>) 6607 { 6608 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/) 6609 { 6610 my $Include = path_format($1, $OSgroup); 6611 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) { 6612 next; 6613 } 6614 if($Include eq $AbsPath) { 6615 next; 6616 } 6617 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1; 6618 } 6619 } 6620 close(PREPROC); 6621 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6622} 6623 6624sub detect_header_includes($$) 6625{ 6626 my ($Path, $LibVersion) = @_; 6627 return if(not $LibVersion or not $Path); 6628 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) { 6629 return; 6630 } 6631 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1; 6632 6633 if(not -e $Path) { 6634 return; 6635 } 6636 6637 my $Content = readFile($Path); 6638 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion)) 6639 { # detect error directive in headers 6640 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion)) 6641 { 6642 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) { 6643 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion); 6644 } 6645 if($RedirectPath ne $Path) { 6646 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath; 6647 } 6648 } 6649 else 6650 { # can't find 6651 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6652 } 6653 } 6654 if(my $Inc = parse_includes($Content, $Path)) 6655 { 6656 foreach my $Include (keys(%{$Inc})) 6657 { # detect includes 6658 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include}; 6659 6660 if(defined $Tolerance and $Tolerance=~/4/) 6661 { 6662 if(my $HPath = identifyHeader($Include, $LibVersion)) 6663 { 6664 $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1; 6665 } 6666 } 6667 } 6668 } 6669} 6670 6671sub fromLibc($) 6672{ # system GLIBC header 6673 my $Path = $_[0]; 6674 my ($Dir, $Name) = separate_path($Path); 6675 if($OStarget eq "symbian") 6676 { 6677 if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name}) 6678 { # epoc32/include/libc/{stdio, ...}.h 6679 return 1; 6680 } 6681 } 6682 else 6683 { 6684 if($Dir eq "/usr/include" and $GlibcHeader{$Name}) 6685 { # /usr/include/{stdio, ...}.h 6686 return 1; 6687 } 6688 } 6689 return 0; 6690} 6691 6692sub isLibcDir($) 6693{ # system GLIBC directory 6694 my $Dir = $_[0]; 6695 my ($OutDir, $Name) = separate_path($Dir); 6696 if($OStarget eq "symbian") 6697 { 6698 if(get_filename($OutDir) eq "libc" 6699 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6700 { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h 6701 return 1; 6702 } 6703 } 6704 else 6705 { # linux 6706 if($OutDir eq "/usr/include" 6707 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6708 { # /usr/include/{sys,bits,asm,asm-*}/*.h 6709 return 1; 6710 } 6711 } 6712 return 0; 6713} 6714 6715sub detect_recursive_includes($$) 6716{ 6717 my ($AbsPath, $LibVersion) = @_; 6718 return () if(not $AbsPath); 6719 if(isCyclical(\@RecurInclude, $AbsPath)) { 6720 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6721 } 6722 my ($AbsDir, $Name) = separate_path($AbsPath); 6723 if(isLibcDir($AbsDir)) 6724 { # system GLIBC internals 6725 return () if(not $ExtraInfo); 6726 } 6727 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6728 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6729 } 6730 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i); 6731 6732 if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING) 6733 { # skip /usr/include/c++/*/ headers 6734 return () if(not $ExtraInfo); 6735 } 6736 6737 push(@RecurInclude, $AbsPath); 6738 if(grep { $AbsDir eq $_ } @DefaultGccPaths 6739 or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath))) 6740 { # check "real" (non-"model") include paths 6741 my @Paths = detect_real_includes($AbsPath, $LibVersion); 6742 pop(@RecurInclude); 6743 return @Paths; 6744 } 6745 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) { 6746 detect_header_includes($AbsPath, $LibVersion); 6747 } 6748 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) 6749 { 6750 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include}; 6751 my $HPath = ""; 6752 if($IncType<0) 6753 { # for #include "..." 6754 my $Candidate = join_P($AbsDir, $Include); 6755 if(-f $Candidate) { 6756 $HPath = realpath($Candidate); 6757 } 6758 } 6759 elsif($IncType>0 6760 and $Include=~/[\/\\]/) # and not find_in_defaults($Include) 6761 { # search for the nearest header 6762 # QtCore/qabstractanimation.h includes <QtCore/qobject.h> 6763 my $Candidate = join_P(get_dirname($AbsDir), $Include); 6764 if(-f $Candidate) { 6765 $HPath = $Candidate; 6766 } 6767 } 6768 if(not $HPath) { 6769 $HPath = identifyHeader($Include, $LibVersion); 6770 } 6771 next if(not $HPath); 6772 if($HPath eq $AbsPath) { 6773 next; 6774 } 6775 6776 if($Debug) 6777 { # boundary headers 6778# if($HPath=~/vtk/ and $AbsPath!~/vtk/) 6779# { 6780# print STDERR "$AbsPath -> $HPath\n"; 6781# } 6782 } 6783 6784 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType; 6785 if($IncType>0) 6786 { # only include <...>, skip include "..." prefixes 6787 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1; 6788 } 6789 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion)) 6790 { 6791 if($IncPath eq $AbsPath) { 6792 next; 6793 } 6794 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath}; 6795 if($RIncType==-1) 6796 { # include "..." 6797 $RIncType = $IncType; 6798 } 6799 elsif($RIncType==2) 6800 { 6801 if($IncType!=-1) { 6802 $RIncType = $IncType; 6803 } 6804 } 6805 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType; 6806 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) { 6807 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1; 6808 } 6809 } 6810 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}})) 6811 { 6812 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2 6813 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}) 6814 { # distinguish math.h from glibc and math.h from the tested library 6815 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}); 6816 last; 6817 } 6818 } 6819 } 6820 pop(@RecurInclude); 6821 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6822} 6823 6824sub find_in_framework($$$) 6825{ 6826 my ($Header, $Framework, $LibVersion) = @_; 6827 return "" if(not $Header or not $Framework or not $LibVersion); 6828 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) { 6829 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}; 6830 } 6831 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}})) 6832 { 6833 if(get_filename($Dependency) eq $Framework 6834 and -f get_dirname($Dependency)."/".$Header) { 6835 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency)); 6836 } 6837 } 6838 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = ""); 6839} 6840 6841sub find_in_defaults($) 6842{ 6843 my $Header = $_[0]; 6844 return "" if(not $Header); 6845 if(defined $Cache{"find_in_defaults"}{$Header}) { 6846 return $Cache{"find_in_defaults"}{$Header}; 6847 } 6848 foreach my $Dir (@DefaultIncPaths, 6849 @DefaultGccPaths, 6850 @DefaultCppPaths, 6851 @UsersIncPath) 6852 { 6853 next if(not $Dir); 6854 if(-f $Dir."/".$Header) { 6855 return ($Cache{"find_in_defaults"}{$Header}=$Dir); 6856 } 6857 } 6858 return ($Cache{"find_in_defaults"}{$Header}=""); 6859} 6860 6861sub cmp_paths($$) 6862{ 6863 my ($Path1, $Path2) = @_; 6864 my @Parts1 = split(/[\/\\]/, $Path1); 6865 my @Parts2 = split(/[\/\\]/, $Path2); 6866 foreach my $Num (0 .. $#Parts1) 6867 { 6868 my $Part1 = $Parts1[$Num]; 6869 my $Part2 = $Parts2[$Num]; 6870 if($GlibcDir{$Part1} 6871 and not $GlibcDir{$Part2}) { 6872 return 1; 6873 } 6874 elsif($GlibcDir{$Part2} 6875 and not $GlibcDir{$Part1}) { 6876 return -1; 6877 } 6878 elsif($Part1=~/glib/ 6879 and $Part2!~/glib/) { 6880 return 1; 6881 } 6882 elsif($Part1!~/glib/ 6883 and $Part2=~/glib/) { 6884 return -1; 6885 } 6886 elsif(my $CmpRes = ($Part1 cmp $Part2)) { 6887 return $CmpRes; 6888 } 6889 } 6890 return 0; 6891} 6892 6893sub checkRelevance($) 6894{ 6895 my $Path = $_[0]; 6896 return 0 if(not $Path); 6897 6898 if($SystemRoot) { 6899 $Path = cut_path_prefix($Path, $SystemRoot); 6900 } 6901 6902 my $Name = lc(get_filename($Path)); 6903 my $Dir = lc(get_dirname($Path)); 6904 6905 $Name=~s/\.\w+\Z//g; # remove extension (.h) 6906 6907 foreach my $Token (split(/[_\d\W]+/, $Name)) 6908 { 6909 my $Len = length($Token); 6910 next if($Len<=1); 6911 if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/) 6912 { # include/evolution-data-server-1.4/libebook/e-book.h 6913 return 1; 6914 } 6915 if($Len>=4 and index($Dir, $Token)!=-1) 6916 { # include/gupnp-1.0/libgupnp/gupnp-context.h 6917 return 1; 6918 } 6919 } 6920 return 0; 6921} 6922 6923sub checkFamily(@) 6924{ 6925 my @Paths = @_; 6926 return 1 if($#Paths<=0); 6927 my %Prefix = (); 6928 foreach my $Path (@Paths) 6929 { 6930 if($SystemRoot) { 6931 $Path = cut_path_prefix($Path, $SystemRoot); 6932 } 6933 if(my $Dir = get_dirname($Path)) 6934 { 6935 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix 6936 $Prefix{$Dir} += 1; 6937 $Prefix{get_dirname($Dir)} += 1; 6938 } 6939 } 6940 foreach (sort keys(%Prefix)) 6941 { 6942 if(get_depth($_)>=3 6943 and $Prefix{$_}==$#Paths+1) { 6944 return 1; 6945 } 6946 } 6947 return 0; 6948} 6949 6950sub isAcceptable($$$) 6951{ 6952 my ($Header, $Candidate, $LibVersion) = @_; 6953 my $HName = get_filename($Header); 6954 if(get_dirname($Header)) 6955 { # with prefix 6956 return 1; 6957 } 6958 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/) 6959 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/ 6960 return 1; 6961 } 6962 if(checkRelevance($Candidate)) 6963 { # allow to search for atk.h in /usr/include/atk-1.0/atk/ 6964 return 1; 6965 } 6966 if(checkFamily(getSystemHeaders($HName, $LibVersion))) 6967 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h 6968 # /usr/include/qt4/Qt/qsslconfiguration.h 6969 return 1; 6970 } 6971 if($OStarget eq "symbian") 6972 { 6973 if($Candidate=~/[\/\\]stdapis[\/\\]/) { 6974 return 1; 6975 } 6976 } 6977 return 0; 6978} 6979 6980sub isRelevant($$$) 6981{ # disallow to search for "abstract" headers in too deep directories 6982 my ($Header, $Candidate, $LibVersion) = @_; 6983 my $HName = get_filename($Header); 6984 if($OStarget eq "symbian") 6985 { 6986 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) { 6987 return 0; 6988 } 6989 } 6990 if($OStarget ne "bsd") 6991 { 6992 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/) 6993 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h 6994 return 0; 6995 } 6996 } 6997 if($OStarget ne "windows") 6998 { 6999 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/) 7000 { # skip /usr/include/wine/msvcrt 7001 return 0; 7002 } 7003 } 7004 if(not get_dirname($Header) 7005 and $Candidate=~/[\/\\]wx[\/\\]/) 7006 { # do NOT search in system /wx/ directory 7007 # for headers without a prefix: sstream.h 7008 return 0; 7009 } 7010 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR 7011 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/) 7012 { # skip ../c++/3.3.3/ if using ../c++/4.5/ 7013 return 0; 7014 } 7015 if($Candidate=~/[\/\\]asm-/ 7016 and (my $Arch = getArch($LibVersion)) ne "unknown") 7017 { # arch-specific header files 7018 if($Candidate!~/[\/\\]asm-\Q$Arch\E/) 7019 {# skip ../asm-arm/ if using x86 architecture 7020 return 0; 7021 } 7022 } 7023 my @Candidates = getSystemHeaders($HName, $LibVersion); 7024 if($#Candidates==1) 7025 { # unique header 7026 return 1; 7027 } 7028 my @SCandidates = getSystemHeaders($Header, $LibVersion); 7029 if($#SCandidates==1) 7030 { # unique name 7031 return 1; 7032 } 7033 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0; 7034 if(get_depth($Candidate)-$SystemDepth>=5) 7035 { # abstract headers in too deep directories 7036 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/ 7037 if(not isAcceptable($Header, $Candidate, $LibVersion)) { 7038 return 0; 7039 } 7040 } 7041 if($Header eq "parser.h" 7042 and $Candidate!~/\/libxml2\//) 7043 { # select parser.h from xml2 library 7044 return 0; 7045 } 7046 if(not get_dirname($Header) 7047 and keys(%{$SystemHeaders{$HName}})>=3) 7048 { # many headers with the same name 7049 # like thread.h included without a prefix 7050 if(not checkFamily(@Candidates)) { 7051 return 0; 7052 } 7053 } 7054 return 1; 7055} 7056 7057sub selectSystemHeader($$) 7058{ # cache function 7059 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) { 7060 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}; 7061 } 7062 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_)); 7063} 7064 7065sub selectSystemHeader_I($$) 7066{ 7067 my ($Header, $LibVersion) = @_; 7068 if(-f $Header) { 7069 return $Header; 7070 } 7071 if(is_abs($Header) and not -f $Header) 7072 { # incorrect absolute path 7073 return ""; 7074 } 7075 if(defined $ConfHeaders{lc($Header)}) 7076 { # too abstract configuration headers 7077 return ""; 7078 } 7079 my $HName = get_filename($Header); 7080 if($OSgroup ne "windows") 7081 { 7082 if(defined $WinHeaders{lc($HName)} 7083 or $HName=~/windows|win32|win64/i) 7084 { # windows headers 7085 return ""; 7086 } 7087 } 7088 if($OSgroup ne "macos") 7089 { 7090 if($HName eq "fp.h") 7091 { # pngconf.h includes fp.h in Mac OS 7092 return ""; 7093 } 7094 } 7095 7096 if(defined $ObsoleteHeaders{$HName}) 7097 { # obsolete headers 7098 return ""; 7099 } 7100 if($OSgroup eq "linux" or $OSgroup eq "bsd") 7101 { 7102 if(defined $AlienHeaders{$HName} 7103 or defined $AlienHeaders{$Header}) 7104 { # alien headers from other systems 7105 return ""; 7106 } 7107 } 7108 7109 foreach my $Path (@{$SystemPaths{"include"}}) 7110 { # search in default paths 7111 if(-f $Path."/".$Header) { 7112 return join_P($Path,$Header); 7113 } 7114 } 7115 if(not defined $Cache{"checkSystemFiles"}) 7116 { # register all headers in system include dirs 7117 checkSystemFiles(); 7118 } 7119 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)} 7120 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion)) 7121 { 7122 if(isRelevant($Header, $Candidate, $LibVersion)) { 7123 return $Candidate; 7124 } 7125 } 7126 # error 7127 return ""; 7128} 7129 7130sub getSystemHeaders($$) 7131{ 7132 my ($Header, $LibVersion) = @_; 7133 my @Candidates = (); 7134 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}})) 7135 { 7136 if(skipHeader($Candidate, $LibVersion)) { 7137 next; 7138 } 7139 push(@Candidates, $Candidate); 7140 } 7141 return @Candidates; 7142} 7143 7144sub cut_path_prefix($$) 7145{ 7146 my ($Path, $Prefix) = @_; 7147 return $Path if(not $Prefix); 7148 $Prefix=~s/[\/\\]+\Z//; 7149 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//; 7150 return $Path; 7151} 7152 7153sub is_default_include_dir($) 7154{ 7155 my $Dir = $_[0]; 7156 $Dir=~s/[\/\\]+\Z//; 7157 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths); 7158} 7159 7160sub identifyHeader($$) 7161{ # cache function 7162 my ($Header, $LibVersion) = @_; 7163 if(not $Header) { 7164 return ""; 7165 } 7166 $Header=~s/\A(\.\.[\\\/])+//g; 7167 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) { 7168 return $Cache{"identifyHeader"}{$LibVersion}{$Header}; 7169 } 7170 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion)); 7171} 7172 7173sub identifyHeader_I($$) 7174{ # search for header by absolute path, relative path or name 7175 my ($Header, $LibVersion) = @_; 7176 if(-f $Header) 7177 { # it's relative or absolute path 7178 return get_abs_path($Header); 7179 } 7180 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING 7181 and my $HeaderDir = find_in_defaults($Header)) 7182 { # search for libc headers in the /usr/include 7183 # for non-libc target library before searching 7184 # in the library paths 7185 return join_P($HeaderDir,$Header); 7186 } 7187 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header}) 7188 { # search in the target library paths 7189 return $Path; 7190 } 7191 elsif(defined $DefaultGccHeader{$Header}) 7192 { # search in the internal GCC include paths 7193 return $DefaultGccHeader{$Header}; 7194 } 7195 elsif(my $DefaultDir = find_in_defaults($Header)) 7196 { # search in the default GCC include paths 7197 return join_P($DefaultDir,$Header); 7198 } 7199 elsif(defined $DefaultCppHeader{$Header}) 7200 { # search in the default G++ include paths 7201 return $DefaultCppHeader{$Header}; 7202 } 7203 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion)) 7204 { # search everywhere in the system 7205 return $AnyPath; 7206 } 7207 elsif($OSgroup eq "macos") 7208 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h" 7209 if(my $Dir = get_dirname($Header)) 7210 { 7211 my $RelPath = "Headers\/".get_filename($Header); 7212 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) { 7213 return join_P($HeaderDir, $RelPath); 7214 } 7215 } 7216 } 7217 # cannot find anything 7218 return ""; 7219} 7220 7221sub getLocation($) 7222{ 7223 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7224 { 7225 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) { 7226 return (path_format($1, $OSgroup), $2); 7227 } 7228 } 7229 return (); 7230} 7231 7232sub getNameByInfo($) 7233{ 7234 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7235 { 7236 if($Info=~/name[ ]*:[ ]*@(\d+) /) 7237 { 7238 if(my $NInfo = $LibInfo{$Version}{"info"}{$1}) 7239 { 7240 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/) 7241 { # short unsigned int (may include spaces) 7242 my $Str = $1; 7243 if($CppMode{$Version} 7244 and $Str=~/\Ac99_(.+)\Z/) 7245 { 7246 if($CppKeywords_A{$1}) { 7247 $Str=$1; 7248 } 7249 } 7250 return $Str; 7251 } 7252 } 7253 } 7254 } 7255 return ""; 7256} 7257 7258sub getTreeStr($) 7259{ 7260 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7261 { 7262 if($Info=~/strg[ ]*:[ ]*([^ ]*)/) 7263 { 7264 my $Str = $1; 7265 if($CppMode{$Version} 7266 and $Str=~/\Ac99_(.+)\Z/) 7267 { 7268 if($CppKeywords_A{$1}) { 7269 $Str=$1; 7270 } 7271 } 7272 return $Str; 7273 } 7274 } 7275 return ""; 7276} 7277 7278sub getFuncShortName($) 7279{ 7280 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7281 { 7282 if(index($Info, " operator ")!=-1) 7283 { 7284 if(index($Info, " conversion ")!=-1) 7285 { 7286 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"}) 7287 { 7288 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) { 7289 return "operator ".$RName; 7290 } 7291 } 7292 } 7293 else 7294 { 7295 if($Info=~/ operator[ ]+([a-zA-Z]+) /) 7296 { 7297 if(my $Ind = $Operator_Indication{$1}) { 7298 return "operator".$Ind; 7299 } 7300 elsif(not $UnknownOperator{$1}) 7301 { 7302 printMsg("WARNING", "unknown operator $1"); 7303 $UnknownOperator{$1} = 1; 7304 } 7305 } 7306 } 7307 } 7308 else 7309 { 7310 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 7311 return getTreeStr($1); 7312 } 7313 } 7314 } 7315 return ""; 7316} 7317 7318sub getFuncReturn($) 7319{ 7320 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7321 { 7322 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7323 { 7324 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) { 7325 return $1; 7326 } 7327 } 7328 } 7329 return ""; 7330} 7331 7332sub getFuncOrig($) 7333{ 7334 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7335 { 7336 if($Info=~/orig[ ]*:[ ]*@(\d+) /) { 7337 return $1; 7338 } 7339 } 7340 return $_[0]; 7341} 7342 7343sub unmangleArray(@) 7344{ 7345 if($_[0]=~/\A\?/) 7346 { # MSVC mangling 7347 my $UndNameCmd = get_CmdPath("undname"); 7348 if(not $UndNameCmd) { 7349 exitStatus("Not_Found", "can't find \"undname\""); 7350 } 7351 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7352 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`); 7353 } 7354 else 7355 { # GCC mangling 7356 my $CppFiltCmd = get_CmdPath("c++filt"); 7357 if(not $CppFiltCmd) { 7358 exitStatus("Not_Found", "can't find c++filt in PATH"); 7359 } 7360 if(not defined $CPPFILT_SUPPORT_FILE) 7361 { 7362 my $Info = `$CppFiltCmd -h 2>&1`; 7363 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/; 7364 } 7365 my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":""; 7366 if($CPPFILT_SUPPORT_FILE) 7367 { # new versions of c++filt can take a file 7368 if($#_>$MAX_CPPFILT_FILE_SIZE) 7369 { # c++filt <= 2.22 may crash on large files (larger than 8mb) 7370 # this is fixed in the oncoming version of Binutils 7371 my @Half = splice(@_, 0, ($#_+1)/2); 7372 return (unmangleArray(@Half), unmangleArray(@_)) 7373 } 7374 else 7375 { 7376 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7377 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`; 7378 if($?==139) 7379 { # segmentation fault 7380 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant"); 7381 } 7382 return split(/\n/, $Res); 7383 } 7384 } 7385 else 7386 { # old-style unmangling 7387 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) 7388 { 7389 my @Half = splice(@_, 0, ($#_+1)/2); 7390 return (unmangleArray(@Half), unmangleArray(@_)) 7391 } 7392 else 7393 { 7394 my $Strings = join(" ", @_); 7395 my $Res = `$CppFiltCmd $NoStrip $Strings`; 7396 if($?==139) 7397 { # segmentation fault 7398 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant"); 7399 } 7400 return split(/\n/, $Res); 7401 } 7402 } 7403 } 7404} 7405 7406sub get_SignatureNoInfo($$) 7407{ 7408 my ($Symbol, $LibVersion) = @_; 7409 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) { 7410 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}; 7411 } 7412 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 7413 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName; 7414 if($Symbol=~/\A(_Z|\?)/) 7415 { # C++ 7416 # some standard typedefs 7417 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g; 7418 $Signature=~s/\Qstd::map<std::string, std::string, std::less<std::string >, std::allocator<std::pair<std::string const, std::string > > >\E/std::map<std::string, std::string>/g; 7419 } 7420 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i) 7421 { # ELF format marks data as OBJECT 7422 if($GlobalDataObject{$LibVersion}{$Symbol}) { 7423 $Signature .= " [data]"; 7424 } 7425 elsif($Symbol!~/\A(_Z|\?)/) { 7426 $Signature .= " (...)"; 7427 } 7428 } 7429 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) 7430 { 7431 my $ShortName = substr($Signature, 0, find_center($Signature, "(")); 7432 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g; 7433 } 7434 if($SymbolVersion) { 7435 $Signature .= $VersionSpec.$SymbolVersion; 7436 } 7437 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature); 7438} 7439 7440sub get_ChargeLevel($$) 7441{ 7442 my ($Symbol, $LibVersion) = @_; 7443 return "" if($Symbol!~/\A(_Z|\?)/); 7444 if(defined $CompleteSignature{$LibVersion}{$Symbol} 7445 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) 7446 { 7447 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}) 7448 { 7449 if($Symbol=~/C1[EI]/) { 7450 return "[in-charge]"; 7451 } 7452 elsif($Symbol=~/C2[EI]/) { 7453 return "[not-in-charge]"; 7454 } 7455 } 7456 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) 7457 { 7458 if($Symbol=~/D1[EI]/) { 7459 return "[in-charge]"; 7460 } 7461 elsif($Symbol=~/D2[EI]/) { 7462 return "[not-in-charge]"; 7463 } 7464 elsif($Symbol=~/D0[EI]/) { 7465 return "[in-charge-deleting]"; 7466 } 7467 } 7468 } 7469 else 7470 { 7471 if($Symbol=~/C1[EI]/) { 7472 return "[in-charge]"; 7473 } 7474 elsif($Symbol=~/C2[EI]/) { 7475 return "[not-in-charge]"; 7476 } 7477 elsif($Symbol=~/D1[EI]/) { 7478 return "[in-charge]"; 7479 } 7480 elsif($Symbol=~/D2[EI]/) { 7481 return "[not-in-charge]"; 7482 } 7483 elsif($Symbol=~/D0[EI]/) { 7484 return "[in-charge-deleting]"; 7485 } 7486 } 7487 return ""; 7488} 7489 7490sub get_Signature_M($$) 7491{ 7492 my ($Symbol, $LibVersion) = @_; 7493 my $Signature_M = $tr_name{$Symbol}; 7494 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 7495 { # add return type name 7496 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M; 7497 } 7498 return $Signature_M; 7499} 7500 7501sub get_Signature($$) 7502{ 7503 my ($Symbol, $LibVersion) = @_; 7504 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) { 7505 return $Cache{"get_Signature"}{$LibVersion}{$Symbol}; 7506 } 7507 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 7508 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) 7509 { # non-public global data 7510 return get_SignatureNoInfo($Symbol, $LibVersion); 7511 } 7512 my ($Signature, @Param_Types_FromUnmangledName) = (); 7513 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 7514 if($Symbol=~/\A(_Z|\?)/) 7515 { 7516 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 7517 { 7518 $Signature .= $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::"; 7519 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { 7520 $Signature .= "~"; 7521 } 7522 $Signature .= $ShortName; 7523 } 7524 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) { 7525 $Signature .= $NameSpace."::".$ShortName; 7526 } 7527 else { 7528 $Signature .= $ShortName; 7529 } 7530 my ($Short, $Params) = split_Signature($tr_name{$MnglName}); 7531 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1); 7532 } 7533 else 7534 { 7535 $Signature .= $MnglName; 7536 } 7537 my @ParamArray = (); 7538 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 7539 { 7540 next if($Pos eq ""); 7541 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}; 7542 next if(not $ParamTypeId); 7543 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"}; 7544 if(not $ParamTypeName) { 7545 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos]; 7546 } 7547 foreach my $Typedef (keys(%ChangedTypedef)) 7548 { 7549 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 7550 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g; 7551 } 7552 } 7553 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) 7554 { 7555 if($ParamName eq "this" 7556 and $Symbol=~/\A(_Z|\?)/) 7557 { # do NOT show first hidded "this"-parameter 7558 next; 7559 } 7560 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName)); 7561 } 7562 else { 7563 push(@ParamArray, $ParamTypeName); 7564 } 7565 } 7566 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"} 7567 or $GlobalDataObject{$LibVersion}{$Symbol}) { 7568 $Signature .= " [data]"; 7569 } 7570 else 7571 { 7572 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) 7573 { # add [in-charge] 7574 $Signature .= " ".$ChargeLevel; 7575 } 7576 $Signature .= " (".join(", ", @ParamArray).")"; 7577 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"} 7578 or $Symbol=~/\A_ZN(V|)K/) { 7579 $Signature .= " const"; 7580 } 7581 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"} 7582 or $Symbol=~/\A_ZN(K|)V/) { 7583 $Signature .= " volatile"; 7584 } 7585 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"} 7586 and $Symbol=~/\A(_Z|\?)/) 7587 { # for static methods 7588 $Signature .= " [static]"; 7589 } 7590 } 7591 if(defined $ShowRetVal 7592 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { 7593 $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"}; 7594 } 7595 if($SymbolVersion) { 7596 $Signature .= $VersionSpec.$SymbolVersion; 7597 } 7598 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature); 7599} 7600 7601sub create_member_decl($$) 7602{ 7603 my ($TName, $Member) = @_; 7604 if($TName=~/\([\*]+\)/) 7605 { 7606 $TName=~s/\(([\*]+)\)/\($1$Member\)/; 7607 return $TName; 7608 } 7609 else 7610 { 7611 my @ArraySizes = (); 7612 while($TName=~s/(\[[^\[\]]*\])\Z//) { 7613 push(@ArraySizes, $1); 7614 } 7615 return $TName." ".$Member.join("", @ArraySizes); 7616 } 7617} 7618 7619sub getFuncType($) 7620{ 7621 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7622 { 7623 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7624 { 7625 if(my $Type = $LibInfo{$Version}{"info_type"}{$1}) 7626 { 7627 if($Type eq "method_type") { 7628 return "Method"; 7629 } 7630 elsif($Type eq "function_type") { 7631 return "Function"; 7632 } 7633 else { 7634 return "Other"; 7635 } 7636 } 7637 } 7638 } 7639 return ""; 7640} 7641 7642sub getFuncTypeId($) 7643{ 7644 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7645 { 7646 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) { 7647 return $1; 7648 } 7649 } 7650 return 0; 7651} 7652 7653sub isAnon($) 7654{ # "._N" or "$_N" in older GCC versions 7655 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/); 7656} 7657 7658sub formatName($$) 7659{ # type name correction 7660 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) { 7661 return $Cache{"formatName"}{$_[1]}{$_[0]}; 7662 } 7663 7664 my $N = $_[0]; 7665 7666 if($_[1] ne "S") 7667 { 7668 $N=~s/\A[ ]+//g; 7669 $N=~s/[ ]+\Z//g; 7670 $N=~s/[ ]{2,}/ /g; 7671 } 7672 7673 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const 7674 7675 $N=~s/\bvolatile const\b/const volatile/g; 7676 7677 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g; 7678 $N=~s/\b(short|long) int\b/$1/g; 7679 7680 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g; 7681 7682 while($N=~s/>>/> >/g) {}; 7683 7684 if($_[1] eq "S") 7685 { 7686 if(index($N, "operator")!=-1) { 7687 $N=~s/\b(operator[ ]*)> >/$1>>/; 7688 } 7689 } 7690 7691 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N); 7692} 7693 7694sub get_HeaderDeps($$) 7695{ 7696 my ($AbsPath, $LibVersion) = @_; 7697 return () if(not $AbsPath or not $LibVersion); 7698 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) { 7699 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7700 } 7701 my %IncDir = (); 7702 detect_recursive_includes($AbsPath, $LibVersion); 7703 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) 7704 { 7705 next if(not $HeaderPath); 7706 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/); 7707 my $Dir = get_dirname($HeaderPath); 7708 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}})) 7709 { 7710 my $Dep = $Dir; 7711 if($Prefix) 7712 { 7713 if($OSgroup eq "windows") 7714 { # case insensitive seach on windows 7715 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) { 7716 next; 7717 } 7718 } 7719 elsif($OSgroup eq "macos") 7720 { # seach in frameworks 7721 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7722 { 7723 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/) 7724 {# frameworks 7725 my ($HFramework, $HName) = ($1, $2); 7726 $Dep = $HFramework; 7727 } 7728 else 7729 {# mismatch 7730 next; 7731 } 7732 } 7733 } 7734 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7735 { # Linux, FreeBSD 7736 next; 7737 } 7738 } 7739 if(not $Dep) 7740 { # nothing to include 7741 next; 7742 } 7743 if(is_default_include_dir($Dep)) 7744 { # included by the compiler 7745 next; 7746 } 7747 if(get_depth($Dep)==1) 7748 { # too short 7749 next; 7750 } 7751 if(isLibcDir($Dep)) 7752 { # do NOT include /usr/include/{sys,bits} 7753 next; 7754 } 7755 $IncDir{$Dep} = 1; 7756 } 7757 } 7758 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion); 7759 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7760} 7761 7762sub sortIncPaths($$) 7763{ 7764 my ($ArrRef, $LibVersion) = @_; 7765 if(not $ArrRef or $#{$ArrRef}<0) { 7766 return $ArrRef; 7767 } 7768 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef}; 7769 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef}; 7770 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef}; 7771 return $ArrRef; 7772} 7773 7774sub sortDeps($$$) 7775{ 7776 if($Header_Dependency{$_[2]}{$_[0]} 7777 and not $Header_Dependency{$_[2]}{$_[1]}) { 7778 return 1; 7779 } 7780 elsif(not $Header_Dependency{$_[2]}{$_[0]} 7781 and $Header_Dependency{$_[2]}{$_[1]}) { 7782 return -1; 7783 } 7784 return 0; 7785} 7786 7787sub join_P($$) 7788{ 7789 my $S = "/"; 7790 if($OSgroup eq "windows") { 7791 $S = "\\"; 7792 } 7793 return join($S, @_); 7794} 7795 7796sub get_namespace_additions($) 7797{ 7798 my $NameSpaces = $_[0]; 7799 my ($Additions, $AddNameSpaceId) = ("", 1); 7800 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces})) 7801 { 7802 next if($SkipNameSpaces{$Version}{$NS}); 7803 next if(not $NS or $NameSpaces->{$NS}==-1); 7804 next if($NS=~/(\A|::)iterator(::|\Z)/i); 7805 next if($NS=~/\A__/i); 7806 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING); 7807 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports 7808 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = (); 7809 my @NS_Parts = split(/::/, $NS); 7810 next if($#NS_Parts==-1); 7811 next if($NS_Parts[0]=~/\A(random|or)\Z/); 7812 foreach my $NS_Part (@NS_Parts) 7813 { 7814 $TypeDecl_Prefix .= "namespace $NS_Part\{"; 7815 $TypeDecl_Suffix .= "}"; 7816 } 7817 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix; 7818 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};"; 7819 $Additions.=" $TypeDecl\n $FuncDecl\n"; 7820 $AddNameSpaceId+=1; 7821 } 7822 return $Additions; 7823} 7824 7825sub path_format($$) 7826{ 7827 my ($Path, $Fmt) = @_; 7828 $Path=~s/[\/\\]+\.?\Z//g; 7829 if($Fmt eq "windows") 7830 { 7831 $Path=~s/\//\\/g; 7832 $Path=lc($Path); 7833 } 7834 else 7835 { # forward slash to pass into MinGW GCC 7836 $Path=~s/\\/\//g; 7837 } 7838 return $Path; 7839} 7840 7841sub inc_opt($$) 7842{ 7843 my ($Path, $Style) = @_; 7844 if($Style eq "GCC") 7845 { # GCC options 7846 if($OSgroup eq "windows") 7847 { # to MinGW GCC 7848 return "-I\"".path_format($Path, "unix")."\""; 7849 } 7850 elsif($OSgroup eq "macos" 7851 and $Path=~/\.framework\Z/) 7852 { # to Apple's GCC 7853 return "-F".esc(get_dirname($Path)); 7854 } 7855 else { 7856 return "-I".esc($Path); 7857 } 7858 } 7859 elsif($Style eq "CL") { 7860 return "/I \"".$Path."\""; 7861 } 7862 return ""; 7863} 7864 7865sub platformSpecs($) 7866{ 7867 my $LibVersion = $_[0]; 7868 my $Arch = getArch($LibVersion); 7869 if($OStarget eq "symbian") 7870 { # options for GCCE compiler 7871 my %Symbian_Opts = map {$_=>1} ( 7872 "-D__GCCE__", 7873 "-DUNICODE", 7874 "-fexceptions", 7875 "-D__SYMBIAN32__", 7876 "-D__MARM_INTERWORK__", 7877 "-D_UNICODE", 7878 "-D__S60_50__", 7879 "-D__S60_3X__", 7880 "-D__SERIES60_3X__", 7881 "-D__EPOC32__", 7882 "-D__MARM__", 7883 "-D__EABI__", 7884 "-D__MARM_ARMV5__", 7885 "-D__SUPPORT_CPP_EXCEPTIONS__", 7886 "-march=armv5t", 7887 "-mapcs", 7888 "-mthumb-interwork", 7889 "-DEKA2", 7890 "-DSYMBIAN_ENABLE_SPLIT_HEADERS" 7891 ); 7892 return join(" ", keys(%Symbian_Opts)); 7893 } 7894 elsif($OSgroup eq "windows" 7895 and get_dumpmachine($GCC_PATH)=~/mingw/i) 7896 { # add options to MinGW compiler 7897 # to simulate the MSVC compiler 7898 my %MinGW_Opts = map {$_=>1} ( 7899 "-D_WIN32", 7900 "-D_STDCALL_SUPPORTED", 7901 "-D__int64=\"long long\"", 7902 "-D__int32=int", 7903 "-D__int16=short", 7904 "-D__int8=char", 7905 "-D__possibly_notnullterminated=\" \"", 7906 "-D__nullterminated=\" \"", 7907 "-D__nullnullterminated=\" \"", 7908 "-D__w64=\" \"", 7909 "-D__ptr32=\" \"", 7910 "-D__ptr64=\" \"", 7911 "-D__forceinline=inline", 7912 "-D__inline=inline", 7913 "-D__uuidof(x)=IID()", 7914 "-D__try=", 7915 "-D__except(x)=", 7916 "-D__declspec(x)=__attribute__((x))", 7917 "-D__pragma(x)=", 7918 "-D_inline=inline", 7919 "-D__forceinline=__inline", 7920 "-D__stdcall=__attribute__((__stdcall__))", 7921 "-D__cdecl=__attribute__((__cdecl__))", 7922 "-D__fastcall=__attribute__((__fastcall__))", 7923 "-D__thiscall=__attribute__((__thiscall__))", 7924 "-D_stdcall=__attribute__((__stdcall__))", 7925 "-D_cdecl=__attribute__((__cdecl__))", 7926 "-D_fastcall=__attribute__((__fastcall__))", 7927 "-D_thiscall=__attribute__((__thiscall__))", 7928 "-DSHSTDAPI_(x)=x", 7929 "-D_MSC_EXTENSIONS", 7930 "-DSECURITY_WIN32", 7931 "-D_MSC_VER=1500", 7932 "-D_USE_DECLSPECS_FOR_SAL", 7933 "-D__noop=\" \"", 7934 "-DDECLSPEC_DEPRECATED=\" \"", 7935 "-D__builtin_alignof(x)=__alignof__(x)", 7936 "-DSORTPP_PASS"); 7937 if($Arch eq "x86") { 7938 $MinGW_Opts{"-D_M_IX86=300"}=1; 7939 } 7940 elsif($Arch eq "x86_64") { 7941 $MinGW_Opts{"-D_M_AMD64=300"}=1; 7942 } 7943 elsif($Arch eq "ia64") { 7944 $MinGW_Opts{"-D_M_IA64=300"}=1; 7945 } 7946 return join(" ", keys(%MinGW_Opts)); 7947 } 7948 return ""; 7949} 7950 7951my %C_Structure = map {$_=>1} ( 7952# FIXME: Can't separate union and struct data types before dumping, 7953# so it sometimes cause compilation errors for unknown reason 7954# when trying to declare TYPE* tmp_add_class_N 7955# This is a list of such structures + list of other C structures 7956 "sigval", 7957 "sigevent", 7958 "sigaction", 7959 "sigvec", 7960 "sigstack", 7961 "timeval", 7962 "timezone", 7963 "rusage", 7964 "rlimit", 7965 "wait", 7966 "flock", 7967 "stat", 7968 "_stat", 7969 "stat32", 7970 "_stat32", 7971 "stat64", 7972 "_stat64", 7973 "_stati64", 7974 "if_nameindex", 7975 "usb_device", 7976 "sigaltstack", 7977 "sysinfo", 7978 "timeLocale", 7979 "tcp_debug", 7980 "rpc_createerr", 7981 # Other 7982 "timespec", 7983 "random_data", 7984 "drand48_data", 7985 "_IO_marker", 7986 "_IO_FILE", 7987 "lconv", 7988 "sched_param", 7989 "tm", 7990 "itimerspec", 7991 "_pthread_cleanup_buffer", 7992 "fd_set", 7993 "siginfo", 7994 "mallinfo", 7995 "timex", 7996 "sigcontext", 7997 "ucontext", 7998 # Mac 7999 "_timex", 8000 "_class_t", 8001 "_category_t", 8002 "_class_ro_t", 8003 "_protocol_t", 8004 "_message_ref_t", 8005 "_super_message_ref_t", 8006 "_ivar_t", 8007 "_ivar_list_t" 8008); 8009 8010sub getCompileCmd($$$) 8011{ 8012 my ($Path, $Opt, $Inc) = @_; 8013 my $GccCall = $GCC_PATH; 8014 if($Opt) { 8015 $GccCall .= " ".$Opt; 8016 } 8017 $GccCall .= " -x "; 8018 if($OSgroup eq "macos") { 8019 $GccCall .= "objective-"; 8020 } 8021 8022 if($EMERGENCY_MODE_48) 8023 { # workaround for GCC 4.8 (C only) 8024 $GccCall .= "c++"; 8025 } 8026 elsif(check_gcc($GCC_PATH, "4")) 8027 { # compile as "C++" header 8028 # to obtain complete dump using GCC 4.0 8029 $GccCall .= "c++-header"; 8030 } 8031 else 8032 { # compile as "C++" source 8033 # GCC 3.3 cannot compile headers 8034 $GccCall .= "c++"; 8035 } 8036 if(my $Opts = platformSpecs($Version)) 8037 { # platform-specific options 8038 $GccCall .= " ".$Opts; 8039 } 8040 # allow extra qualifications 8041 # and other nonconformant code 8042 $GccCall .= " -fpermissive"; 8043 $GccCall .= " -w"; 8044 if($NoStdInc) 8045 { 8046 $GccCall .= " -nostdinc"; 8047 $GccCall .= " -nostdinc++"; 8048 } 8049 if(my $Opts_GCC = getGCC_Opts($Version)) 8050 { # user-defined options 8051 $GccCall .= " ".$Opts_GCC; 8052 } 8053 $GccCall .= " \"$Path\""; 8054 if($Inc) 8055 { # include paths 8056 $GccCall .= " ".$Inc; 8057 } 8058 return $GccCall; 8059} 8060 8061sub detectPreamble($$) 8062{ 8063 my ($Content, $LibVersion) = @_; 8064 my %HeaderElems = ( 8065 # Types 8066 "stdio.h" => ["FILE", "va_list"], 8067 "stddef.h" => ["NULL", "ptrdiff_t"], 8068 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t", 8069 "int8_t", "int16_t", "int32_t", "int64_t"], 8070 "time.h" => ["time_t"], 8071 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char", 8072 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"], 8073 "unistd.h" => ["gid_t", "uid_t", "socklen_t"], 8074 "stdbool.h" => ["_Bool"], 8075 "rpc/xdr.h" => ["bool_t"], 8076 "in_systm.h" => ["n_long", "n_short"], 8077 # Fields 8078 "arpa/inet.h" => ["fw_src", "ip_src"], 8079 # Functions 8080 "stdlib.h" => ["free", "malloc", "size_t"], 8081 "string.h" => ["memmove", "strcmp"] 8082 ); 8083 my %AutoPreamble = (); 8084 foreach (keys(%HeaderElems)) 8085 { 8086 foreach my $Elem (@{$HeaderElems{$_}}) { 8087 $AutoPreamble{$Elem} = $_; 8088 } 8089 } 8090 my %Types = (); 8091 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//) 8092 { # error: 'FILE' has not been declared 8093 $Types{$2} = 1; 8094 } 8095 if(keys(%Types)) 8096 { 8097 my %AddHeaders = (); 8098 foreach my $Type (keys(%Types)) 8099 { 8100 if(my $Header = $AutoPreamble{$Type}) 8101 { 8102 if(my $Path = identifyHeader($Header, $LibVersion)) 8103 { 8104 if(skipHeader($Path, $LibVersion)) { 8105 next; 8106 } 8107 $Path = path_format($Path, $OSgroup); 8108 $AddHeaders{$Path}{"Type"} = $Type; 8109 $AddHeaders{$Path}{"Header"} = $Header; 8110 } 8111 } 8112 } 8113 if(keys(%AddHeaders)) { 8114 return \%AddHeaders; 8115 } 8116 } 8117 return undef; 8118} 8119 8120sub checkCTags($) 8121{ 8122 my $Path = $_[0]; 8123 if(not $Path) { 8124 return; 8125 } 8126 my $CTags = undef; 8127 8128 if($OSgroup eq "bsd") 8129 { # use ectags on BSD 8130 $CTags = get_CmdPath("ectags"); 8131 if(not $CTags) { 8132 printMsg("WARNING", "can't find \'ectags\' program"); 8133 } 8134 } 8135 if(not $CTags) { 8136 $CTags = get_CmdPath("ctags"); 8137 } 8138 if(not $CTags) 8139 { 8140 printMsg("WARNING", "can't find \'ctags\' program"); 8141 return; 8142 } 8143 8144 if($OSgroup ne "linux") 8145 { # macos, freebsd, etc. 8146 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`; 8147 if($Info!~/exuberant/i) 8148 { 8149 printMsg("WARNING", "incompatible version of \'ctags\' program"); 8150 return; 8151 } 8152 } 8153 8154 my $Out = $TMP_DIR."/ctags.txt"; 8155 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\""); 8156 if($Debug) { 8157 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt"); 8158 } 8159 open(CTAGS, "<", $Out); 8160 while(my $Line = <CTAGS>) 8161 { 8162 chomp($Line); 8163 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line); 8164 if(defined $Intrinsic_Keywords{$Name}) 8165 { # noise 8166 next; 8167 } 8168 if($Type eq "n") 8169 { 8170 if(index($Scpe, "class:")==0) { 8171 next; 8172 } 8173 if(index($Scpe, "struct:")==0) { 8174 next; 8175 } 8176 if(index($Scpe, "namespace:")==0) 8177 { 8178 if($Scpe=~s/\Anamespace://) { 8179 $Name = $Scpe."::".$Name; 8180 } 8181 } 8182 $TUnit_NameSpaces{$Version}{$Name} = 1; 8183 } 8184 elsif($Type eq "p") 8185 { 8186 if(not $Scpe or index($Scpe, "namespace:")==0) { 8187 $TUnit_Funcs{$Version}{$Name} = 1; 8188 } 8189 } 8190 elsif($Type eq "x") 8191 { 8192 if(not $Scpe or index($Scpe, "namespace:")==0) { 8193 $TUnit_Vars{$Version}{$Name} = 1; 8194 } 8195 } 8196 } 8197 close(CTAGS); 8198} 8199 8200sub preChange($$) 8201{ 8202 my ($HeaderPath, $IncStr) = @_; 8203 8204 my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr); 8205 my $Content = undef; 8206 8207 if($OStarget eq "windows" 8208 and get_dumpmachine($GCC_PATH)=~/mingw/i 8209 and $MinGWMode{$Version}!=-1) 8210 { # modify headers to compile by MinGW 8211 if(not $Content) 8212 { # preprocessing 8213 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8214 } 8215 if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g) 8216 { # __asm { ... } 8217 $MinGWMode{$Version}=1; 8218 } 8219 if($Content=~s/\s+(\/ \/.*?)\n/\n/g) 8220 { # comments after preprocessing 8221 $MinGWMode{$Version}=1; 8222 } 8223 if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g) 8224 { # 0xffui8 8225 $MinGWMode{$Version}=1; 8226 } 8227 8228 if($MinGWMode{$Version}) { 8229 printMsg("INFO", "Using MinGW compatibility mode"); 8230 } 8231 } 8232 8233 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly) 8234 and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS) 8235 { # rename C++ keywords in C code 8236 # disable this code by -cpp-compatible option 8237 if(not $Content) 8238 { # preprocessing 8239 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8240 } 8241 my $RegExp_C = join("|", keys(%CppKeywords_C)); 8242 my $RegExp_F = join("|", keys(%CppKeywords_F)); 8243 my $RegExp_O = join("|", keys(%CppKeywords_O)); 8244 8245 my $Detected = undef; 8246 8247 while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/$1$2c99_$3$4/g) 8248 { # MATCH: 8249 # int foo(int new, int class, int (*new)(int)); 8250 # int foo(char template[], char*); 8251 # unsigned private: 8; 8252 # DO NOT MATCH: 8253 # #pragma GCC visibility push(default) 8254 $CppMode{$Version} = 1; 8255 $Detected = "$1$2$3$4" if(not defined $Detected); 8256 } 8257 if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g) 8258 { # MATCH: 8259 # int delete(...); 8260 # int explicit(...); 8261 # DO NOT MATCH: 8262 # void operator delete(...) 8263 $CppMode{$Version} = 1; 8264 $Detected = "$1$2$3" if(not defined $Detected); 8265 } 8266 if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g) 8267 { # MATCH: 8268 # int bool; 8269 # DO NOT MATCH: 8270 # bool X; 8271 # return *this; 8272 # throw; 8273 $CppMode{$Version} = 1; 8274 $Detected = "$1$2$3" if(not defined $Detected); 8275 } 8276 if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g) 8277 { # MATCH: 8278 # int operator(...); 8279 # DO NOT MATCH: 8280 # int operator()(...); 8281 $CppMode{$Version} = 1; 8282 $Detected = "$1$2$3" if(not defined $Detected); 8283 } 8284 if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g) 8285 { # MATCH: 8286 # int foo(int operator); 8287 # int foo(int operator, int other); 8288 # DO NOT MATCH: 8289 # int operator,(...); 8290 $CppMode{$Version} = 1; 8291 $Detected = "$1$2$3" if(not defined $Detected); 8292 } 8293 if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g) 8294 { # MATCH: 8295 # int foo(gboolean *bool); 8296 # DO NOT MATCH: 8297 # void setTabEnabled(int index, bool); 8298 $CppMode{$Version} = 1; 8299 $Detected = "$1$2$3" if(not defined $Detected); 8300 } 8301 if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g) 8302 { # MATCH: 8303 # int foo(int* this); 8304 # int bar(int this); 8305 # int baz(int throw); 8306 # DO NOT MATCH: 8307 # foo(X, this); 8308 $CppMode{$Version} = 1; 8309 $Detected = "$1$2$3$4" if(not defined $Detected); 8310 } 8311 if($Content=~s/(struct |extern )(template) /$1c99_$2 /g) 8312 { # MATCH: 8313 # struct template {...}; 8314 # extern template foo(...); 8315 $CppMode{$Version} = 1; 8316 $Detected = "$1$2" if(not defined $Detected); 8317 } 8318 8319 if($CppMode{$Version} == 1) 8320 { 8321 if($Debug) 8322 { 8323 $Detected=~s/\A\s+//g; 8324 printMsg("INFO", "Detected code: \"$Detected\""); 8325 } 8326 } 8327 8328 # remove typedef enum NAME NAME; 8329 my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g; 8330 my $N = 0; 8331 while($N<=$#FwdTypedefs-1) 8332 { 8333 my $S = $FwdTypedefs[$N]; 8334 if($S eq $FwdTypedefs[$N+1]) 8335 { 8336 $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g; 8337 $CppMode{$Version} = 1; 8338 8339 if($Debug) { 8340 printMsg("INFO", "Detected code: \"typedef enum $S $S;\""); 8341 } 8342 } 8343 $N+=2; 8344 } 8345 8346 if($CppMode{$Version}==1) { 8347 printMsg("INFO", "Using C++ compatibility mode"); 8348 } 8349 } 8350 8351 if($CppMode{$Version}==1 8352 or $MinGWMode{$Version}==1) 8353 { 8354 my $IPath = $TMP_DIR."/dump$Version.i"; 8355 writeFile($IPath, $Content); 8356 return $IPath; 8357 } 8358 8359 return undef; 8360} 8361 8362sub getDump() 8363{ 8364 if(not $GCC_PATH) { 8365 exitStatus("Error", "internal error - GCC path is not set"); 8366 } 8367 8368 my @Headers = keys(%{$Registered_Headers{$Version}}); 8369 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers; 8370 8371 my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC"); 8372 8373 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h"; 8374 my $HeaderPath = $TmpHeaderPath; 8375 8376 # write tmp-header 8377 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n"); 8378 if(my $AddDefines = $Descriptor{$Version}{"Defines"}) 8379 { 8380 $AddDefines=~s/\n\s+/\n /g; 8381 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n"; 8382 } 8383 print TMP_HEADER "\n // add includes\n"; 8384 foreach my $HPath (@{$Include_Preamble{$Version}}) { 8385 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8386 } 8387 foreach my $HPath (@Headers) 8388 { 8389 if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) { 8390 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8391 } 8392 } 8393 close(TMP_HEADER); 8394 8395 if($ExtraInfo) 8396 { # extra information for other tools 8397 if($IncludeString) { 8398 writeFile($ExtraInfo."/include-string", $IncludeString); 8399 } 8400 writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version})); 8401 writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version})); 8402 8403 if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}})) 8404 { 8405 my $REDIR = ""; 8406 foreach my $P1 (sort @Redirects) { 8407 $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n"; 8408 } 8409 writeFile($ExtraInfo."/include-redirect", $REDIR); 8410 } 8411 } 8412 8413 if(not keys(%{$TargetHeaders{$Version}})) 8414 { # Target headers 8415 addTargetHeaders($Version); 8416 } 8417 8418 # clean memory 8419 %RecursiveIncludes = (); 8420 %Header_Include_Prefix = (); 8421 %Header_Includes = (); 8422 8423 # clean cache 8424 delete($Cache{"identifyHeader"}); 8425 delete($Cache{"detect_header_includes"}); 8426 delete($Cache{"selectSystemHeader"}); 8427 8428 # preprocessing stage 8429 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version); 8430 checkPreprocessedUnit($Pre); 8431 8432 if($ExtraInfo) 8433 { # extra information for other tools 8434 writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}}))); 8435 } 8436 8437 # clean memory 8438 delete($Include_Neighbors{$Version}); 8439 delete($PreprocessedHeaders{$Version}); 8440 8441 if($COMMON_LANGUAGE{$Version} eq "C++") { 8442 checkCTags($Pre); 8443 } 8444 8445 if(my $PrePath = preChange($TmpHeaderPath, $IncludeString)) 8446 { # try to correct the preprocessor output 8447 $HeaderPath = $PrePath; 8448 } 8449 8450 if($COMMON_LANGUAGE{$Version} eq "C++") 8451 { # add classes and namespaces to the dump 8452 my $CHdump = "-fdump-class-hierarchy -c"; 8453 if($CppMode{$Version}==1 8454 or $MinGWMode{$Version}==1) { 8455 $CHdump .= " -fpreprocessed"; 8456 } 8457 my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString); 8458 chdir($TMP_DIR); 8459 system($ClassHierarchyCmd." >null 2>&1"); 8460 chdir($ORIG_DIR); 8461 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0]) 8462 { 8463 my $Content = readFile($ClassDump); 8464 foreach my $ClassInfo (split(/\n\n/, $Content)) 8465 { 8466 if($ClassInfo=~/\AClass\s+(.+)\s*/i) 8467 { 8468 my $CName = $1; 8469 next if($CName=~/\A(__|_objc_|_opaque_)/); 8470 $TUnit_NameSpaces{$Version}{$CName} = -1; 8471 if($CName=~/\A[\w:]+\Z/) 8472 { # classes 8473 $TUnit_Classes{$Version}{$CName} = 1; 8474 } 8475 if($CName=~/(\w[\w:]*)::/) 8476 { # namespaces 8477 my $NS = $1; 8478 if(not defined $TUnit_NameSpaces{$Version}{$NS}) { 8479 $TUnit_NameSpaces{$Version}{$NS} = 1; 8480 } 8481 } 8482 } 8483 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i) 8484 { # read v-tables (advanced approach) 8485 my ($CName, $VTable) = ($1, $2); 8486 $ClassVTable_Content{$Version}{$CName} = $VTable; 8487 } 8488 } 8489 foreach my $NS (keys(%{$AddNameSpaces{$Version}})) 8490 { # add user-defined namespaces 8491 $TUnit_NameSpaces{$Version}{$NS} = 1; 8492 } 8493 if($Debug) 8494 { # debug mode 8495 mkpath($DEBUG_PATH{$Version}); 8496 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt"); 8497 } 8498 unlink($ClassDump); 8499 } 8500 8501 # add namespaces and classes 8502 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version})) 8503 { # GCC on all supported platforms does not include namespaces to the dump by default 8504 appendFile($HeaderPath, "\n // add namespaces\n".$NS_Add); 8505 } 8506 # some GCC versions don't include class methods to the TU dump by default 8507 my ($AddClass, $ClassNum) = ("", 0); 8508 my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions 8509 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}})) 8510 { 8511 next if($C_Structure{$CName}); 8512 next if(not $STDCXX_TESTING and $CName=~/\Astd::/); 8513 next if($SkipTypes{$Version}{$CName}); 8514 if(not $Force and $GCC_44 8515 and $OSgroup eq "linux") 8516 { # optimization for linux with GCC >= 4.4 8517 # disable this code by -force option 8518 if(index($CName, "::")!=-1) 8519 { # should be added by name space 8520 next; 8521 } 8522 } 8523 else 8524 { 8525 if($CName=~/\A(.+)::[^:]+\Z/ 8526 and $TUnit_Classes{$Version}{$1}) 8527 { # classes inside other classes 8528 next; 8529 } 8530 } 8531 if(defined $TUnit_Funcs{$Version}{$CName}) 8532 { # the same name for a function and type 8533 next; 8534 } 8535 if(defined $TUnit_Vars{$Version}{$CName}) 8536 { # the same name for a variable and type 8537 next; 8538 } 8539 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n"; 8540 } 8541 if($AddClass) { 8542 appendFile($HeaderPath, "\n // add classes\n".$AddClass); 8543 } 8544 } 8545 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n"); 8546 # create TU dump 8547 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c"; 8548 if($UserLang eq "C") { 8549 $TUdump .= " -U__cplusplus -D_Bool=\"bool\""; 8550 } 8551 if($CppMode{$Version}==1 8552 or $MinGWMode{$Version}==1) { 8553 $TUdump .= " -fpreprocessed"; 8554 } 8555 my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString); 8556 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n"); 8557 chdir($TMP_DIR); 8558 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1"); 8559 my $Errors = ""; 8560 if($?) 8561 { # failed to compile, but the TU dump still can be created 8562 if($Errors = readFile($TMP_DIR."/tu_errors")) 8563 { # try to recompile 8564 # FIXME: handle other errors and try to recompile 8565 if($CppMode{$Version}==1 8566 and index($Errors, "c99_")!=-1 8567 and not defined $CppIncompat) 8568 { # disable c99 mode and try again 8569 $CppMode{$Version}=-1; 8570 8571 if($Debug) 8572 { 8573 # printMsg("INFO", $Errors); 8574 } 8575 8576 printMsg("INFO", "Disabling C++ compatibility mode"); 8577 resetLogging($Version); 8578 $TMP_DIR = tempdir(CLEANUP=>1); 8579 return getDump(); 8580 } 8581 elsif($AutoPreambleMode{$Version}!=-1 8582 and my $AddHeaders = detectPreamble($Errors, $Version)) 8583 { # add auto preamble headers and try again 8584 $AutoPreambleMode{$Version}=-1; 8585 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first 8586 foreach my $Num (0 .. $#Headers) 8587 { 8588 my $Path = $Headers[$Num]; 8589 if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}})) 8590 { 8591 push_U($Include_Preamble{$Version}, $Path); 8592 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'"); 8593 } 8594 } 8595 resetLogging($Version); 8596 $TMP_DIR = tempdir(CLEANUP=>1); 8597 return getDump(); 8598 } 8599 elsif($Cpp0xMode{$Version}!=-1 8600 and ($Errors=~/\Q-std=c++0x\E/ 8601 or $Errors=~/is not a class or namespace/)) 8602 { # c++0x: enum class 8603 if(check_gcc($GCC_PATH, "4.6")) 8604 { 8605 $Cpp0xMode{$Version}=-1; 8606 printMsg("INFO", "Enabling c++0x mode"); 8607 resetLogging($Version); 8608 $TMP_DIR = tempdir(CLEANUP=>1); 8609 $CompilerOptions{$Version} .= " -std=c++0x"; 8610 return getDump(); 8611 } 8612 else { 8613 printMsg("WARNING", "Probably c++0x construction detected"); 8614 } 8615 8616 } 8617 elsif($MinGWMode{$Version}==1) 8618 { # disable MinGW mode and try again 8619 $MinGWMode{$Version}=-1; 8620 resetLogging($Version); 8621 $TMP_DIR = tempdir(CLEANUP=>1); 8622 return getDump(); 8623 } 8624 writeLog($Version, $Errors); 8625 } 8626 else { 8627 writeLog($Version, "$!: $?\n"); 8628 } 8629 printMsg("ERROR", "some errors occurred when compiling headers"); 8630 printErrorLog($Version); 8631 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"}; 8632 writeLog($Version, "\n"); # new line 8633 } 8634 chdir($ORIG_DIR); 8635 unlink($TmpHeaderPath); 8636 unlink($HeaderPath); 8637 8638 if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) { 8639 return $TUs[0]; 8640 } 8641 else 8642 { 8643 my $Msg = "can't compile header(s)"; 8644 if($Errors=~/error trying to exec \W+cc1plus\W+/) { 8645 $Msg .= "\nDid you install G++?"; 8646 } 8647 exitStatus("Cannot_Compile", $Msg); 8648 } 8649} 8650 8651sub cmd_file($) 8652{ 8653 my $Path = $_[0]; 8654 return "" if(not $Path or not -e $Path); 8655 if(my $CmdPath = get_CmdPath("file")) { 8656 return `$CmdPath -b \"$Path\"`; 8657 } 8658 return ""; 8659} 8660 8661sub getIncString($$) 8662{ 8663 my ($ArrRef, $Style) = @_; 8664 return "" if(not $ArrRef or $#{$ArrRef}<0); 8665 my $String = ""; 8666 foreach (@{$ArrRef}) { 8667 $String .= " ".inc_opt($_, $Style); 8668 } 8669 return $String; 8670} 8671 8672sub getIncPaths(@) 8673{ 8674 my @HeaderPaths = @_; 8675 my @IncPaths = @{$Add_Include_Paths{$Version}}; 8676 if($INC_PATH_AUTODETECT{$Version}) 8677 { # auto-detecting dependencies 8678 my %Includes = (); 8679 foreach my $HPath (@HeaderPaths) 8680 { 8681 foreach my $Dir (get_HeaderDeps($HPath, $Version)) 8682 { 8683 if($Skip_Include_Paths{$Version}{$Dir}) { 8684 next; 8685 } 8686 if($SystemRoot) 8687 { 8688 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) { 8689 next; 8690 } 8691 } 8692 $Includes{$Dir} = 1; 8693 } 8694 } 8695 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) { 8696 push_U(\@IncPaths, $Dir); 8697 } 8698 } 8699 else 8700 { # user-defined paths 8701 @IncPaths = @{$Include_Paths{$Version}}; 8702 } 8703 return \@IncPaths; 8704} 8705 8706sub push_U($@) 8707{ # push unique 8708 if(my $Array = shift @_) 8709 { 8710 if(@_) 8711 { 8712 my %Exist = map {$_=>1} @{$Array}; 8713 foreach my $Elem (@_) 8714 { 8715 if(not defined $Exist{$Elem}) 8716 { 8717 push(@{$Array}, $Elem); 8718 $Exist{$Elem} = 1; 8719 } 8720 } 8721 } 8722 } 8723} 8724 8725sub callPreprocessor($$$) 8726{ 8727 my ($Path, $Inc, $LibVersion) = @_; 8728 return "" if(not $Path or not -f $Path); 8729 my $IncludeString=$Inc; 8730 if(not $Inc) { 8731 $IncludeString = getIncString(getIncPaths($Path), "GCC"); 8732 } 8733 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString); 8734 my $Out = $TMP_DIR."/preprocessed.h"; 8735 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\""); 8736 return $Out; 8737} 8738 8739sub cmd_find($;$$$$) 8740{ # native "find" is much faster than File::Find (~6x) 8741 # also the File::Find doesn't support --maxdepth N option 8742 # so using the cross-platform wrapper for the native one 8743 my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_; 8744 return () if(not $Path or not -e $Path); 8745 if($OSgroup eq "windows") 8746 { 8747 my $DirCmd = get_CmdPath("dir"); 8748 if(not $DirCmd) { 8749 exitStatus("Not_Found", "can't find \"dir\" command"); 8750 } 8751 $Path = get_abs_path($Path); 8752 $Path = path_format($Path, $OSgroup); 8753 my $Cmd = $DirCmd." \"$Path\" /B /O"; 8754 if($MaxDepth!=1) { 8755 $Cmd .= " /S"; 8756 } 8757 if($Type eq "d") { 8758 $Cmd .= " /AD"; 8759 } 8760 elsif($Type eq "f") { 8761 $Cmd .= " /A-D"; 8762 } 8763 my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`); 8764 if($Name) 8765 { 8766 if(not $UseRegex) 8767 { # FIXME: how to search file names in MS shell? 8768 # wildcard to regexp 8769 $Name=~s/\*/.*/g; 8770 $Name='\A'.$Name.'\Z'; 8771 } 8772 @Files = grep { /$Name/i } @Files; 8773 } 8774 my @AbsPaths = (); 8775 foreach my $File (@Files) 8776 { 8777 if(not is_abs($File)) { 8778 $File = join_P($Path, $File); 8779 } 8780 if($Type eq "f" and not -f $File) 8781 { # skip dirs 8782 next; 8783 } 8784 push(@AbsPaths, path_format($File, $OSgroup)); 8785 } 8786 if($Type eq "d") { 8787 push(@AbsPaths, $Path); 8788 } 8789 return @AbsPaths; 8790 } 8791 else 8792 { 8793 my $FindCmd = get_CmdPath("find"); 8794 if(not $FindCmd) { 8795 exitStatus("Not_Found", "can't find a \"find\" command"); 8796 } 8797 $Path = get_abs_path($Path); 8798 if(-d $Path and -l $Path 8799 and $Path!~/\/\Z/) 8800 { # for directories that are symlinks 8801 $Path.="/"; 8802 } 8803 my $Cmd = $FindCmd." \"$Path\""; 8804 if($MaxDepth) { 8805 $Cmd .= " -maxdepth $MaxDepth"; 8806 } 8807 if($Type) { 8808 $Cmd .= " -type $Type"; 8809 } 8810 if($Name and not $UseRegex) 8811 { # wildcards 8812 $Cmd .= " -name \"$Name\""; 8813 } 8814 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`; 8815 if($? and $!) { 8816 printMsg("ERROR", "problem with \'find\' utility ($?): $!"); 8817 } 8818 my @Files = split(/\n/, $Res); 8819 if($Name and $UseRegex) 8820 { # regex 8821 @Files = grep { /$Name/ } @Files; 8822 } 8823 return @Files; 8824 } 8825} 8826 8827sub unpackDump($) 8828{ 8829 my $Path = $_[0]; 8830 return "" if(not $Path or not -e $Path); 8831 $Path = get_abs_path($Path); 8832 $Path = path_format($Path, $OSgroup); 8833 my ($Dir, $FileName) = separate_path($Path); 8834 my $UnpackDir = $TMP_DIR."/unpack"; 8835 rmtree($UnpackDir); 8836 mkpath($UnpackDir); 8837 if($FileName=~s/\Q.zip\E\Z//g) 8838 { # *.zip 8839 my $UnzipCmd = get_CmdPath("unzip"); 8840 if(not $UnzipCmd) { 8841 exitStatus("Not_Found", "can't find \"unzip\" command"); 8842 } 8843 chdir($UnpackDir); 8844 system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\""); 8845 if($?) { 8846 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8847 } 8848 chdir($ORIG_DIR); 8849 my @Contents = cmd_find($UnpackDir, "f"); 8850 if(not @Contents) { 8851 exitStatus("Error", "can't extract \'$Path\'"); 8852 } 8853 return $Contents[0]; 8854 } 8855 elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g) 8856 { # *.tar.gz 8857 # *.tar.gz.amd64 (dh & cdbs) 8858 if($OSgroup eq "windows") 8859 { # -xvzf option is not implemented in tar.exe (2003) 8860 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead 8861 my $TarCmd = get_CmdPath("tar"); 8862 if(not $TarCmd) { 8863 exitStatus("Not_Found", "can't find \"tar\" command"); 8864 } 8865 my $GzipCmd = get_CmdPath("gzip"); 8866 if(not $GzipCmd) { 8867 exitStatus("Not_Found", "can't find \"gzip\" command"); 8868 } 8869 chdir($UnpackDir); 8870 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k) 8871 if($?) { 8872 exitStatus("Error", "can't extract \'$Path\'"); 8873 } 8874 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\""); 8875 if($?) { 8876 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8877 } 8878 chdir($ORIG_DIR); 8879 unlink($Dir."/".$FileName.".tar"); 8880 my @Contents = cmd_find($UnpackDir, "f"); 8881 if(not @Contents) { 8882 exitStatus("Error", "can't extract \'$Path\'"); 8883 } 8884 return $Contents[0]; 8885 } 8886 else 8887 { # Unix, Mac 8888 my $TarCmd = get_CmdPath("tar"); 8889 if(not $TarCmd) { 8890 exitStatus("Not_Found", "can't find \"tar\" command"); 8891 } 8892 chdir($UnpackDir); 8893 system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\""); 8894 if($?) { 8895 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8896 } 8897 chdir($ORIG_DIR); 8898 my @Contents = cmd_find($UnpackDir, "f"); 8899 if(not @Contents) { 8900 exitStatus("Error", "can't extract \'$Path\'"); 8901 } 8902 return $Contents[0]; 8903 } 8904 } 8905} 8906 8907sub createArchive($$) 8908{ 8909 my ($Path, $To) = @_; 8910 if(not $To) { 8911 $To = "."; 8912 } 8913 if(not $Path or not -e $Path 8914 or not -d $To) { 8915 return ""; 8916 } 8917 my ($From, $Name) = separate_path($Path); 8918 if($OSgroup eq "windows") 8919 { # *.zip 8920 my $ZipCmd = get_CmdPath("zip"); 8921 if(not $ZipCmd) { 8922 exitStatus("Not_Found", "can't find \"zip\""); 8923 } 8924 my $Pkg = $To."/".$Name.".zip"; 8925 unlink($Pkg); 8926 chdir($To); 8927 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\""); 8928 if($?) 8929 { # cannot allocate memory (or other problems with "zip") 8930 unlink($Path); 8931 exitStatus("Error", "can't pack the ABI dump: ".$!); 8932 } 8933 chdir($ORIG_DIR); 8934 unlink($Path); 8935 return $Pkg; 8936 } 8937 else 8938 { # *.tar.gz 8939 my $TarCmd = get_CmdPath("tar"); 8940 if(not $TarCmd) { 8941 exitStatus("Not_Found", "can't find \"tar\""); 8942 } 8943 my $GzipCmd = get_CmdPath("gzip"); 8944 if(not $GzipCmd) { 8945 exitStatus("Not_Found", "can't find \"gzip\""); 8946 } 8947 my $Pkg = abs_path($To)."/".$Name.".tar.gz"; 8948 unlink($Pkg); 8949 chdir($From); 8950 system($TarCmd, "-czf", $Pkg, $Name); 8951 if($?) 8952 { # cannot allocate memory (or other problems with "tar") 8953 unlink($Path); 8954 exitStatus("Error", "can't pack the ABI dump: ".$!); 8955 } 8956 chdir($ORIG_DIR); 8957 unlink($Path); 8958 return $To."/".$Name.".tar.gz"; 8959 } 8960} 8961 8962sub is_header_file($) 8963{ 8964 if($_[0]=~/\.($HEADER_EXT)\Z/i) { 8965 return $_[0]; 8966 } 8967 return 0; 8968} 8969 8970sub is_not_header($) 8971{ 8972 if($_[0]=~/\.\w+\Z/ 8973 and $_[0]!~/\.($HEADER_EXT)\Z/i) { 8974 return 1; 8975 } 8976 return 0; 8977} 8978 8979sub is_header($$$) 8980{ 8981 my ($Header, $UserDefined, $LibVersion) = @_; 8982 return 0 if(-d $Header); 8983 if(-f $Header) { 8984 $Header = get_abs_path($Header); 8985 } 8986 else 8987 { 8988 if(is_abs($Header)) 8989 { # incorrect absolute path 8990 return 0; 8991 } 8992 if(my $HPath = identifyHeader($Header, $LibVersion)) { 8993 $Header = $HPath; 8994 } 8995 else 8996 { # can't find header 8997 return 0; 8998 } 8999 } 9000 if($Header=~/\.\w+\Z/) 9001 { # have an extension 9002 return is_header_file($Header); 9003 } 9004 else 9005 { 9006 if($UserDefined==2) 9007 { # specified on the command line 9008 if(cmd_file($Header)!~/HTML|XML/i) { 9009 return $Header; 9010 } 9011 } 9012 elsif($UserDefined) 9013 { # specified in the XML-descriptor 9014 # header file without an extension 9015 return $Header; 9016 } 9017 else 9018 { 9019 if(index($Header, "/include/")!=-1 9020 or cmd_file($Header)=~/C[\+]*\s+program/i) 9021 { # !~/HTML|XML|shared|dynamic/i 9022 return $Header; 9023 } 9024 } 9025 } 9026 return 0; 9027} 9028 9029sub addTargetHeaders($) 9030{ 9031 my $LibVersion = $_[0]; 9032 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}})) 9033 { 9034 my $RegDir = get_dirname($RegHeader); 9035 $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1; 9036 9037 if(not $INC_PATH_AUTODETECT{$LibVersion}) { 9038 detect_recursive_includes($RegHeader, $LibVersion); 9039 } 9040 9041 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}})) 9042 { 9043 my $Dir = get_dirname($RecInc); 9044 9045 if(familiarDirs($RegDir, $Dir) 9046 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1) 9047 { # in the same directory or included by #include "..." 9048 $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1; 9049 } 9050 } 9051 } 9052} 9053 9054sub familiarDirs($$) 9055{ 9056 my ($D1, $D2) = @_; 9057 if($D1 eq $D2) { 9058 return 1; 9059 } 9060 9061 my $U1 = index($D1, "/usr/"); 9062 my $U2 = index($D2, "/usr/"); 9063 9064 if($U1==0 and $U2!=0) { 9065 return 0; 9066 } 9067 9068 if($U2==0 and $U1!=0) { 9069 return 0; 9070 } 9071 9072 if(index($D2, $D1."/")==0) { 9073 return 1; 9074 } 9075 9076 # /usr/include/DIR 9077 # /home/user/DIR 9078 9079 my $DL = get_depth($D1); 9080 9081 my @Dirs1 = ($D1); 9082 while($DL - get_depth($D1)<=2 9083 and get_depth($D1)>=4 9084 and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { 9085 push(@Dirs1, $D1); 9086 } 9087 9088 my @Dirs2 = ($D2); 9089 while(get_depth($D2)>=4 9090 and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { 9091 push(@Dirs2, $D2); 9092 } 9093 9094 foreach my $P1 (@Dirs1) 9095 { 9096 foreach my $P2 (@Dirs2) 9097 { 9098 9099 if($P1 eq $P2) { 9100 return 1; 9101 } 9102 } 9103 } 9104 return 0; 9105} 9106 9107sub readHeaders($) 9108{ 9109 $Version = $_[0]; 9110 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ..."); 9111 my $DumpPath = getDump(); 9112 if($Debug) 9113 { # debug mode 9114 mkpath($DEBUG_PATH{$Version}); 9115 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt"); 9116 } 9117 getInfo($DumpPath); 9118} 9119 9120sub prepareTypes($) 9121{ 9122 my $LibVersion = $_[0]; 9123 if(not checkDump($LibVersion, "2.0")) 9124 { # support for old ABI dumps 9125 # type names have been corrected in ACC 1.22 (dump 2.0 format) 9126 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9127 { 9128 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9129 if($TName=~/\A(\w+)::(\w+)/) { 9130 my ($P1, $P2) = ($1, $2); 9131 if($P1 eq $P2) { 9132 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/; 9133 } 9134 else { 9135 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/; 9136 } 9137 } 9138 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName; 9139 } 9140 } 9141 if(not checkDump($LibVersion, "2.5")) 9142 { # support for old ABI dumps 9143 # V < 2.5: array size == "number of elements" 9144 # V >= 2.5: array size in bytes 9145 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9146 { 9147 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9148 if($Type{"Type"} eq "Array") 9149 { 9150 if(my $Size = $Type{"Size"}) 9151 { # array[N] 9152 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion}); 9153 $Size *= $Base{"Size"}; 9154 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size"; 9155 } 9156 else 9157 { # array[] is a pointer 9158 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion}; 9159 } 9160 } 9161 } 9162 } 9163 my $V2 = ($LibVersion==1)?2:1; 9164 if(not checkDump($LibVersion, "2.7")) 9165 { # support for old ABI dumps 9166 # size of "method ptr" corrected in 2.7 9167 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9168 { 9169 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9170 if($PureType{"Type"} eq "MethodPtr") 9171 { 9172 my %Type = get_Type($TypeId, $LibVersion); 9173 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2); 9174 my %Type2 = get_Type($TypeId_2, $V2); 9175 if($Type{"Size"} ne $Type2{"Size"}) { 9176 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"}; 9177 } 9178 } 9179 } 9180 } 9181} 9182 9183sub prepareSymbols($) 9184{ 9185 my $LibVersion = $_[0]; 9186 9187 if(not keys(%{$SymbolInfo{$LibVersion}})) 9188 { # check if input is valid 9189 if(not $ExtendedCheck and not $CheckObjectsOnly) 9190 { 9191 if($CheckHeadersOnly) { 9192 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")"); 9193 } 9194 else { 9195 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")"); 9196 } 9197 } 9198 } 9199 9200 my $Remangle = 0; 9201 if(not checkDump(1, "2.10") 9202 or not checkDump(2, "2.10")) 9203 { # different formats 9204 $Remangle = 1; 9205 } 9206 if($CheckHeadersOnly) 9207 { # different languages 9208 if($UserLang) 9209 { # --lang=LANG for both versions 9210 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"}) 9211 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"})) 9212 { 9213 if($UserLang eq "C++") 9214 { # remangle symbols 9215 $Remangle = 1; 9216 } 9217 elsif($UserLang eq "C") 9218 { # remove mangling 9219 $Remangle = -1; 9220 } 9221 } 9222 } 9223 } 9224 9225 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}})) 9226 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2 9227 if(not checkDump($LibVersion, "2.13")) 9228 { # support for old ABI dumps 9229 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 9230 { 9231 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) 9232 { 9233 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"}; 9234 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"}; 9235 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9236 if(defined $DVal and $DVal ne "") 9237 { 9238 if($TName eq "char") { 9239 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal); 9240 } 9241 elsif($TName eq "bool") { 9242 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false"; 9243 } 9244 } 9245 } 9246 } 9247 } 9248 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 9249 { 9250 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 9251 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}) 9252 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 9253 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg) 9254 # + support for old ABI dumps 9255 next; 9256 } 9257 } 9258 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9259 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9260 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}; 9261 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 9262 9263 my $SRemangle = 0; 9264 if(not checkDump(1, "2.12") 9265 or not checkDump(2, "2.12")) 9266 { # support for old ABI dumps 9267 if($ShortName eq "operator>>") 9268 { 9269 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9270 { # corrected mangling of operator>> 9271 $SRemangle = 1; 9272 } 9273 } 9274 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9275 { 9276 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 9277 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/) 9278 { # corrected mangling of const global data 9279 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8) 9280 # and incorrectly mangled by old ACC versions 9281 $SRemangle = 1; 9282 } 9283 } 9284 } 9285 if(not $CheckHeadersOnly) 9286 { # support for old ABI dumps 9287 if(not checkDump(1, "2.17") 9288 or not checkDump(2, "2.17")) 9289 { 9290 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9291 { 9292 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9293 { 9294 if(link_symbol($ShortName, $LibVersion, "-Deps")) 9295 { 9296 $MnglName = $ShortName; 9297 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9298 } 9299 } 9300 } 9301 } 9302 } 9303 if($Remangle==1 or $SRemangle==1) 9304 { # support for old ABI dumps: some symbols are not mangled in old dumps 9305 # mangle both sets of symbols (old and new) 9306 # NOTE: remangling all symbols by the same mangler 9307 if($MnglName=~/\A_ZN(V|)K/) 9308 { # mangling may be incorrect on old ABI dumps 9309 # because of absent "Const" attribute 9310 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1; 9311 } 9312 if($MnglName=~/\A_ZN(K|)V/) 9313 { # mangling may be incorrect on old ABI dumps 9314 # because of absent "Volatile" attribute 9315 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1; 9316 } 9317 if(($ClassID and $MnglName!~/\A(_Z|\?)/) 9318 or (not $ClassID and $CheckHeadersOnly) 9319 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps"))) 9320 { # support for old ABI dumps, GCC >= 4.0 9321 # remangling all manually mangled symbols 9322 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC")) 9323 { 9324 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9325 $MangledNames{$LibVersion}{$MnglName} = 1; 9326 } 9327 } 9328 } 9329 elsif($Remangle==-1) 9330 { # remove mangling 9331 $MnglName = ""; 9332 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = ""; 9333 } 9334 if(not $MnglName) { 9335 next; 9336 } 9337 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"}) 9338 { # NOTE: global data may enter here twice 9339 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9340 9341 } 9342 if(not checkDump($LibVersion, "2.6")) 9343 { # support for old dumps 9344 # add "Volatile" attribute 9345 if($MnglName=~/_Z(K|)V/) { 9346 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1; 9347 } 9348 } 9349 # symbol and its symlink have same signatures 9350 if($SymVer{$LibVersion}{$MnglName}) { 9351 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9352 } 9353 9354 if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"}) 9355 { 9356 %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9357 if($SymVer{$LibVersion}{$Alias}) { 9358 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9359 } 9360 } 9361 9362 # clean memory 9363 delete($SymbolInfo{$LibVersion}{$InfoId}); 9364 } 9365 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") { 9366 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion); 9367 } 9368 if($ExtendedCheck) 9369 { # --ext option 9370 addExtension($LibVersion); 9371 } 9372 9373 # clean memory 9374 delete($SymbolInfo{$LibVersion}); 9375 9376 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 9377 { # detect allocable classes with public exported constructors 9378 # or classes with auto-generated or inline-only constructors 9379 # and other temp info 9380 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 9381 { 9382 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 9383 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"} 9384 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}) 9385 { # Class() { ... } will not be exported 9386 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9387 { 9388 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) { 9389 $AllocableClass{$LibVersion}{$ClassName} = 1; 9390 } 9391 } 9392 } 9393 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9394 { # all imported class methods 9395 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary")) 9396 { 9397 if($CheckHeadersOnly) 9398 { 9399 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 9400 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 9401 { # all symbols except non-virtual inline 9402 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9403 } 9404 } 9405 else { 9406 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9407 } 9408 } 9409 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) { 9410 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9411 } 9412 } 9413 $ClassNames{$LibVersion}{$ClassName} = 1; 9414 } 9415 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 9416 { 9417 my %Base = get_BaseType($RetId, $LibVersion); 9418 if(defined $Base{"Type"} 9419 and $Base{"Type"}=~/Struct|Class/) 9420 { 9421 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"}; 9422 if($Name=~/<([^<>\s]+)>/) 9423 { 9424 if(my $Tid = getTypeIdByName($1, $LibVersion)) { 9425 $ReturnedClass{$LibVersion}{$Tid} = 1; 9426 } 9427 } 9428 else { 9429 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1; 9430 } 9431 } 9432 } 9433 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 9434 { 9435 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"}; 9436 if(get_PLevel($PId, $LibVersion)>=1) 9437 { 9438 if(my %Base = get_BaseType($PId, $LibVersion)) 9439 { 9440 if($Base{"Type"}=~/Struct|Class/) 9441 { 9442 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1; 9443 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1)) 9444 { # mark all derived classes 9445 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1; 9446 } 9447 } 9448 } 9449 } 9450 } 9451 9452 # mapping {short name => symbols} 9453 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1; 9454 } 9455 foreach my $MnglName (keys(%VTableClass)) 9456 { # reconstruct attributes of v-tables 9457 if(index($MnglName, "_ZTV")==0) 9458 { 9459 if(my $ClassName = $VTableClass{$MnglName}) 9460 { 9461 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 9462 { 9463 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"}; 9464 $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId; 9465 } 9466 } 9467 } 9468 } 9469 9470 # types 9471 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9472 { 9473 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}) 9474 { 9475 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) { 9476 $ClassNames{$LibVersion}{$TName} = 1; 9477 } 9478 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"}) 9479 { 9480 $ClassNames{$LibVersion}{$TName} = 1; 9481 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}})) 9482 { 9483 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) { 9484 $ClassNames{$LibVersion}{$BName} = 1; 9485 } 9486 } 9487 } 9488 } 9489 } 9490} 9491 9492sub getFirst($$) 9493{ 9494 my ($Tid, $LibVersion) = @_; 9495 if(not $Tid) { 9496 return $Tid; 9497 } 9498 9499 if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9500 { 9501 if($TName_Tid{$LibVersion}{$Name}) { 9502 return $TName_Tid{$LibVersion}{$Name}; 9503 } 9504 } 9505 9506 return $Tid; 9507} 9508 9509sub register_SymbolUsage($$$) 9510{ 9511 my ($InfoId, $UsedType, $LibVersion) = @_; 9512 9513 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9514 if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion)) 9515 { 9516 register_TypeUsage($RTid, $UsedType, $LibVersion); 9517 $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid; 9518 } 9519 if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion)) 9520 { 9521 register_TypeUsage($FCid, $UsedType, $LibVersion); 9522 $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid; 9523 9524 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) 9525 { # register "this" pointer 9526 register_TypeUsage($ThisId, $UsedType, $LibVersion); 9527 } 9528 if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion)) 9529 { # register "this" pointer (const method) 9530 register_TypeUsage($ThisId_C, $UsedType, $LibVersion); 9531 } 9532 } 9533 foreach my $PPos (keys(%{$FuncInfo{"Param"}})) 9534 { 9535 if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion)) 9536 { 9537 register_TypeUsage($PTid, $UsedType, $LibVersion); 9538 $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; 9539 } 9540 } 9541 foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) 9542 { 9543 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; 9544 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9545 register_TypeUsage($TTid, $UsedType, $LibVersion); 9546 } 9547 } 9548} 9549 9550sub register_TypeUsage($$$) 9551{ 9552 my ($TypeId, $UsedType, $LibVersion) = @_; 9553 if(not $TypeId) { 9554 return; 9555 } 9556 if($UsedType->{$TypeId}) 9557 { # already registered 9558 return; 9559 } 9560 9561 my %TInfo = get_Type($TypeId, $LibVersion); 9562 if($TInfo{"Type"}) 9563 { 9564 if(my $NS = $TInfo{"NameSpace"}) 9565 { 9566 if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) { 9567 register_TypeUsage($NSTid, $UsedType, $LibVersion); 9568 } 9569 } 9570 9571 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) 9572 { 9573 $UsedType->{$TypeId} = 1; 9574 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) 9575 { 9576 foreach my $BaseId (keys(%{$TInfo{"Base"}})) { 9577 register_TypeUsage($BaseId, $UsedType, $LibVersion); 9578 } 9579 foreach my $TPos (keys(%{$TInfo{"TParam"}})) 9580 { 9581 my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; 9582 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9583 register_TypeUsage($TTid, $UsedType, $LibVersion); 9584 } 9585 } 9586 } 9587 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}})) 9588 { 9589 if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion)) 9590 { 9591 register_TypeUsage($MTid, $UsedType, $LibVersion); 9592 $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; 9593 } 9594 } 9595 if($TInfo{"Type"} eq "FuncPtr" 9596 or $TInfo{"Type"} eq "MethodPtr" 9597 or $TInfo{"Type"} eq "Func") 9598 { 9599 if(my $RTid = $TInfo{"Return"}) { 9600 register_TypeUsage($RTid, $UsedType, $LibVersion); 9601 } 9602 foreach my $PPos (keys(%{$TInfo{"Param"}})) 9603 { 9604 if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { 9605 register_TypeUsage($PTid, $UsedType, $LibVersion); 9606 } 9607 } 9608 } 9609 if($TInfo{"Type"} eq "FieldPtr") 9610 { 9611 if(my $RTid = $TInfo{"Return"}) { 9612 register_TypeUsage($RTid, $UsedType, $LibVersion); 9613 } 9614 if(my $CTid = $TInfo{"Class"}) { 9615 register_TypeUsage($CTid, $UsedType, $LibVersion); 9616 } 9617 } 9618 if($TInfo{"Type"} eq "MethodPtr") 9619 { 9620 if(my $CTid = $TInfo{"Class"}) { 9621 register_TypeUsage($CTid, $UsedType, $LibVersion); 9622 } 9623 } 9624 } 9625 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) 9626 { 9627 $UsedType->{$TypeId} = 1; 9628 if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion)) 9629 { 9630 register_TypeUsage($BTid, $UsedType, $LibVersion); 9631 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid; 9632 } 9633 } 9634 else 9635 { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. 9636 $UsedType->{$TypeId} = 1; 9637 } 9638 } 9639} 9640 9641sub selectSymbol($$$$) 9642{ # select symbol to check or to dump 9643 my ($Symbol, $SInfo, $Level, $LibVersion) = @_; 9644 9645 if($Level eq "Dump") 9646 { 9647 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"}) 9648 { # TODO: check if this symbol is from 9649 # base classes of other target symbols 9650 return 1; 9651 } 9652 } 9653 9654 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/) 9655 { # stdc++ interfaces 9656 return 0; 9657 } 9658 9659 my $Target = 0; 9660 if(my $Header = $SInfo->{"Header"}) { 9661 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2)); 9662 } 9663 if($ExtendedCheck) 9664 { 9665 if(index($Symbol, "external_func_")==0) { 9666 $Target = 1; 9667 } 9668 } 9669 if($CheckHeadersOnly or $Level eq "Source") 9670 { 9671 if($Target) 9672 { 9673 if($Level eq "Dump") 9674 { # dumped 9675 if($BinaryOnly) 9676 { 9677 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) { 9678 return 1; 9679 } 9680 } 9681 else { 9682 return 1; 9683 } 9684 } 9685 elsif($Level eq "Source") 9686 { # checked 9687 return 1; 9688 } 9689 elsif($Level eq "Binary") 9690 { # checked 9691 if(not $SInfo->{"InLine"} or $SInfo->{"Data"} 9692 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) { 9693 return 1; 9694 } 9695 } 9696 } 9697 } 9698 else 9699 { # library is available 9700 if(link_symbol($Symbol, $LibVersion, "-Deps")) 9701 { # exported symbols 9702 return 1; 9703 } 9704 if($Level eq "Dump") 9705 { # dumped 9706 if($BinaryOnly) 9707 { 9708 if($SInfo->{"Data"}) 9709 { 9710 if($Target) { 9711 return 1; 9712 } 9713 } 9714 } 9715 else 9716 { # SrcBin 9717 if($Target) { 9718 return 1; 9719 } 9720 } 9721 } 9722 elsif($Level eq "Source") 9723 { # checked 9724 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"} 9725 or isInLineInst($Symbol, $SInfo, $LibVersion)) 9726 { # skip LOCAL symbols 9727 if($Target) { 9728 return 1; 9729 } 9730 } 9731 } 9732 elsif($Level eq "Binary") 9733 { # checked 9734 if($SInfo->{"PureVirt"} or $SInfo->{"Data"}) 9735 { 9736 if($Target) { 9737 return 1; 9738 } 9739 } 9740 } 9741 } 9742 return 0; 9743} 9744 9745sub cleanDump($) 9746{ # clean data 9747 my $LibVersion = $_[0]; 9748 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 9749 { 9750 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}})) 9751 { 9752 delete($SymbolInfo{$LibVersion}{$InfoId}); 9753 next; 9754 } 9755 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9756 if(not $MnglName) 9757 { 9758 delete($SymbolInfo{$LibVersion}{$InfoId}); 9759 next; 9760 } 9761 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9762 if(not $ShortName) 9763 { 9764 delete($SymbolInfo{$LibVersion}{$InfoId}); 9765 next; 9766 } 9767 if($MnglName eq $ShortName) 9768 { # remove duplicate data 9769 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}); 9770 } 9771 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) { 9772 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"}); 9773 } 9774 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { 9775 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"}); 9776 } 9777 delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"}); 9778 } 9779 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 9780 { 9781 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}})) 9782 { 9783 delete($TypeInfo{$LibVersion}{$Tid}); 9784 next; 9785 } 9786 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"}); 9787 foreach my $Attr ("Header", "Line", "Size", "NameSpace") 9788 { 9789 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) { 9790 delete($TypeInfo{$LibVersion}{$Tid}{$Attr}); 9791 } 9792 } 9793 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) { 9794 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"}); 9795 } 9796 } 9797} 9798 9799sub selectType($$) 9800{ 9801 my ($Tid, $LibVersion) = @_; 9802 9803 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid}) 9804 { 9805 if(defined $TypeInfo{$LibVersion}{$Dupl}) 9806 { 9807 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9808 { # duplicate 9809 return 0; 9810 } 9811 } 9812 } 9813 9814 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}) 9815 { 9816 if(not isBuiltIn($THeader)) 9817 { 9818 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/) 9819 { 9820 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"})) 9821 { 9822 if(is_target_header($THeader, $LibVersion)) 9823 { # from target headers 9824 if(not selfTypedef($Tid, $LibVersion)) { 9825 return 1; 9826 } 9827 } 9828 } 9829 } 9830 } 9831 } 9832 return 0; 9833} 9834 9835sub remove_Unused($$) 9836{ # remove unused data types from the ABI dump 9837 my ($LibVersion, $Kind) = @_; 9838 9839 my %UsedType = (); 9840 9841 foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}})) 9842 { 9843 register_SymbolUsage($InfoId, \%UsedType, $LibVersion); 9844 } 9845 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9846 { 9847 if($UsedType{$Tid}) 9848 { # All & Extended 9849 next; 9850 } 9851 9852 if($Kind eq "Extended") 9853 { 9854 if(selectType($Tid, $LibVersion)) 9855 { 9856 my %Tree = (); 9857 register_TypeUsage($Tid, \%Tree, $LibVersion); 9858 9859 my $Tmpl = 0; 9860 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9861 { 9862 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9863 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 9864 { 9865 $Tmpl = 1; 9866 last; 9867 } 9868 } 9869 if(not $Tmpl) 9870 { 9871 foreach (keys(%Tree)) { 9872 $UsedType{$_} = 1; 9873 } 9874 } 9875 } 9876 } 9877 } 9878 9879 my %Delete = (); 9880 9881 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9882 { # remove unused types 9883 if($UsedType{$Tid}) 9884 { # All & Extended 9885 next; 9886 } 9887 9888 if($Kind eq "Extra") 9889 { 9890 my %Tree = (); 9891 register_TypeUsage($Tid, \%Tree, $LibVersion); 9892 9893 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9894 { 9895 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9896 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 9897 { 9898 $Delete{$Tid} = 1; 9899 last; 9900 } 9901 } 9902 } 9903 else 9904 { 9905 # remove type 9906 delete($TypeInfo{$LibVersion}{$Tid}); 9907 } 9908 } 9909 9910 if($Kind eq "Extra") 9911 { # remove duplicates 9912 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9913 { 9914 if($UsedType{$Tid}) 9915 { # All & Extended 9916 next; 9917 } 9918 9919 my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 9920 9921 if($TName_Tid{$LibVersion}{$Name} ne $Tid) { 9922 delete($TypeInfo{$LibVersion}{$Tid}); 9923 } 9924 } 9925 } 9926 9927 foreach my $Tid (keys(%Delete)) 9928 { 9929 delete($TypeInfo{$LibVersion}{$Tid}); 9930 } 9931} 9932 9933sub check_Completeness($$) 9934{ 9935 my ($Info, $LibVersion) = @_; 9936 9937 # data types 9938 if(defined $Info->{"Memb"}) 9939 { 9940 foreach my $Pos (keys(%{$Info->{"Memb"}})) 9941 { 9942 if(defined $Info->{"Memb"}{$Pos}{"type"}) { 9943 check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion); 9944 } 9945 } 9946 } 9947 if(defined $Info->{"Base"}) 9948 { 9949 foreach my $Bid (keys(%{$Info->{"Base"}})) { 9950 check_TypeInfo($Bid, $LibVersion); 9951 } 9952 } 9953 if(defined $Info->{"BaseType"}) { 9954 check_TypeInfo($Info->{"BaseType"}, $LibVersion); 9955 } 9956 if(defined $Info->{"TParam"}) 9957 { 9958 foreach my $Pos (keys(%{$Info->{"TParam"}})) 9959 { 9960 my $TName = $Info->{"TParam"}{$Pos}{"name"}; 9961 if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) { 9962 next; 9963 } 9964 if($TName eq "_BoolType") { 9965 next; 9966 } 9967 if($TName=~/\Asizeof\(/) { 9968 next; 9969 } 9970 if(my $Tid = $TName_Tid{$LibVersion}{$TName}) { 9971 check_TypeInfo($Tid, $LibVersion); 9972 } 9973 else 9974 { 9975 if(defined $Debug) { 9976 printMsg("WARNING", "missed type $TName"); 9977 } 9978 } 9979 } 9980 } 9981 9982 # symbols 9983 if(defined $Info->{"Param"}) 9984 { 9985 foreach my $Pos (keys(%{$Info->{"Param"}})) 9986 { 9987 if(defined $Info->{"Param"}{$Pos}{"type"}) { 9988 check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion); 9989 } 9990 } 9991 } 9992 if(defined $Info->{"Return"}) { 9993 check_TypeInfo($Info->{"Return"}, $LibVersion); 9994 } 9995 if(defined $Info->{"Class"}) { 9996 check_TypeInfo($Info->{"Class"}, $LibVersion); 9997 } 9998} 9999 10000sub check_TypeInfo($$) 10001{ 10002 my ($Tid, $LibVersion) = @_; 10003 10004 if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) { 10005 return; 10006 } 10007 $CheckedTypeInfo{$LibVersion}{$Tid} = 1; 10008 10009 if(defined $TypeInfo{$LibVersion}{$Tid}) 10010 { 10011 if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) { 10012 printMsg("ERROR", "missed type name ($Tid)"); 10013 } 10014 check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion); 10015 } 10016 else { 10017 printMsg("ERROR", "missed type id $Tid"); 10018 } 10019} 10020 10021sub selfTypedef($$) 10022{ 10023 my ($TypeId, $LibVersion) = @_; 10024 my %Type = get_Type($TypeId, $LibVersion); 10025 if($Type{"Type"} eq "Typedef") 10026 { 10027 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion}); 10028 if($Base{"Type"}=~/Class|Struct/) 10029 { 10030 if($Type{"Name"} eq $Base{"Name"}) { 10031 return 1; 10032 } 10033 elsif($Type{"Name"}=~/::(\w+)\Z/) 10034 { 10035 if($Type{"Name"} eq $Base{"Name"}."::".$1) 10036 { # QPointer<QWidget>::QPointer 10037 return 1; 10038 } 10039 } 10040 } 10041 } 10042 return 0; 10043} 10044 10045sub addExtension($) 10046{ 10047 my $LibVersion = $_[0]; 10048 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 10049 { 10050 if(selectType($Tid, $LibVersion)) 10051 { 10052 my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 10053 $TName=~s/\A(struct|union|class|enum) //; 10054 my $Symbol = "external_func_".$TName; 10055 10056 %{$CompleteSignature{$LibVersion}{$Symbol}} = ( 10057 "Header" => "extended.h", 10058 "ShortName" => $Symbol, 10059 "MnglName" => $Symbol, 10060 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } } 10061 ); 10062 10063 $ExtendedSymbols{$Symbol} = 1; 10064 $CheckedSymbols{"Binary"}{$Symbol} = 1; 10065 $CheckedSymbols{"Source"}{$Symbol} = 1; 10066 } 10067 } 10068 $ExtendedSymbols{"external_func_0"} = 1; 10069 $CheckedSymbols{"Binary"}{"external_func_0"} = 1; 10070 $CheckedSymbols{"Source"}{"external_func_0"} = 1; 10071} 10072 10073sub findMethod($$$) 10074{ 10075 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10076 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}})) 10077 { 10078 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) { 10079 return $VirtMethodInClass; 10080 } 10081 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) { 10082 return $VirtMethodInBaseClasses; 10083 } 10084 } 10085 return ""; 10086} 10087 10088sub findMethod_Class($$$) 10089{ 10090 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10091 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 10092 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName}); 10093 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1); 10094 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"}; 10095 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10096 { # search for interface with the same parameters suffix (overridden) 10097 if($TargetSuffix eq get_symbol_suffix($Candidate, 1)) 10098 { 10099 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) 10100 { 10101 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) 10102 { 10103 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/) 10104 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/) 10105 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) { 10106 return $Candidate; 10107 } 10108 } 10109 } 10110 else 10111 { 10112 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) { 10113 return $Candidate; 10114 } 10115 } 10116 } 10117 } 10118 return ""; 10119} 10120 10121sub registerVTable($) 10122{ 10123 my $LibVersion = $_[0]; 10124 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 10125 { 10126 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"} 10127 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"}) 10128 { 10129 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"}; 10130 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/); 10131 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"} 10132 and $Symbol=~/D2E/) 10133 { # pure virtual D2-destructors are marked as "virt" in the dump 10134 # virtual D2-destructors are NOT marked as "virt" in the dump 10135 # both destructors are not presented in the v-table 10136 next; 10137 } 10138 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 10139 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1; 10140 } 10141 } 10142} 10143 10144sub registerOverriding($) 10145{ 10146 my $LibVersion = $_[0]; 10147 my @Classes = keys(%{$VirtualTable{$LibVersion}}); 10148 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes; 10149 foreach my $ClassName (@Classes) 10150 { 10151 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10152 { 10153 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"}) 10154 { # pure virtuals 10155 next; 10156 } 10157 my $ClassId = $TName_Tid{$LibVersion}{$ClassName}; 10158 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion)) 10159 { 10160 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"} 10161 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"}) 10162 { # both overridden virtual methods 10163 # and implemented pure virtual methods 10164 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden; 10165 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1; 10166 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model 10167 } 10168 } 10169 } 10170 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { 10171 delete($VirtualTable{$LibVersion}{$ClassName}); 10172 } 10173 } 10174} 10175 10176sub setVirtFuncPositions($) 10177{ 10178 my $LibVersion = $_[0]; 10179 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}})) 10180 { 10181 my ($Num, $Rel) = (1, 0); 10182 10183 if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10184 { 10185 if($UsedDump{$LibVersion}{"DWARF"}) { 10186 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs; 10187 } 10188 else { 10189 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs; 10190 } 10191 foreach my $VirtFunc (@Funcs) 10192 { 10193 if($UsedDump{$LibVersion}{"DWARF"}) { 10194 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"}; 10195 } 10196 else { 10197 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++; 10198 } 10199 10200 # set relative positions 10201 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc} 10202 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc}) 10203 { # relative position excluding added and removed virtual functions 10204 if(not $CompleteSignature{1}{$VirtFunc}{"Override"} 10205 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) { 10206 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++; 10207 } 10208 } 10209 } 10210 } 10211 } 10212 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}})) 10213 { 10214 my $AbsNum = 1; 10215 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) { 10216 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++; 10217 } 10218 } 10219} 10220 10221sub get_sub_classes($$$) 10222{ 10223 my ($ClassId, $LibVersion, $Recursive) = @_; 10224 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId}); 10225 my @Subs = (); 10226 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 10227 { 10228 if($Recursive) 10229 { 10230 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) { 10231 push(@Subs, $SubSubId); 10232 } 10233 } 10234 push(@Subs, $SubId); 10235 } 10236 return @Subs; 10237} 10238 10239sub get_base_classes($$$) 10240{ 10241 my ($ClassId, $LibVersion, $Recursive) = @_; 10242 my %ClassType = get_Type($ClassId, $LibVersion); 10243 return () if(not defined $ClassType{"Base"}); 10244 my @Bases = (); 10245 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})} 10246 keys(%{$ClassType{"Base"}})) 10247 { 10248 if($Recursive) 10249 { 10250 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) { 10251 push(@Bases, $SubBaseId); 10252 } 10253 } 10254 push(@Bases, $BaseId); 10255 } 10256 return @Bases; 10257} 10258 10259sub getVTable_Model($$) 10260{ # return an ordered list of v-table elements 10261 my ($ClassId, $LibVersion) = @_; 10262 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10263 my @Elements = (); 10264 foreach my $BaseId (@Bases, $ClassId) 10265 { 10266 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10267 { 10268 if(defined $VirtualTable{$LibVersion}{$BName}) 10269 { 10270 my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}}); 10271 if($UsedDump{$LibVersion}{"DWARF"}) { 10272 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs; 10273 } 10274 else { 10275 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs; 10276 } 10277 foreach my $VFunc (@VFuncs) { 10278 push(@Elements, $VFunc); 10279 } 10280 } 10281 } 10282 } 10283 return @Elements; 10284} 10285 10286sub getVShift($$) 10287{ 10288 my ($ClassId, $LibVersion) = @_; 10289 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10290 my $VShift = 0; 10291 foreach my $BaseId (@Bases) 10292 { 10293 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10294 { 10295 if(defined $VirtualTable{$LibVersion}{$BName}) { 10296 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}}); 10297 } 10298 } 10299 } 10300 return $VShift; 10301} 10302 10303sub getShift($$) 10304{ 10305 my ($ClassId, $LibVersion) = @_; 10306 my @Bases = get_base_classes($ClassId, $LibVersion, 0); 10307 my $Shift = 0; 10308 foreach my $BaseId (@Bases) 10309 { 10310 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"}) 10311 { 10312 if($Size!=1) 10313 { # not empty base class 10314 $Shift+=$Size; 10315 } 10316 } 10317 } 10318 return $Shift; 10319} 10320 10321sub getVTable_Size($$) 10322{ # number of v-table elements 10323 my ($ClassName, $LibVersion) = @_; 10324 my $Size = 0; 10325 # three approaches 10326 if(not $Size) 10327 { # real size 10328 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) { 10329 $Size = keys(%VTable); 10330 } 10331 } 10332 if(not $Size) 10333 { # shared library symbol size 10334 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) { 10335 $Size /= $WORD_SIZE{$LibVersion}; 10336 } 10337 } 10338 if(not $Size) 10339 { # model size 10340 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) { 10341 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2; 10342 } 10343 } 10344 return $Size; 10345} 10346 10347sub isCopyingClass($$) 10348{ 10349 my ($TypeId, $LibVersion) = @_; 10350 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"}; 10351} 10352 10353sub isLeafClass($$) 10354{ 10355 my ($ClassId, $LibVersion) = @_; 10356 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})); 10357} 10358 10359sub havePubFields($) 10360{ # check structured type for public fields 10361 return isAccessible($_[0], {}, 0, -1); 10362} 10363 10364sub isAccessible($$$$) 10365{ # check interval in structured type for public fields 10366 my ($TypePtr, $Skip, $Start, $End) = @_; 10367 return 0 if(not $TypePtr); 10368 if($End==-1) { 10369 $End = keys(%{$TypePtr->{"Memb"}})-1; 10370 } 10371 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}})) 10372 { 10373 if($Skip and $Skip->{$MemPos}) 10374 { # skip removed/added fields 10375 next; 10376 } 10377 if(int($MemPos)>=$Start and int($MemPos)<=$End) 10378 { 10379 if(isPublic($TypePtr, $MemPos)) { 10380 return ($MemPos+1); 10381 } 10382 } 10383 } 10384 return 0; 10385} 10386 10387sub isReserved($) 10388{ # reserved fields == private 10389 my $MName = $_[0]; 10390 if($MName=~/reserved|padding|f_spare/i) { 10391 return 1; 10392 } 10393 if($MName=~/\A[_]*(spare|pad|unused|dummy)[_\d]*\Z/i) { 10394 return 1; 10395 } 10396 if($MName=~/(pad\d+)/i) { 10397 return 1; 10398 } 10399 return 0; 10400} 10401 10402sub isPublic($$) 10403{ 10404 my ($TypePtr, $FieldPos) = @_; 10405 return 0 if(not $TypePtr); 10406 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}); 10407 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"}); 10408 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"}) 10409 { # by name in C language 10410 # FIXME: add other methods to detect private members 10411 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"}; 10412 if($MName=~/priv|abidata|parent_object/i) 10413 { # C-styled private data 10414 return 0; 10415 } 10416 if(lc($MName) eq "abi") 10417 { # ABI information/reserved field 10418 return 0; 10419 } 10420 if(isReserved($MName)) 10421 { # reserved fields 10422 return 0; 10423 } 10424 return 1; 10425 } 10426 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private") 10427 { # by access in C++ language 10428 return 1; 10429 } 10430 return 0; 10431} 10432 10433sub getVTable_Real($$) 10434{ 10435 my ($ClassName, $LibVersion) = @_; 10436 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 10437 { 10438 my %Type = get_Type($ClassId, $LibVersion); 10439 if(defined $Type{"VTable"}) { 10440 return %{$Type{"VTable"}}; 10441 } 10442 } 10443 return (); 10444} 10445 10446sub cmpVTables($) 10447{ 10448 my $ClassName = $_[0]; 10449 my $Res = cmpVTables_Real($ClassName, 1); 10450 if($Res==-1) { 10451 $Res = cmpVTables_Model($ClassName); 10452 } 10453 return $Res; 10454} 10455 10456sub cmpVTables_Model($) 10457{ 10458 my $ClassName = $_[0]; 10459 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}})) 10460 { 10461 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) { 10462 return 1; 10463 } 10464 } 10465 return 0; 10466} 10467 10468sub cmpVTables_Real($$) 10469{ 10470 my ($ClassName, $Strong) = @_; 10471 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) { 10472 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}; 10473 } 10474 my %VTable_Old = getVTable_Real($ClassName, 1); 10475 my %VTable_New = getVTable_Real($ClassName, 2); 10476 if(not %VTable_Old or not %VTable_New) 10477 { # old ABI dumps 10478 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1); 10479 } 10480 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New)); 10481 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes)) 10482 { 10483 if(not defined $VTable_Old{$Offset}) 10484 { # v-table v.1 < v-table v.2 10485 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong); 10486 } 10487 my $Entry1 = $VTable_Old{$Offset}; 10488 if(not defined $VTable_New{$Offset}) 10489 { # v-table v.1 > v-table v.2 10490 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/)); 10491 } 10492 my $Entry2 = $VTable_New{$Offset}; 10493 10494 $Entry1 = simpleVEntry($Entry1); 10495 $Entry2 = simpleVEntry($Entry2); 10496 if($Entry1 ne $Entry2) 10497 { # register as changed 10498 if($Entry1=~/::([^:]+)\Z/) 10499 { 10500 my $M1 = $1; 10501 if($Entry2=~/::([^:]+)\Z/) 10502 { 10503 my $M2 = $1; 10504 if($M1 eq $M2) 10505 { # overridden 10506 next; 10507 } 10508 } 10509 } 10510 if(differentDumps("G")) 10511 { 10512 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/) 10513 { 10514 # GCC 4.6.1: -0x00000000000000010 10515 # GCC 4.7.0: -16 10516 next; 10517 } 10518 } 10519 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1); 10520 } 10521 } 10522 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0); 10523} 10524 10525sub mergeVTables($) 10526{ # merging v-tables without diagnostics 10527 my $Level = $_[0]; 10528 foreach my $ClassName (keys(%{$VirtualTable{1}})) 10529 { 10530 if($VTableChanged_M{$ClassName}) 10531 { # already registered 10532 next; 10533 } 10534 if(cmpVTables_Real($ClassName, 0)==1) 10535 { 10536 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10537 foreach my $Symbol (@Affected) 10538 { 10539 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=( 10540 "Type_Name"=>$ClassName, 10541 "Target"=>$ClassName); 10542 } 10543 } 10544 } 10545} 10546 10547sub mergeBases($) 10548{ 10549 my $Level = $_[0]; 10550 foreach my $ClassName (keys(%{$ClassNames{1}})) 10551 { # detect added and removed virtual functions 10552 my $ClassId = $TName_Tid{1}{$ClassName}; 10553 next if(not $ClassId); 10554 if(defined $VirtualTable{2}{$ClassName}) 10555 { 10556 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}})) 10557 { 10558 if($TName_Tid{1}{$ClassName} 10559 and not defined $VirtualTable{1}{$ClassName}{$Symbol}) 10560 { # added to v-table 10561 if(defined $CompleteSignature{1}{$Symbol} 10562 and $CompleteSignature{1}{$Symbol}{"Virt"}) 10563 { # override some method in v.1 10564 next; 10565 } 10566 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10567 } 10568 } 10569 } 10570 if(defined $VirtualTable{1}{$ClassName}) 10571 { 10572 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}})) 10573 { 10574 if($TName_Tid{2}{$ClassName} 10575 and not defined $VirtualTable{2}{$ClassName}{$Symbol}) 10576 { # removed from v-table 10577 if(defined $CompleteSignature{2}{$Symbol} 10578 and $CompleteSignature{2}{$Symbol}{"Virt"}) 10579 { # override some method in v.2 10580 next; 10581 } 10582 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10583 } 10584 } 10585 } 10586 if($Level eq "Binary") 10587 { # Binary-level 10588 my %Class_Type = get_Type($ClassId, 1); 10589 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}})) 10590 { # check replacements, including pure virtual methods 10591 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc}; 10592 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}})) 10593 { 10594 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc}; 10595 if($AddedPos==$RemovedPos) 10596 { 10597 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc; 10598 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc; 10599 last; # other methods will be reported as "added" or "removed" 10600 } 10601 } 10602 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc}) 10603 { 10604 if(lc($AddedVFunc) eq lc($RemovedVFunc)) 10605 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0) 10606 next; 10607 } 10608 my $ProblemType = "Virtual_Replacement"; 10609 my @Affected = ($RemovedVFunc); 10610 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 10611 { # pure methods 10612 if(not isUsedClass($ClassId, 1, $Level)) 10613 { # not a parameter of some exported method 10614 next; 10615 } 10616 $ProblemType = "Pure_Virtual_Replacement"; 10617 10618 # affected all methods (both virtual and non-virtual ones) 10619 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10620 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}})); 10621 } 10622 $VTableChanged_M{$ClassName}=1; 10623 foreach my $AffectedInt (@Affected) 10624 { 10625 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"}) 10626 { # affected exported methods only 10627 next; 10628 } 10629 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) { 10630 next; 10631 } 10632 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 10633 "Type_Name"=>$Class_Type{"Name"}, 10634 "Target"=>get_Signature($AddedVFunc, 2), 10635 "Old_Value"=>get_Signature($RemovedVFunc, 1)); 10636 } 10637 } 10638 } 10639 } 10640 } 10641 if(not checkDump(1, "2.0") 10642 or not checkDump(2, "2.0")) 10643 { # support for old ABI dumps 10644 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format) 10645 return; 10646 } 10647 foreach my $ClassName (sort keys(%{$ClassNames{1}})) 10648 { 10649 my $ClassId_Old = $TName_Tid{1}{$ClassName}; 10650 next if(not $ClassId_Old); 10651 if(not isCreatable($ClassId_Old, 1)) 10652 { # skip classes without public constructors (including auto-generated) 10653 # example: class has only a private exported or private inline constructor 10654 next; 10655 } 10656 if($ClassName=~/>/) 10657 { # skip affected template instances 10658 next; 10659 } 10660 my %Class_Old = get_Type($ClassId_Old, 1); 10661 my $ClassId_New = $TName_Tid{2}{$ClassName}; 10662 if(not $ClassId_New) { 10663 next; 10664 } 10665 my %Class_New = get_Type($ClassId_New, 2); 10666 if($Class_New{"Type"}!~/Class|Struct/) 10667 { # became typedef 10668 if($Level eq "Binary") { 10669 next; 10670 } 10671 if($Level eq "Source") 10672 { 10673 %Class_New = get_PureType($ClassId_New, $TypeInfo{2}); 10674 if($Class_New{"Type"}!~/Class|Struct/) { 10675 next; 10676 } 10677 $ClassId_New = $Class_New{"Tid"}; 10678 } 10679 } 10680 10681 if(not $Class_New{"Size"} or not $Class_Old{"Size"}) 10682 { # incomplete info in the ABI dump 10683 next; 10684 } 10685 10686 10687 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}}); 10688 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}}); 10689 10690 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old; 10691 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New; 10692 10693 my ($BNum1, $BNum2) = (1, 1); 10694 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old; 10695 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New; 10696 my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old; 10697 my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New; 10698 my $Shift_Old = getShift($ClassId_Old, 1); 10699 my $Shift_New = getShift($ClassId_New, 2); 10700 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New; 10701 my ($Added, $Removed) = (0, 0); 10702 my @StableBases_Old = (); 10703 foreach my $BaseId (@Bases_Old) 10704 { 10705 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10706 if($BasePos_New{$Tr_Old{$BaseName}}) { 10707 push(@StableBases_Old, $BaseId); 10708 } 10709 elsif(not $ShortBase_New{$Tr_Old{$BaseName}} 10710 and not $ShortBase_New{get_ShortClass($BaseId, 1)}) 10711 { # removed base 10712 # excluding namespace::SomeClass to SomeClass renaming 10713 my $ProblemKind = "Removed_Base_Class"; 10714 if($Level eq "Binary") 10715 { # Binary-level 10716 if($Shift_Old ne $Shift_New) 10717 { # affected fields 10718 if(havePubFields(\%Class_Old)) { 10719 $ProblemKind .= "_And_Shift"; 10720 } 10721 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10722 $ProblemKind .= "_And_Size"; 10723 } 10724 } 10725 if(keys(%{$VirtualTable_Model{1}{$BaseName}}) 10726 and cmpVTables($ClassName)==1) 10727 { # affected v-table 10728 $ProblemKind .= "_And_VTable"; 10729 $VTableChanged_M{$ClassName}=1; 10730 } 10731 } 10732 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10733 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10734 { 10735 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10736 { 10737 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10738 if($ProblemKind=~/VTable/) { 10739 $VTableChanged_M{$SubName}=1; 10740 } 10741 } 10742 } 10743 foreach my $Interface (@Affected) 10744 { 10745 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10746 next; 10747 } 10748 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10749 "Type_Name"=>$ClassName, 10750 "Target"=>$BaseName, 10751 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10752 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10753 "Shift"=>abs($Shift_New-$Shift_Old) ); 10754 } 10755 $Removed+=1; 10756 } 10757 } 10758 my @StableBases_New = (); 10759 foreach my $BaseId (@Bases_New) 10760 { 10761 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"}; 10762 if($BasePos_Old{$Tr_New{$BaseName}}) { 10763 push(@StableBases_New, $BaseId); 10764 } 10765 elsif(not $ShortBase_Old{$Tr_New{$BaseName}} 10766 and not $ShortBase_Old{get_ShortClass($BaseId, 2)}) 10767 { # added base 10768 # excluding namespace::SomeClass to SomeClass renaming 10769 my $ProblemKind = "Added_Base_Class"; 10770 if($Level eq "Binary") 10771 { # Binary-level 10772 if($Shift_Old ne $Shift_New) 10773 { # affected fields 10774 if(havePubFields(\%Class_Old)) { 10775 $ProblemKind .= "_And_Shift"; 10776 } 10777 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10778 $ProblemKind .= "_And_Size"; 10779 } 10780 } 10781 if(keys(%{$VirtualTable_Model{2}{$BaseName}}) 10782 and cmpVTables($ClassName)==1) 10783 { # affected v-table 10784 $ProblemKind .= "_And_VTable"; 10785 $VTableChanged_M{$ClassName}=1; 10786 } 10787 } 10788 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10789 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10790 { 10791 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10792 { 10793 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10794 if($ProblemKind=~/VTable/) { 10795 $VTableChanged_M{$SubName}=1; 10796 } 10797 } 10798 } 10799 foreach my $Interface (@Affected) 10800 { 10801 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10802 next; 10803 } 10804 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10805 "Type_Name"=>$ClassName, 10806 "Target"=>$BaseName, 10807 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10808 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10809 "Shift"=>abs($Shift_New-$Shift_Old) ); 10810 } 10811 $Added+=1; 10812 } 10813 } 10814 if($Level eq "Binary") 10815 { # Binary-level 10816 ($BNum1, $BNum2) = (1, 1); 10817 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old; 10818 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New; 10819 foreach my $BaseId (@Bases_Old) 10820 { 10821 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10822 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}}) 10823 { 10824 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}}; 10825 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}}; 10826 if($NewPos!=$OldPos) 10827 { # changed position of the base class 10828 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10829 { 10830 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10831 next; 10832 } 10833 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=( 10834 "Type_Name"=>$ClassName, 10835 "Target"=>$BaseName, 10836 "Old_Value"=>$OldPos-1, 10837 "New_Value"=>$NewPos-1 ); 10838 } 10839 } 10840 if($Class_Old{"Base"}{$BaseId}{"virtual"} 10841 and not $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10842 { # became non-virtual base 10843 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10844 { 10845 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10846 next; 10847 } 10848 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=( 10849 "Type_Name"=>$ClassName, 10850 "Target"=>$BaseName ); 10851 } 10852 } 10853 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"} 10854 and $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10855 { # became virtual base 10856 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10857 { 10858 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10859 next; 10860 } 10861 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=( 10862 "Type_Name"=>$ClassName, 10863 "Target"=>$BaseName ); 10864 } 10865 } 10866 } 10867 } 10868 # detect size changes in base classes 10869 if($Shift_Old!=$Shift_New) 10870 { # size of allocable class 10871 foreach my $BaseId (@StableBases_Old) 10872 { # search for changed base 10873 my %BaseType = get_Type($BaseId, 1); 10874 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"}; 10875 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"}; 10876 if($Size_Old ne $Size_New 10877 and $Size_Old and $Size_New) 10878 { 10879 my $ProblemType = undef; 10880 if(isCopyingClass($BaseId, 1)) { 10881 $ProblemType = "Size_Of_Copying_Class"; 10882 } 10883 elsif($AllocableClass{1}{$BaseType{"Name"}}) 10884 { 10885 if($Size_New>$Size_Old) 10886 { # increased size 10887 $ProblemType = "Size_Of_Allocable_Class_Increased"; 10888 } 10889 else 10890 { # decreased size 10891 $ProblemType = "Size_Of_Allocable_Class_Decreased"; 10892 if(not havePubFields(\%Class_Old)) 10893 { # affected class has no public members 10894 next; 10895 } 10896 } 10897 } 10898 next if(not $ProblemType); 10899 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10900 { # base class size changes affecting current class 10901 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10902 next; 10903 } 10904 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=( 10905 "Type_Name"=>$BaseType{"Name"}, 10906 "Target"=>$BaseType{"Name"}, 10907 "Old_Size"=>$Size_Old*$BYTE_SIZE, 10908 "New_Size"=>$Size_New*$BYTE_SIZE ); 10909 } 10910 } 10911 } 10912 } 10913 if(defined $VirtualTable_Model{1}{$ClassName} 10914 and cmpVTables_Real($ClassName, 1)==1 10915 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}})) 10916 { # compare virtual tables size in base classes 10917 my $VShift_Old = getVShift($ClassId_Old, 1); 10918 my $VShift_New = getVShift($ClassId_New, 2); 10919 if($VShift_Old ne $VShift_New) 10920 { # changes in the base class or changes in the list of base classes 10921 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1); 10922 my @AllBases_New = get_base_classes($ClassId_New, 2, 1); 10923 ($BNum1, $BNum2) = (1, 1); 10924 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New; 10925 foreach my $BaseId (@AllBases_Old) 10926 { 10927 my %BaseType = get_Type($BaseId, 1); 10928 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}}) 10929 { # lost base 10930 next; 10931 } 10932 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1); 10933 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2); 10934 if($VSize_Old!=$VSize_New) 10935 { 10936 foreach my $Symbol (@VFunctions) 10937 { # TODO: affected non-virtual methods? 10938 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) 10939 { # Removed_Virtual_Method, will be registered in mergeVirtualTables() 10940 next; 10941 } 10942 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0) 10943 { # skip interfaces that have not changed the absolute virtual position 10944 next; 10945 } 10946 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 10947 next; 10948 } 10949 $VTableChanged_M{$BaseType{"Name"}} = 1; 10950 $VTableChanged_M{$ClassName} = 1; 10951 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}})) 10952 { # the reason of the layout change: added virtual functions 10953 next if($VirtualReplacement{$VirtFunc}); 10954 my $ProblemType = "Added_Virtual_Method"; 10955 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) { 10956 $ProblemType = "Added_Pure_Virtual_Method"; 10957 } 10958 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=( 10959 "Type_Name"=>$BaseType{"Name"}, 10960 "Target"=>get_Signature($VirtFunc, 2) ); 10961 } 10962 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}})) 10963 { # the reason of the layout change: removed virtual functions 10964 next if($VirtualReplacement{$VirtFunc}); 10965 my $ProblemType = "Removed_Virtual_Method"; 10966 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) { 10967 $ProblemType = "Removed_Pure_Virtual_Method"; 10968 } 10969 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=( 10970 "Type_Name"=>$BaseType{"Name"}, 10971 "Target"=>get_Signature($VirtFunc, 1) ); 10972 } 10973 } 10974 } 10975 } 10976 } 10977 } 10978 } 10979 } 10980} 10981 10982sub isCreatable($$) 10983{ 10984 my ($ClassId, $LibVersion) = @_; 10985 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}} 10986 or isCopyingClass($ClassId, $LibVersion)) { 10987 return 1; 10988 } 10989 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 10990 { # Fix for incomplete data: if this class has 10991 # a base class then it should also has a constructor 10992 return 1; 10993 } 10994 if($ReturnedClass{$LibVersion}{$ClassId}) 10995 { # returned by some method of this class 10996 # or any other class 10997 return 1; 10998 } 10999 return 0; 11000} 11001 11002sub isUsedClass($$$) 11003{ 11004 my ($ClassId, $LibVersion, $Level) = @_; 11005 if(keys(%{$ParamClass{$LibVersion}{$ClassId}})) 11006 { # parameter of some exported method 11007 return 1; 11008 } 11009 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 11010 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}})) 11011 { # method from target class 11012 return 1; 11013 } 11014 return 0; 11015} 11016 11017sub mergeVirtualTables($$) 11018{ # check for changes in the virtual table 11019 my ($Interface, $Level) = @_; 11020 # affected methods: 11021 # - virtual 11022 # - pure-virtual 11023 # - non-virtual 11024 if($CompleteSignature{1}{$Interface}{"Data"}) 11025 { # global data is not affected 11026 return; 11027 } 11028 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"}; 11029 if(not $Class_Id) { 11030 return; 11031 } 11032 my $CName = $TypeInfo{1}{$Class_Id}{"Name"}; 11033 if(cmpVTables_Real($CName, 1)==0) 11034 { # no changes 11035 return; 11036 } 11037 $CheckedTypes{$Level}{$CName} = 1; 11038 if($Level eq "Binary") 11039 { # Binary-level 11040 if($CompleteSignature{1}{$Interface}{"PureVirt"} 11041 and not isUsedClass($Class_Id, 1, $Level)) 11042 { # pure virtuals should not be affected 11043 # if there are no exported methods using this class 11044 return; 11045 } 11046 } 11047 foreach my $Func (keys(%{$VirtualTable{1}{$CName}})) 11048 { 11049 if(defined $VirtualTable{2}{$CName}{$Func} 11050 and defined $CompleteSignature{2}{$Func}) 11051 { 11052 if(not $CompleteSignature{1}{$Func}{"PureVirt"} 11053 and $CompleteSignature{2}{$Func}{"PureVirt"}) 11054 { # became pure virtual 11055 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=( 11056 "Type_Name"=>$CName, 11057 "Target"=>get_Signature_M($Func, 1) ); 11058 $VTableChanged_M{$CName} = 1; 11059 } 11060 elsif($CompleteSignature{1}{$Func}{"PureVirt"} 11061 and not $CompleteSignature{2}{$Func}{"PureVirt"}) 11062 { # became non-pure virtual 11063 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=( 11064 "Type_Name"=>$CName, 11065 "Target"=>get_Signature_M($Func, 1) ); 11066 $VTableChanged_M{$CName} = 1; 11067 } 11068 } 11069 } 11070 if($Level eq "Binary") 11071 { # Binary-level 11072 # check virtual table structure 11073 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11074 { 11075 next if($Interface eq $AddedVFunc); 11076 next if($VirtualReplacement{$AddedVFunc}); 11077 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc}; 11078 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11079 { # pure virtual methods affect all others (virtual and non-virtual) 11080 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11081 "Type_Name"=>$CName, 11082 "Target"=>get_Signature($AddedVFunc, 2) ); 11083 $VTableChanged_M{$CName} = 1; 11084 } 11085 elsif(not defined $VirtualTable{1}{$CName} 11086 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}})) 11087 { # added virtual function at the end of v-table 11088 if(not keys(%{$VirtualTable_Model{1}{$CName}})) 11089 { # became polymorphous class, added v-table pointer 11090 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11091 "Type_Name"=>$CName, 11092 "Target"=>get_Signature($AddedVFunc, 2) ); 11093 $VTableChanged_M{$CName} = 1; 11094 } 11095 else 11096 { 11097 my $VSize_Old = getVTable_Size($CName, 1); 11098 my $VSize_New = getVTable_Size($CName, 2); 11099 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method 11100 if(isCopyingClass($Class_Id, 1)) 11101 { # class has no constructors and v-table will be copied by applications, this may affect all methods 11102 my $ProblemType = "Added_Virtual_Method"; 11103 if(isLeafClass($Class_Id, 1)) { 11104 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class"; 11105 } 11106 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11107 "Type_Name"=>$CName, 11108 "Target"=>get_Signature($AddedVFunc, 2) ); 11109 $VTableChanged_M{$CName} = 1; 11110 } 11111 else 11112 { 11113 my $ProblemType = "Added_Virtual_Method"; 11114 if(isLeafClass($Class_Id, 1)) { 11115 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class"; 11116 } 11117 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11118 "Type_Name"=>$CName, 11119 "Target"=>get_Signature($AddedVFunc, 2) ); 11120 $VTableChanged_M{$CName} = 1; 11121 } 11122 } 11123 } 11124 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11125 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11126 { 11127 if(defined $VirtualTable{1}{$CName} 11128 and defined $VirtualTable{2}{$CName}) 11129 { 11130 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11131 my $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11132 11133 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New) 11134 { 11135 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11136 foreach my $ASymbol (@Affected) 11137 { 11138 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11139 { 11140 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11141 next; 11142 } 11143 } 11144 $CheckedSymbols{$Level}{$ASymbol} = 1; 11145 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11146 "Type_Name"=>$CName, 11147 "Target"=>get_Signature($AddedVFunc, 2) ); 11148 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11149 } 11150 } 11151 } 11152 } 11153 else { 11154 # safe 11155 } 11156 } 11157 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11158 { 11159 next if($VirtualReplacement{$RemovedVFunc}); 11160 if($RemovedVFunc eq $Interface 11161 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11162 { # This case is for removed virtual methods 11163 # implemented in both versions of a library 11164 next; 11165 } 11166 if(not keys(%{$VirtualTable_Model{2}{$CName}})) 11167 { # became non-polymorphous class, removed v-table pointer 11168 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11169 "Type_Name"=>$CName, 11170 "Target"=>get_Signature($RemovedVFunc, 1) ); 11171 $VTableChanged_M{$CName} = 1; 11172 } 11173 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11174 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11175 { 11176 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName}) 11177 { 11178 if(not defined $VirtualTable{1}{$CName}{$Interface}) { 11179 next; 11180 } 11181 my $VPos_New = -1; 11182 if(defined $VirtualTable{2}{$CName}{$Interface}) 11183 { 11184 $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11185 } 11186 else 11187 { 11188 if($Interface ne $RemovedVFunc) { 11189 next; 11190 } 11191 } 11192 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc}; 11193 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11194 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New) 11195 { 11196 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11197 foreach my $ASymbol (@Affected) 11198 { 11199 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11200 { 11201 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11202 next; 11203 } 11204 } 11205 my $ProblemType = "Removed_Virtual_Method"; 11206 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { 11207 $ProblemType = "Removed_Pure_Virtual_Method"; 11208 } 11209 $CheckedSymbols{$Level}{$ASymbol} = 1; 11210 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=( 11211 "Type_Name"=>$CName, 11212 "Target"=>get_Signature($RemovedVFunc, 1) ); 11213 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11214 } 11215 } 11216 } 11217 } 11218 } 11219 } 11220 else 11221 { # Source-level 11222 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11223 { 11224 next if($Interface eq $AddedVFunc); 11225 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11226 { 11227 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11228 "Type_Name"=>$CName, 11229 "Target"=>get_Signature($AddedVFunc, 2) ); 11230 } 11231 } 11232 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11233 { 11234 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11235 { 11236 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11237 "Type_Name"=>$CName, 11238 "Target"=>get_Signature($RemovedVFunc, 1) ); 11239 } 11240 } 11241 } 11242} 11243 11244sub find_MemberPair_Pos_byName($$) 11245{ 11246 my ($Member_Name, $Pair_Type) = @_; 11247 $Member_Name=~s/\A[_]+|[_]+\Z//g; 11248 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11249 { 11250 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}) 11251 { 11252 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"}; 11253 $Name=~s/\A[_]+|[_]+\Z//g; 11254 if($Name eq $Member_Name) { 11255 return $MemberPair_Pos; 11256 } 11257 } 11258 } 11259 return "lost"; 11260} 11261 11262sub find_MemberPair_Pos_byVal($$) 11263{ 11264 my ($Member_Value, $Pair_Type) = @_; 11265 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11266 { 11267 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos} 11268 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) { 11269 return $MemberPair_Pos; 11270 } 11271 } 11272 return "lost"; 11273} 11274 11275sub isRecurType($$$) 11276{ 11277 foreach (@{$_[2]}) 11278 { 11279 if( $_->{"T1"} eq $_[0] 11280 and $_->{"T2"} eq $_[1] ) 11281 { 11282 return 1; 11283 } 11284 } 11285 return 0; 11286} 11287 11288sub pushType($$$) 11289{ 11290 my %IDs = ( 11291 "T1" => $_[0], 11292 "T2" => $_[1] 11293 ); 11294 push(@{$_[2]}, \%IDs); 11295} 11296 11297sub isRenamed($$$$$) 11298{ 11299 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_; 11300 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"}; 11301 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"}; 11302 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1}); 11303 if(not defined $Type2->{"Memb"}{$MemPos}) { 11304 return ""; 11305 } 11306 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"}; 11307 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2}); 11308 11309 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"}; 11310 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1); 11311 if($MemberPair_Pos_Rev eq "lost") 11312 { 11313 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"}) 11314 { # base type match 11315 return $Pair_Name; 11316 } 11317 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"}) 11318 { # exact type match 11319 return $Pair_Name; 11320 } 11321 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"}) 11322 { # size match 11323 return $Pair_Name; 11324 } 11325 if(isReserved($Pair_Name)) 11326 { # reserved fields 11327 return $Pair_Name; 11328 } 11329 } 11330 return ""; 11331} 11332 11333sub isLastElem($$) 11334{ 11335 my ($Pos, $TypeRef) = @_; 11336 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"}; 11337 if($Name=~/last|count|max|total/i) 11338 { # GST_LEVEL_COUNT, GST_RTSP_ELAST 11339 return 1; 11340 } 11341 elsif($Name=~/END|NLIMITS\Z/) 11342 { # __RLIMIT_NLIMITS 11343 return 1; 11344 } 11345 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/ 11346 and $Pos+1==keys(%{$TypeRef->{"Memb"}})) 11347 { # NImageFormats, NColorRoles 11348 return 1; 11349 } 11350 return 0; 11351} 11352 11353sub nonComparable($$) 11354{ 11355 my ($T1, $T2) = @_; 11356 11357 my $N1 = $T1->{"Name"}; 11358 my $N2 = $T2->{"Name"}; 11359 11360 $N1=~s/\A(struct|union|enum) //; 11361 $N2=~s/\A(struct|union|enum) //; 11362 11363 if($N1 ne $N2 11364 and not isAnon($N1) 11365 and not isAnon($N2)) 11366 { # different names 11367 if($T1->{"Type"} ne "Pointer" 11368 or $T2->{"Type"} ne "Pointer") 11369 { # compare base types 11370 return 1; 11371 } 11372 if($N1!~/\Avoid\s*\*/ 11373 and $N2=~/\Avoid\s*\*/) 11374 { 11375 return 1; 11376 } 11377 } 11378 elsif($T1->{"Type"} ne $T2->{"Type"}) 11379 { # different types 11380 if($T1->{"Type"} eq "Class" 11381 and $T2->{"Type"} eq "Struct") 11382 { # "class" to "struct" 11383 return 0; 11384 } 11385 elsif($T2->{"Type"} eq "Class" 11386 and $T1->{"Type"} eq "Struct") 11387 { # "struct" to "class" 11388 return 0; 11389 } 11390 else 11391 { # "class" to "enum" 11392 # "union" to "class" 11393 # ... 11394 return 1; 11395 } 11396 } 11397 return 0; 11398} 11399 11400sub isOpaque($) 11401{ 11402 my $T = $_[0]; 11403 if(not defined $T->{"Memb"}) 11404 { 11405 return 1; 11406 } 11407 return 0; 11408} 11409 11410sub removeVPtr($) 11411{ # support for old ABI dumps 11412 my $TPtr = $_[0]; 11413 my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}}); 11414 if($#Pos>=1) 11415 { 11416 foreach my $Pos (0 .. $#Pos-1) 11417 { 11418 %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}}; 11419 } 11420 delete($TPtr->{"Memb"}{$#Pos}); 11421 } 11422} 11423 11424sub mergeTypes($$$) 11425{ 11426 my ($Type1_Id, $Type2_Id, $Level) = @_; 11427 return {} if(not $Type1_Id or not $Type2_Id); 11428 11429 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}) 11430 { # already merged 11431 return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}; 11432 } 11433 11434 my %Type1 = get_Type($Type1_Id, 1); 11435 my %Type2 = get_Type($Type2_Id, 2); 11436 if(not $Type1{"Name"} or not $Type2{"Name"}) { 11437 return {}; 11438 } 11439 11440 $CheckedTypes{$Level}{$Type1{"Name"}} = 1; 11441 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 11442 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 11443 11444 $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1; 11445 11446 my %SubProblems = (); 11447 11448 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 11449 { 11450 if($Type1_Pure{"Type"}=~/Struct|Union/ 11451 and $Type2_Pure{"Type"}=~/Struct|Union/) 11452 { 11453 if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure)) 11454 { 11455 %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=( 11456 "Target"=>$Type1_Pure{"Name"}, 11457 "Type_Name"=>$Type1_Pure{"Name"} ); 11458 11459 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11460 } 11461 } 11462 } 11463 11464 if(not $Type1_Pure{"Size"} 11465 or not $Type2_Pure{"Size"}) 11466 { # including a case when "class Class { ... };" changed to "class Class;" 11467 if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"} 11468 or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1) 11469 { # NOTE: template instances have no size 11470 return {}; 11471 } 11472 } 11473 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes)) 11474 { # skip recursive declarations 11475 return {}; 11476 } 11477 return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); 11478 return {} if($SkipTypes{1}{$Type1_Pure{"Name"}}); 11479 return {} if($SkipTypes{1}{$Type1{"Name"}}); 11480 11481 if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/) 11482 { # support for old ABI dumps 11483 # _vptr field added in 3.0 11484 if(not checkDump(1, "3.0") and checkDump(2, "3.0")) 11485 { 11486 if(defined $Type2_Pure{"Memb"} 11487 and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr") 11488 { 11489 if(keys(%{$Type2_Pure{"Memb"}})==1) { 11490 delete($Type2_Pure{"Memb"}{0}); 11491 } 11492 else { 11493 removeVPtr(\%Type2_Pure); 11494 } 11495 } 11496 } 11497 if(checkDump(1, "3.0") and not checkDump(2, "3.0")) 11498 { 11499 if(defined $Type1_Pure{"Memb"} 11500 and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr") 11501 { 11502 if(keys(%{$Type1_Pure{"Memb"}})==1) { 11503 delete($Type1_Pure{"Memb"}{0}); 11504 } 11505 else { 11506 removeVPtr(\%Type1_Pure); 11507 } 11508 } 11509 } 11510 } 11511 11512 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 11513 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 11514 11515 if(%Typedef_1 and %Typedef_2 11516 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef" 11517 and $Typedef_1{"Name"} eq $Typedef_2{"Name"}) 11518 { 11519 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1}); 11520 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2}); 11521 if($Base_1{"Name"} ne $Base_2{"Name"}) 11522 { 11523 if(differentDumps("G") 11524 or differentDumps("V")) 11525 { # different GCC versions or different dumps 11526 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1); 11527 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2); 11528 # std::__va_list and __va_list 11529 $Base_1{"Name"}=~s/\A(\w+::)+//; 11530 $Base_2{"Name"}=~s/\A(\w+::)+//; 11531 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T"); 11532 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T"); 11533 } 11534 } 11535 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/ 11536 and $Base_1{"Name"} ne $Base_2{"Name"}) 11537 { 11538 if($Level eq "Binary" 11539 and $Type1{"Size"} and $Type2{"Size"} 11540 and $Type1{"Size"} ne $Type2{"Size"}) 11541 { 11542 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=( 11543 "Target"=>$Typedef_1{"Name"}, 11544 "Type_Name"=>$Typedef_1{"Name"}, 11545 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 11546 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE ); 11547 } 11548 my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1}); 11549 my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2}); 11550 if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"})) 11551 { 11552 if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level)) 11553 { 11554 %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=( 11555 "Target"=>$Typedef_1{"Name"}, 11556 "Type_Name"=>$Typedef_1{"Name"}, 11557 "Old_Value"=>$Base_1{"Name"}, 11558 "New_Value"=>$Base_2{"Name"} ); 11559 } 11560 else 11561 { 11562 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=( 11563 "Target"=>$Typedef_1{"Name"}, 11564 "Type_Name"=>$Typedef_1{"Name"}, 11565 "Old_Value"=>$Base_1{"Name"}, 11566 "New_Value"=>$Base_2{"Name"} ); 11567 } 11568 } 11569 } 11570 } 11571 if(nonComparable(\%Type1_Pure, \%Type2_Pure)) 11572 { # different types (reported in detectTypeChange(...)) 11573 my $TT1 = $Type1_Pure{"Type"}; 11574 my $TT2 = $Type2_Pure{"Type"}; 11575 11576 if($TT1 ne $TT2 11577 and $TT1!~/Intrinsic|Pointer|Ref|Typedef/) 11578 { # different type of the type 11579 my $Short1 = $Type1_Pure{"Name"}; 11580 my $Short2 = $Type2_Pure{"Name"}; 11581 11582 $Short1=~s/\A\Q$TT1\E //ig; 11583 $Short2=~s/\A\Q$TT2\E //ig; 11584 11585 if($Short1 eq $Short2) 11586 { 11587 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=( 11588 "Target"=>$Type1_Pure{"Name"}, 11589 "Type_Name"=>$Type1_Pure{"Name"}, 11590 "Old_Value"=>lc($Type1_Pure{"Type"}), 11591 "New_Value"=>lc($Type2_Pure{"Type"}) ); 11592 } 11593 } 11594 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11595 } 11596 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes); 11597 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"} 11598 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"}))) 11599 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11600 { # checking size 11601 if($Level eq "Binary" 11602 and $Type1_Pure{"Size"} and $Type2_Pure{"Size"} 11603 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11604 { 11605 my $ProblemKind = "DataType_Size"; 11606 if($Type1_Pure{"Type"} eq "Class" 11607 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}})) 11608 { 11609 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) { 11610 $ProblemKind = "Size_Of_Copying_Class"; 11611 } 11612 elsif($AllocableClass{1}{$Type1_Pure{"Name"}}) 11613 { 11614 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) { 11615 $ProblemKind = "Size_Of_Allocable_Class_Increased"; 11616 } 11617 else 11618 { 11619 # descreased size of allocable class 11620 # it has no special effects 11621 } 11622 } 11623 } 11624 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=( 11625 "Target"=>$Type1_Pure{"Name"}, 11626 "Type_Name"=>$Type1_Pure{"Name"}, 11627 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE, 11628 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE); 11629 } 11630 } 11631 if(defined $Type1_Pure{"BaseType"} 11632 and defined $Type2_Pure{"BaseType"}) 11633 { # checking base types 11634 my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); 11635 foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) 11636 { 11637 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { 11638 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 11639 } 11640 } 11641 } 11642 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = (); 11643 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}}); 11644 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}}); 11645 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11646 { # detect removed and renamed fields 11647 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11648 next if(not $Member_Name); 11649 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); 11650 if($MemberPair_Pos eq "lost") 11651 { 11652 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11653 { 11654 if(isUnnamed($Member_Name)) 11655 { # support for old-version dumps 11656 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11657 if(not checkDump(2, "2.1")) { 11658 next; 11659 } 11660 } 11661 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2)) 11662 { # renamed 11663 $RenamedField{$Member_Pos} = $RenamedTo; 11664 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11665 } 11666 else 11667 { # removed 11668 $RemovedField{$Member_Pos} = 1; 11669 } 11670 } 11671 elsif($Type1_Pure{"Type"} eq "Enum") 11672 { 11673 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 11674 next if($Member_Value1 eq ""); 11675 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure); 11676 if($MemberPair_Pos ne "lost") 11677 { # renamed 11678 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"}; 11679 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure); 11680 if($MemberPair_Pos_Rev eq "lost") 11681 { 11682 $RenamedField{$Member_Pos} = $RenamedTo; 11683 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11684 } 11685 else { 11686 $RemovedField{$Member_Pos} = 1; 11687 } 11688 } 11689 else 11690 { # removed 11691 $RemovedField{$Member_Pos} = 1; 11692 } 11693 } 11694 } 11695 else 11696 { # related 11697 $RelatedField{$Member_Pos} = $MemberPair_Pos; 11698 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos; 11699 } 11700 } 11701 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11702 { # detect added fields 11703 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11704 next if(not $Member_Name); 11705 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); 11706 if($MemberPair_Pos eq "lost") 11707 { 11708 if(isUnnamed($Member_Name)) 11709 { # support for old-version dumps 11710 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11711 if(not checkDump(1, "2.1")) { 11712 next; 11713 } 11714 } 11715 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/) 11716 { 11717 if(not $RenamedField_Rev{$Member_Pos}) 11718 { # added 11719 $AddedField{$Member_Pos}=1; 11720 } 11721 } 11722 } 11723 } 11724 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 11725 { # detect moved fields 11726 my (%RelPos, %RelPosName, %AbsPos) = (); 11727 my $Pos = 0; 11728 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11729 { # relative positions in 1st version 11730 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11731 next if(not $Member_Name); 11732 if(not $RemovedField{$Member_Pos}) 11733 { # old type without removed fields 11734 $RelPos{1}{$Member_Name} = $Pos; 11735 $RelPosName{1}{$Pos} = $Member_Name; 11736 $AbsPos{1}{$Pos++} = $Member_Pos; 11737 } 11738 } 11739 $Pos = 0; 11740 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11741 { # relative positions in 2nd version 11742 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11743 next if(not $Member_Name); 11744 if(not $AddedField{$Member_Pos}) 11745 { # new type without added fields 11746 $RelPos{2}{$Member_Name} = $Pos; 11747 $RelPosName{2}{$Pos} = $Member_Name; 11748 $AbsPos{2}{$Pos++} = $Member_Pos; 11749 } 11750 } 11751 foreach my $Member_Name (keys(%{$RelPos{1}})) 11752 { 11753 my $RPos1 = $RelPos{1}{$Member_Name}; 11754 my $AbsPos1 = $NameToPosA{$Member_Name}; 11755 my $Member_Name2 = $Member_Name; 11756 if(my $RenamedTo = $RenamedField{$AbsPos1}) 11757 { # renamed 11758 $Member_Name2 = $RenamedTo; 11759 } 11760 my $RPos2 = $RelPos{2}{$Member_Name2}; 11761 if($RPos2 ne "" and $RPos1 ne $RPos2) 11762 { # different relative positions 11763 my $AbsPos2 = $NameToPosB{$Member_Name2}; 11764 if($AbsPos1 ne $AbsPos2) 11765 { # different absolute positions 11766 my $ProblemType = "Moved_Field"; 11767 if(not isPublic(\%Type1_Pure, $AbsPos1)) 11768 { # may change layout and size of type 11769 if($Level eq "Source") { 11770 next; 11771 } 11772 $ProblemType = "Moved_Private_Field"; 11773 } 11774 if($Level eq "Binary" 11775 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11776 { # affected size 11777 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"}; 11778 my $MovedAbsPos = $AbsPos{1}{$RPos2}; 11779 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"}; 11780 if($MemSize1 ne $MemSize2) { 11781 $ProblemType .= "_And_Size"; 11782 } 11783 } 11784 if($ProblemType eq "Moved_Private_Field") { 11785 next; 11786 } 11787 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11788 "Target"=>$Member_Name, 11789 "Type_Name"=>$Type1_Pure{"Name"}, 11790 "Old_Value"=>$RPos1, 11791 "New_Value"=>$RPos2 ); 11792 } 11793 } 11794 } 11795 } 11796 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11797 { # check older fields, public and private 11798 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11799 next if(not $Member_Name); 11800 next if($Member_Name eq "_vptr"); 11801 if(my $RenamedTo = $RenamedField{$Member_Pos}) 11802 { # renamed 11803 if(defined $Constants{2}{$Member_Name}) 11804 { 11805 if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo) 11806 { # define OLD NEW 11807 next; # Safe 11808 } 11809 } 11810 11811 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11812 { 11813 if(isPublic(\%Type1_Pure, $Member_Pos)) 11814 { 11815 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=( 11816 "Target"=>$Member_Name, 11817 "Type_Name"=>$Type1_Pure{"Name"}, 11818 "Old_Value"=>$Member_Name, 11819 "New_Value"=>$RenamedTo ); 11820 } 11821 elsif(isReserved($Member_Name)) 11822 { 11823 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=( 11824 "Target"=>$Member_Name, 11825 "Type_Name"=>$Type1_Pure{"Name"}, 11826 "Old_Value"=>$Member_Name, 11827 "New_Value"=>$RenamedTo ); 11828 } 11829 } 11830 elsif($Type1_Pure{"Type"} eq "Enum") 11831 { 11832 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=( 11833 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"}, 11834 "Type_Name"=>$Type1_Pure{"Name"}, 11835 "Old_Value"=>$Member_Name, 11836 "New_Value"=>$RenamedTo ); 11837 } 11838 } 11839 elsif($RemovedField{$Member_Pos}) 11840 { # removed 11841 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 11842 { 11843 my $ProblemType = "Removed_Field"; 11844 if(not isPublic(\%Type1_Pure, $Member_Pos) 11845 or isUnnamed($Member_Name)) 11846 { 11847 if($Level eq "Source") { 11848 next; 11849 } 11850 $ProblemType = "Removed_Private_Field"; 11851 } 11852 if($Level eq "Binary" 11853 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 11854 { 11855 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 11856 { # affected fields 11857 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})) 11858 { # changed offset 11859 $ProblemType .= "_And_Layout"; 11860 } 11861 } 11862 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11863 { # affected size 11864 $ProblemType .= "_And_Size"; 11865 } 11866 } 11867 if($ProblemType eq "Removed_Private_Field") { 11868 next; 11869 } 11870 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11871 "Target"=>$Member_Name, 11872 "Type_Name"=>$Type1_Pure{"Name"} ); 11873 } 11874 elsif($Type2_Pure{"Type"} eq "Union") 11875 { 11876 if($Level eq "Binary" 11877 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11878 { 11879 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=( 11880 "Target"=>$Member_Name, 11881 "Type_Name"=>$Type1_Pure{"Name"} ); 11882 } 11883 else 11884 { 11885 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=( 11886 "Target"=>$Member_Name, 11887 "Type_Name"=>$Type1_Pure{"Name"} ); 11888 } 11889 } 11890 elsif($Type1_Pure{"Type"} eq "Enum") 11891 { 11892 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=( 11893 "Target"=>$Member_Name, 11894 "Type_Name"=>$Type1_Pure{"Name"}, 11895 "Old_Value"=>$Member_Name ); 11896 } 11897 } 11898 else 11899 { # changed 11900 my $MemberPair_Pos = $RelatedField{$Member_Pos}; 11901 if($Type1_Pure{"Type"} eq "Enum") 11902 { 11903 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 11904 next if($Member_Value1 eq ""); 11905 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"}; 11906 next if($Member_Value2 eq ""); 11907 if($Member_Value1 ne $Member_Value2) 11908 { 11909 my $ProblemType = "Enum_Member_Value"; 11910 if(isLastElem($Member_Pos, \%Type1_Pure)) { 11911 $ProblemType = "Enum_Last_Member_Value"; 11912 } 11913 if($SkipConstants{1}{$Member_Name}) { 11914 $ProblemType = "Enum_Private_Member_Value"; 11915 } 11916 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11917 "Target"=>$Member_Name, 11918 "Type_Name"=>$Type1_Pure{"Name"}, 11919 "Old_Value"=>$Member_Value1, 11920 "New_Value"=>$Member_Value2 ); 11921 } 11922 } 11923 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11924 { 11925 my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"}; 11926 my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"}; 11927 11928 if($Access1 ne "private" 11929 and $Access2 eq "private") 11930 { 11931 %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=( 11932 "Target"=>$Member_Name, 11933 "Type_Name"=>$Type1_Pure{"Name"}); 11934 } 11935 elsif($Access1 ne "protected" 11936 and $Access1 ne "private" 11937 and $Access2 eq "protected") 11938 { 11939 %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=( 11940 "Target"=>$Member_Name, 11941 "Type_Name"=>$Type1_Pure{"Name"}); 11942 } 11943 11944 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"}; 11945 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"}; 11946 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE; 11947 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) { 11948 $SizeV1 = $BSize1; 11949 } 11950 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE; 11951 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) { 11952 $SizeV2 = $BSize2; 11953 } 11954 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"}; 11955 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"}; 11956 if($Level eq "Binary" 11957 and $SizeV1 and $SizeV2 11958 and $SizeV1 ne $SizeV2) 11959 { 11960 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name)) 11961 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})) 11962 { # field size change (including anon-structures and unions) 11963 # - same types 11964 # - unnamed types 11965 # - bitfields 11966 my $ProblemType = "Field_Size"; 11967 if(not isPublic(\%Type1_Pure, $Member_Pos) 11968 or isUnnamed($Member_Name)) 11969 { # should not be accessed by applications, goes to "Low Severity" 11970 # example: "abidata" members in GStreamer types 11971 $ProblemType = "Private_".$ProblemType; 11972 } 11973 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 11974 { # check an effect 11975 if($Type2_Pure{"Type"} ne "Union" 11976 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 11977 { # public fields after the current 11978 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})) 11979 { # changed offset 11980 $ProblemType .= "_And_Layout"; 11981 } 11982 } 11983 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 11984 $ProblemType .= "_And_Type_Size"; 11985 } 11986 } 11987 if($ProblemType eq "Private_Field_Size") 11988 { # private field size with no effect 11989 } 11990 if($ProblemType eq "Field_Size") 11991 { 11992 if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2) 11993 { # Low severity 11994 $ProblemType = "Struct_Field_Size_Increased"; 11995 } 11996 } 11997 if($ProblemType) 11998 { # register a problem 11999 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12000 "Target"=>$Member_Name, 12001 "Type_Name"=>$Type1_Pure{"Name"}, 12002 "Old_Size"=>$SizeV1, 12003 "New_Size"=>$SizeV2); 12004 } 12005 } 12006 } 12007 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} 12008 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) 12009 { # do NOT check bitfield type changes 12010 next; 12011 } 12012 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 12013 { 12014 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12015 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12016 { 12017 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=( 12018 "Target"=>$Member_Name, 12019 "Type_Name"=>$Type1_Pure{"Name"}); 12020 } 12021 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12022 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12023 { 12024 %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=( 12025 "Target"=>$Member_Name, 12026 "Type_Name"=>$Type1_Pure{"Name"}); 12027 } 12028 } 12029 my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); 12030 foreach my $ProblemType (keys(%Sub_SubChanges)) 12031 { 12032 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12033 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12034 12035 # quals 12036 if($ProblemType eq "Field_Type" 12037 or $ProblemType eq "Field_Type_And_Size" 12038 or $ProblemType eq "Field_Type_Format") 12039 { 12040 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 12041 { 12042 if(addedQual($Old_Value, $New_Value, "volatile")) { 12043 %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12044 } 12045 elsif(removedQual($Old_Value, $New_Value, "volatile")) { 12046 %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12047 } 12048 } 12049 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 12050 { 12051 if($RA==2) { 12052 %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12053 } 12054 else { 12055 %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12056 } 12057 } 12058 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 12059 { 12060 if($RR==2) { 12061 %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12062 } 12063 else { 12064 %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12065 } 12066 } 12067 } 12068 } 12069 12070 if($Level eq "Source") 12071 { 12072 foreach my $ProblemType (keys(%Sub_SubChanges)) 12073 { 12074 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12075 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12076 12077 if($ProblemType eq "Field_Type") 12078 { 12079 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 12080 delete($Sub_SubChanges{$ProblemType}); 12081 } 12082 } 12083 } 12084 } 12085 12086 foreach my $ProblemType (keys(%Sub_SubChanges)) 12087 { 12088 my $ProblemType_Init = $ProblemType; 12089 if($ProblemType eq "Field_Type_And_Size") 12090 { # Binary 12091 if(not isPublic(\%Type1_Pure, $Member_Pos) 12092 or isUnnamed($Member_Name)) { 12093 $ProblemType = "Private_".$ProblemType; 12094 } 12095 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12096 { # check an effect 12097 if($Type2_Pure{"Type"} ne "Union" 12098 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12099 { # public fields after the current 12100 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})) 12101 { # changed offset 12102 $ProblemType .= "_And_Layout"; 12103 } 12104 } 12105 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12106 $ProblemType .= "_And_Type_Size"; 12107 } 12108 } 12109 } 12110 else 12111 { 12112 # TODO: Private_Field_Type rule? 12113 12114 if(not isPublic(\%Type1_Pure, $Member_Pos) 12115 or isUnnamed($Member_Name)) { 12116 next; 12117 } 12118 } 12119 if($ProblemType eq "Private_Field_Type_And_Size") 12120 { # private field change with no effect 12121 } 12122 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12123 "Target"=>$Member_Name, 12124 "Type_Name"=>$Type1_Pure{"Name"}); 12125 12126 foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}})) 12127 { # other properties 12128 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr}; 12129 } 12130 } 12131 if(not isPublic(\%Type1_Pure, $Member_Pos)) 12132 { # do NOT check internal type changes 12133 next; 12134 } 12135 if($MemberType1_Id and $MemberType2_Id) 12136 { # checking member type changes 12137 my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); 12138 12139 my %DupProblems = (); 12140 12141 foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) 12142 { 12143 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) 12144 { 12145 if(not defined $AllAffected) 12146 { 12147 if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) { 12148 next; 12149 } 12150 } 12151 12152 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; 12153 $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 12154 12155 if(not defined $AllAffected) 12156 { 12157 $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1; 12158 } 12159 } 12160 } 12161 12162 %DupProblems = (); 12163 } 12164 } 12165 } 12166 } 12167 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 12168 { # checking added members, public and private 12169 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 12170 next if(not $Member_Name); 12171 next if($Member_Name eq "_vptr"); 12172 if($AddedField{$Member_Pos}) 12173 { # added 12174 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 12175 { 12176 my $ProblemType = "Added_Field"; 12177 if(not isPublic(\%Type2_Pure, $Member_Pos) 12178 or isUnnamed($Member_Name)) 12179 { 12180 if($Level eq "Source") { 12181 next; 12182 } 12183 $ProblemType = "Added_Private_Field"; 12184 } 12185 if($Level eq "Binary" 12186 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12187 { 12188 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1)) 12189 { # public fields after the current 12190 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})) 12191 { # changed offset 12192 $ProblemType .= "_And_Layout"; 12193 } 12194 } 12195 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12196 $ProblemType .= "_And_Size"; 12197 } 12198 } 12199 if($ProblemType eq "Added_Private_Field") 12200 { # skip added private fields 12201 next; 12202 } 12203 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12204 "Target"=>$Member_Name, 12205 "Type_Name"=>$Type1_Pure{"Name"}); 12206 } 12207 elsif($Type2_Pure{"Type"} eq "Union") 12208 { 12209 if($Level eq "Binary" 12210 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 12211 { 12212 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=( 12213 "Target"=>$Member_Name, 12214 "Type_Name"=>$Type1_Pure{"Name"}); 12215 } 12216 else 12217 { 12218 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=( 12219 "Target"=>$Member_Name, 12220 "Type_Name"=>$Type1_Pure{"Name"}); 12221 } 12222 } 12223 elsif($Type2_Pure{"Type"} eq "Enum") 12224 { 12225 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"}; 12226 next if($Member_Value eq ""); 12227 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=( 12228 "Target"=>$Member_Name, 12229 "Type_Name"=>$Type2_Pure{"Name"}, 12230 "New_Value"=>$Member_Value); 12231 } 12232 } 12233 } 12234 12235 pop(@RecurTypes); 12236 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 12237} 12238 12239sub isUnnamed($) { 12240 return $_[0]=~/\Aunnamed\d+\Z/; 12241} 12242 12243sub get_ShortClass($$) 12244{ 12245 my ($TypeId, $LibVersion) = @_; 12246 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 12247 if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) { 12248 $TypeName = uncover_typedefs($TypeName, $LibVersion); 12249 } 12250 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) { 12251 $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g; 12252 } 12253 return $TypeName; 12254} 12255 12256sub goToFirst($$$) 12257{ 12258 my ($TypeId, $LibVersion, $Type_Type) = @_; 12259 return () if(not $TypeId); 12260 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) { 12261 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}}; 12262 } 12263 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12264 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12265 return () if(not $Type{"Type"}); 12266 if($Type{"Type"} ne $Type_Type) 12267 { 12268 return () if(not $Type{"BaseType"}); 12269 %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type); 12270 } 12271 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type; 12272 return %Type; 12273} 12274 12275my %TypeSpecAttributes = ( 12276 "Const" => 1, 12277 "Volatile" => 1, 12278 "ConstVolatile" => 1, 12279 "Restrict" => 1, 12280 "Typedef" => 1 12281); 12282 12283sub get_PureType($$) 12284{ 12285 my ($TypeId, $Info) = @_; 12286 if(not $TypeId or not $Info 12287 or not $Info->{$TypeId}) { 12288 return (); 12289 } 12290 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) { 12291 return %{$Cache{"get_PureType"}{$TypeId}{$Info}}; 12292 } 12293 my %Type = %{$Info->{$TypeId}}; 12294 return %Type if(not $Type{"BaseType"}); 12295 if($TypeSpecAttributes{$Type{"Type"}}) { 12296 %Type = get_PureType($Type{"BaseType"}, $Info); 12297 } 12298 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type; 12299 return %Type; 12300} 12301 12302sub get_PLevel($$) 12303{ 12304 my ($TypeId, $LibVersion) = @_; 12305 return 0 if(not $TypeId); 12306 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) { 12307 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion}; 12308 } 12309 return 0 if(not $TypeInfo{$LibVersion}{$TypeId}); 12310 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12311 return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/); 12312 my $PLevel = 0; 12313 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) { 12314 $PLevel += 1; 12315 } 12316 return $PLevel if(not $Type{"BaseType"}); 12317 $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion); 12318 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel; 12319 return $PLevel; 12320} 12321 12322sub get_BaseType($$) 12323{ 12324 my ($TypeId, $LibVersion) = @_; 12325 return () if(not $TypeId); 12326 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) { 12327 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}}; 12328 } 12329 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12330 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12331 return %Type if(not $Type{"BaseType"}); 12332 %Type = get_BaseType($Type{"BaseType"}, $LibVersion); 12333 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type; 12334 return %Type; 12335} 12336 12337sub get_BaseTypeQual($$) 12338{ 12339 my ($TypeId, $LibVersion) = @_; 12340 return "" if(not $TypeId); 12341 return "" if(not $TypeInfo{$LibVersion}{$TypeId}); 12342 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12343 return "" if(not $Type{"BaseType"}); 12344 my $Qual = ""; 12345 if($Type{"Type"} eq "Pointer") { 12346 $Qual .= "*"; 12347 } 12348 elsif($Type{"Type"} eq "Ref") { 12349 $Qual .= "&"; 12350 } 12351 elsif($Type{"Type"} eq "ConstVolatile") { 12352 $Qual .= "const volatile"; 12353 } 12354 elsif($Type{"Type"} eq "Const" 12355 or $Type{"Type"} eq "Volatile" 12356 or $Type{"Type"} eq "Restrict") { 12357 $Qual .= lc($Type{"Type"}); 12358 } 12359 my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion); 12360 return $BQual.$Qual; 12361} 12362 12363sub get_OneStep_BaseType($$) 12364{ 12365 my ($TypeId, $Info) = @_; 12366 if(not $TypeId or not $Info 12367 or not $Info->{$TypeId}) { 12368 return (); 12369 } 12370 my %Type = %{$Info->{$TypeId}}; 12371 return %Type if(not $Type{"BaseType"}); 12372 if(my $BTid = $Type{"BaseType"}) 12373 { 12374 if($Info->{$BTid}) { 12375 return %{$Info->{$BTid}}; 12376 } 12377 else { # something is going wrong 12378 return (); 12379 } 12380 } 12381 else { 12382 return %Type; 12383 } 12384} 12385 12386sub get_Type($$) 12387{ 12388 my ($TypeId, $LibVersion) = @_; 12389 return () if(not $TypeId); 12390 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12391 return %{$TypeInfo{$LibVersion}{$TypeId}}; 12392} 12393 12394sub isPrivateData($) 12395{ # non-public global data 12396 my $Symbol = $_[0]; 12397 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/); 12398} 12399 12400sub isInLineInst($$$) { 12401 return (isTemplateInstance(@_) and not isTemplateSpec(@_)); 12402} 12403 12404sub isTemplateInstance($$$) 12405{ 12406 my ($Symbol, $SInfo, $LibVersion) = @_; 12407 if($CheckObjectsOnly) 12408 { 12409 if($Symbol!~/\A(_Z|\?)/) { 12410 return 0; 12411 } 12412 if(my $Signature = $tr_name{$Symbol}) 12413 { 12414 if(index($Signature,">")==-1) { 12415 return 0; 12416 } 12417 if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) 12418 { 12419 if(index($ShortName,"<")!=-1 12420 and index($ShortName,">")!=-1) { 12421 return 1; 12422 } 12423 } 12424 } 12425 } 12426 else 12427 { 12428 if(my $ClassId = $SInfo->{"Class"}) 12429 { 12430 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}) 12431 { 12432 if(index($ClassName,"<")!=-1) { 12433 return 1; 12434 } 12435 } 12436 } 12437 if(my $ShortName = $SInfo->{"ShortName"}) 12438 { 12439 if(index($ShortName,"<")!=-1 12440 and index($ShortName,">")!=-1) { 12441 return 1; 12442 } 12443 } 12444 } 12445 return 0; 12446} 12447 12448sub isTemplateSpec($$$) 12449{ 12450 my ($Symbol, $SInfo, $LibVersion) = @_; 12451 if(my $ClassId = $SInfo->{"Class"}) 12452 { 12453 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"}) 12454 { # class specialization 12455 return 1; 12456 } 12457 elsif($SInfo->{"Spec"}) 12458 { # method specialization 12459 return 1; 12460 } 12461 } 12462 return 0; 12463} 12464 12465sub symbolFilter($$$$) 12466{ # some special cases when the symbol cannot be imported 12467 my ($Symbol, $LibVersion, $Type, $Level) = @_; 12468 if(isPrivateData($Symbol)) 12469 { # non-public global data 12470 return 0; 12471 } 12472 12473 if(defined $SkipInternal) 12474 { 12475 return 0 if($Symbol=~/($SkipInternal)/); 12476 } 12477 12478 if($CheckObjectsOnly) { 12479 return 0 if($Symbol=~/\A(_init|_fini)\Z/); 12480 } 12481 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7")) 12482 { # support for old ABI dumps in --headers-only mode 12483 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 12484 { 12485 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}) 12486 { 12487 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"}; 12488 if(not $PType or $PType eq "Unknown") { 12489 return 0; 12490 } 12491 } 12492 } 12493 } 12494 if($Type=~/Affected/) 12495 { 12496 if($SkipSymbols{$LibVersion}{$Symbol}) 12497 { # user defined symbols to ignore 12498 return 0; 12499 } 12500 if($SymbolsListPath and not $SymbolsList{$Symbol}) 12501 { # user defined symbols 12502 return 0; 12503 } 12504 if($AppPath and not $SymbolsList_App{$Symbol}) 12505 { # user defined symbols (in application) 12506 return 0; 12507 } 12508 12509 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}; 12510 12511 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 12512 if(not $NameSpace and $ClassId) 12513 { # class methods have no "NameSpace" attribute 12514 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}; 12515 } 12516 if($NameSpace) 12517 { # user defined namespaces to ignore 12518 if($SkipNameSpaces{$LibVersion}{$NameSpace}) { 12519 return 0; 12520 } 12521 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}})) 12522 { # nested namespaces 12523 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) { 12524 return 0; 12525 } 12526 } 12527 } 12528 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) 12529 { 12530 if(my $Skip = skipHeader($Header, $LibVersion)) 12531 { # --skip-headers or <skip_headers> (not <skip_including>) 12532 if($Skip==1) { 12533 return 0; 12534 } 12535 } 12536 } 12537 if($TypesListPath and $ClassId) 12538 { # user defined types 12539 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 12540 12541 if(not $TypesList{$CName}) 12542 { 12543 if(my $NS = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}) 12544 { 12545 $CName=~s/\A\Q$NS\E\:\://g; 12546 } 12547 12548 if(not $TypesList{$CName}) 12549 { 12550 my $Found = 0; 12551 12552 while($CName=~s/\:\:.+?\Z//) 12553 { 12554 if($TypesList{$CName}) 12555 { 12556 $Found = 1; 12557 last; 12558 } 12559 } 12560 12561 if(not $Found) { 12562 return 0; 12563 } 12564 } 12565 } 12566 } 12567 12568 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion)) 12569 { # non-target symbols 12570 return 0; 12571 } 12572 if($Level eq "Binary") 12573 { 12574 if($CheckObjectsOnly) 12575 { 12576 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) { 12577 return 0; 12578 } 12579 } 12580 else 12581 { 12582 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 12583 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) 12584 { 12585 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 12586 { # inline virtual methods 12587 if($Type=~/InlineVirt/) { 12588 return 1; 12589 } 12590 my $Allocable = (not isCopyingClass($ClassId, $LibVersion)); 12591 if(not $Allocable) 12592 { # check bases 12593 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1)) 12594 { 12595 if(not isCopyingClass($DCId, $LibVersion)) 12596 { # exists a derived class without default c-tor 12597 $Allocable=1; 12598 last; 12599 } 12600 } 12601 } 12602 if(not $Allocable) { 12603 return 0; 12604 } 12605 } 12606 else 12607 { # inline non-virtual methods 12608 return 0; 12609 } 12610 } 12611 } 12612 } 12613 } 12614 return 1; 12615} 12616 12617sub detectAdded($) 12618{ 12619 my $Level = $_[0]; 12620 foreach my $Symbol (keys(%{$Symbol_Library{2}})) 12621 { 12622 if(link_symbol($Symbol, 1, "+Deps")) 12623 { # linker can find a new symbol 12624 # in the old-version library 12625 # So, it's not a new symbol 12626 next; 12627 } 12628 if(my $VSym = $SymVer{2}{$Symbol} 12629 and index($Symbol,"\@")==-1) { 12630 next; 12631 } 12632 $AddedInt{$Level}{$Symbol} = 1; 12633 } 12634} 12635 12636sub detectRemoved($) 12637{ 12638 my $Level = $_[0]; 12639 foreach my $Symbol (keys(%{$Symbol_Library{1}})) 12640 { 12641 if($CheckObjectsOnly) { 12642 $CheckedSymbols{"Binary"}{$Symbol} = 1; 12643 } 12644 if(link_symbol($Symbol, 2, "+Deps")) 12645 { # linker can find an old symbol 12646 # in the new-version library 12647 next; 12648 } 12649 if(my $VSym = $SymVer{1}{$Symbol} 12650 and index($Symbol,"\@")==-1) { 12651 next; 12652 } 12653 $RemovedInt{$Level}{$Symbol} = 1; 12654 } 12655} 12656 12657sub mergeLibs($) 12658{ 12659 my $Level = $_[0]; 12660 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 12661 { # checking added symbols 12662 next if($CompleteSignature{2}{$Symbol}{"Private"}); 12663 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly); 12664 next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level)); 12665 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 12666 } 12667 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 12668 { # checking removed symbols 12669 next if($CompleteSignature{1}{$Symbol}{"Private"}); 12670 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly); 12671 if(index($Symbol, "_ZTV")==0) 12672 { # skip v-tables for templates, that should not be imported by applications 12673 next if($tr_name{$Symbol}=~/</); 12674 if(my $CName = $VTableClass{$Symbol}) 12675 { 12676 if(not keys(%{$ClassMethods{$Level}{1}{$CName}})) 12677 { # vtables for "private" classes 12678 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol 12679 next; 12680 } 12681 } 12682 } 12683 else { 12684 next if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)); 12685 } 12686 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) 12687 { # symbols for pure virtual methods cannot be called by clients 12688 next; 12689 } 12690 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 12691 } 12692} 12693 12694sub checkDump($$) 12695{ 12696 my ($LibVersion, $V) = @_; 12697 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) { 12698 return $Cache{"checkDump"}{$LibVersion}{$V}; 12699 } 12700 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0)); 12701} 12702 12703sub detectAdded_H($) 12704{ 12705 my $Level = $_[0]; 12706 foreach my $Symbol (sort keys(%{$CompleteSignature{2}})) 12707 { 12708 if($Level eq "Source") 12709 { # remove symbol version 12710 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12711 $Symbol=$SN; 12712 12713 if($CompleteSignature{2}{$Symbol}{"Artificial"}) 12714 { # skip artificial constructors 12715 next; 12716 } 12717 } 12718 if(not $CompleteSignature{2}{$Symbol}{"Header"} 12719 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) { 12720 next; 12721 } 12722 if($ExtendedSymbols{$Symbol}) { 12723 next; 12724 } 12725 if(not defined $CompleteSignature{1}{$Symbol} 12726 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) 12727 { 12728 if($UsedDump{2}{"SrcBin"}) 12729 { 12730 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11")) 12731 { # support for old and different (!) ABI dumps 12732 if(not $CompleteSignature{2}{$Symbol}{"Virt"} 12733 and not $CompleteSignature{2}{$Symbol}{"PureVirt"}) 12734 { 12735 if($CheckHeadersOnly) 12736 { 12737 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"}) 12738 { 12739 if($Lang eq "C") 12740 { # support for old ABI dumps: missed extern "C" functions 12741 next; 12742 } 12743 } 12744 } 12745 else 12746 { 12747 if(not link_symbol($Symbol, 2, "-Deps")) 12748 { # skip added inline symbols and const global data 12749 next; 12750 } 12751 } 12752 } 12753 } 12754 } 12755 $AddedInt{$Level}{$Symbol} = 1; 12756 } 12757 } 12758} 12759 12760sub detectRemoved_H($) 12761{ 12762 my $Level = $_[0]; 12763 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 12764 { 12765 if($Level eq "Source") 12766 { # remove symbol version 12767 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12768 $Symbol=$SN; 12769 } 12770 if(not $CompleteSignature{1}{$Symbol}{"Header"} 12771 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) { 12772 next; 12773 } 12774 if($ExtendedSymbols{$Symbol}) { 12775 next; 12776 } 12777 if(not defined $CompleteSignature{2}{$Symbol} 12778 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) 12779 { 12780 if($UsedDump{1}{"SrcBin"}) 12781 { 12782 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11")) 12783 { # support for old and different (!) ABI dumps 12784 if(not $CompleteSignature{1}{$Symbol}{"Virt"} 12785 and not $CompleteSignature{1}{$Symbol}{"PureVirt"}) 12786 { 12787 if($CheckHeadersOnly) 12788 { # skip all removed symbols 12789 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"}) 12790 { 12791 if($Lang eq "C") 12792 { # support for old ABI dumps: missed extern "C" functions 12793 next; 12794 } 12795 } 12796 } 12797 else 12798 { 12799 if(not link_symbol($Symbol, 1, "-Deps")) 12800 { # skip removed inline symbols 12801 next; 12802 } 12803 } 12804 } 12805 } 12806 } 12807 if(not checkDump(1, "2.15")) 12808 { 12809 if($Symbol=~/_IT_E\Z/) 12810 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E 12811 next; 12812 } 12813 } 12814 if(not $CompleteSignature{1}{$Symbol}{"Class"}) 12815 { 12816 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"}) 12817 { 12818 if(defined $Constants{2}{$Short}) 12819 { 12820 my $Val = $Constants{2}{$Short}{"Value"}; 12821 if(defined $Func_ShortName{2}{$Val}) 12822 { # old name defined to new 12823 next; 12824 } 12825 } 12826 } 12827 12828 } 12829 $RemovedInt{$Level}{$Symbol} = 1; 12830 if($Level eq "Source") 12831 { # search for a source-compatible equivalent 12832 setAlternative($Symbol, $Level); 12833 } 12834 } 12835 } 12836} 12837 12838sub mergeHeaders($) 12839{ 12840 my $Level = $_[0]; 12841 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 12842 { # checking added symbols 12843 next if($CompleteSignature{2}{$Symbol}{"PureVirt"}); 12844 next if($CompleteSignature{2}{$Symbol}{"Private"}); 12845 next if(not symbolFilter($Symbol, 2, "Affected", $Level)); 12846 if($Level eq "Binary") 12847 { 12848 if($CompleteSignature{2}{$Symbol}{"InLine"}) 12849 { 12850 if(not $CompleteSignature{2}{$Symbol}{"Virt"}) 12851 { # skip inline non-virtual functions 12852 next; 12853 } 12854 } 12855 } 12856 else 12857 { # Source 12858 if($SourceAlternative_B{$Symbol}) { 12859 next; 12860 } 12861 } 12862 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 12863 } 12864 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 12865 { # checking removed symbols 12866 next if($CompleteSignature{1}{$Symbol}{"PureVirt"}); 12867 next if($CompleteSignature{1}{$Symbol}{"Private"}); 12868 next if(not symbolFilter($Symbol, 1, "Affected", $Level)); 12869 if($Level eq "Binary") 12870 { 12871 if($CompleteSignature{1}{$Symbol}{"InLine"}) 12872 { 12873 if(not $CompleteSignature{1}{$Symbol}{"Virt"}) 12874 { # skip inline non-virtual functions 12875 next; 12876 } 12877 } 12878 } 12879 else 12880 { # Source 12881 if(my $Alt = $SourceAlternative{$Symbol}) 12882 { 12883 if(defined $CompleteSignature{1}{$Alt} 12884 and $CompleteSignature{1}{$Symbol}{"Const"}) 12885 { 12886 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 12887 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=( 12888 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"}, 12889 "Target"=>get_Signature($Alt, 1)); 12890 } 12891 else 12892 { # do NOT show removed symbol 12893 next; 12894 } 12895 } 12896 } 12897 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 12898 } 12899} 12900 12901sub addParamNames($) 12902{ 12903 my $LibraryVersion = $_[0]; 12904 return if(not keys(%AddIntParams)); 12905 my $SecondVersion = $LibraryVersion==1?2:1; 12906 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}})) 12907 { 12908 next if(not keys(%{$AddIntParams{$Interface}})); 12909 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}})) 12910 { # add absent parameter names 12911 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"}; 12912 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos}) 12913 { # names from the external file 12914 if(defined $CompleteSignature{$SecondVersion}{$Interface} 12915 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}) 12916 { 12917 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) { 12918 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 12919 } 12920 } 12921 else { 12922 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 12923 } 12924 } 12925 } 12926 } 12927} 12928 12929sub detectChangedTypedefs() 12930{ # detect changed typedefs to show 12931 # correct function signatures 12932 foreach my $Typedef (keys(%{$Typedef_BaseName{1}})) 12933 { 12934 next if(not $Typedef); 12935 my $BName1 = $Typedef_BaseName{1}{$Typedef}; 12936 if(not $BName1 or isAnon($BName1)) { 12937 next; 12938 } 12939 my $BName2 = $Typedef_BaseName{2}{$Typedef}; 12940 if(not $BName2 or isAnon($BName2)) { 12941 next; 12942 } 12943 if($BName1 ne $BName2) { 12944 $ChangedTypedef{$Typedef} = 1; 12945 } 12946 } 12947} 12948 12949sub get_symbol_suffix($$) 12950{ 12951 my ($Symbol, $Full) = @_; 12952 my ($SN, $SO, $SV) = separate_symbol($Symbol); 12953 $Symbol=$SN; # remove version 12954 my $Signature = $tr_name{$Symbol}; 12955 my $Suffix = substr($Signature, find_center($Signature, "(")); 12956 if(not $Full) { 12957 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g; 12958 } 12959 return $Suffix; 12960} 12961 12962sub get_symbol_prefix($$) 12963{ 12964 my ($Symbol, $LibVersion) = @_; 12965 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 12966 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 12967 { # methods 12968 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName; 12969 } 12970 return $ShortName; 12971} 12972 12973sub setAlternative($) 12974{ 12975 my $Symbol = $_[0]; 12976 my $PSymbol = $Symbol; 12977 if(not defined $CompleteSignature{2}{$PSymbol} 12978 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"} 12979 and not $CompleteSignature{2}{$PSymbol}{"ShortName"})) 12980 { # search for a pair 12981 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"}) 12982 { 12983 if($CompleteSignature{1}{$PSymbol}{"Data"}) 12984 { 12985 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/ 12986 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/) 12987 { 12988 if(defined $CompleteSignature{2}{$PSymbol} 12989 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 12990 { 12991 $SourceAlternative{$Symbol} = $PSymbol; 12992 $SourceAlternative_B{$PSymbol} = $Symbol; 12993 if(not defined $CompleteSignature{1}{$PSymbol} 12994 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 12995 $SourceReplacement{$Symbol} = $PSymbol; 12996 } 12997 } 12998 } 12999 } 13000 else 13001 { 13002 foreach my $Sp ("KV", "VK", "K", "V") 13003 { 13004 if($PSymbol=~s/\A_ZN$Sp/_ZN/ 13005 or $PSymbol=~s/\A_ZN/_ZN$Sp/) 13006 { 13007 if(defined $CompleteSignature{2}{$PSymbol} 13008 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13009 { 13010 $SourceAlternative{$Symbol} = $PSymbol; 13011 $SourceAlternative_B{$PSymbol} = $Symbol; 13012 if(not defined $CompleteSignature{1}{$PSymbol} 13013 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 13014 $SourceReplacement{$Symbol} = $PSymbol; 13015 } 13016 } 13017 } 13018 $PSymbol = $Symbol; 13019 } 13020 } 13021 } 13022 } 13023 return ""; 13024} 13025 13026sub getSymKind($$) 13027{ 13028 my ($Symbol, $LibVersion) = @_; 13029 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}) 13030 { 13031 return "Global_Data"; 13032 } 13033 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 13034 { 13035 return "Method"; 13036 } 13037 return "Function"; 13038} 13039 13040sub mergeSymbols($) 13041{ 13042 my $Level = $_[0]; 13043 my %SubProblems = (); 13044 13045 mergeBases($Level); 13046 13047 my %AddedOverloads = (); 13048 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 13049 { # check all added exported symbols 13050 if(not $CompleteSignature{2}{$Symbol}{"Header"}) { 13051 next; 13052 } 13053 if(defined $CompleteSignature{1}{$Symbol} 13054 and $CompleteSignature{1}{$Symbol}{"Header"}) 13055 { # double-check added symbol 13056 next; 13057 } 13058 if(not symbolFilter($Symbol, 2, "Affected", $Level)) { 13059 next; 13060 } 13061 if($Symbol=~/\A(_Z|\?)/) 13062 { # C++ 13063 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol; 13064 } 13065 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"}) 13066 { # register virtual overridings 13067 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"}; 13068 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"}; 13069 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} 13070 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"}) 13071 { 13072 if($TName_Tid{1}{$AffectedClass_Name}) 13073 { # class should exist in previous version 13074 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1)) 13075 { # old v-table is NOT copied by old applications 13076 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=( 13077 "Type_Name"=>$AffectedClass_Name, 13078 "Target"=>get_Signature($Symbol, 2), 13079 "Old_Value"=>get_Signature($OverriddenMethod, 2), 13080 "New_Value"=>get_Signature($Symbol, 2)); 13081 } 13082 } 13083 } 13084 } 13085 } 13086 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 13087 { # check all removed exported symbols 13088 if(not $CompleteSignature{1}{$Symbol}{"Header"}) { 13089 next; 13090 } 13091 if(defined $CompleteSignature{2}{$Symbol} 13092 and $CompleteSignature{2}{$Symbol}{"Header"}) 13093 { # double-check removed symbol 13094 next; 13095 } 13096 if($CompleteSignature{1}{$Symbol}{"Private"}) 13097 { # skip private methods 13098 next; 13099 } 13100 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 13101 next; 13102 } 13103 $CheckedSymbols{$Level}{$Symbol} = 1; 13104 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"}) 13105 { # register virtual overridings 13106 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 13107 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"}; 13108 if(defined $CompleteSignature{2}{$OverriddenMethod} 13109 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"}) 13110 { 13111 if($TName_Tid{2}{$AffectedClass_Name}) 13112 { # class should exist in newer version 13113 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1)) 13114 { # old v-table is NOT copied by old applications 13115 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=( 13116 "Type_Name"=>$AffectedClass_Name, 13117 "Target"=>get_Signature($OverriddenMethod, 1), 13118 "Old_Value"=>get_Signature($Symbol, 1), 13119 "New_Value"=>get_Signature($OverriddenMethod, 1)); 13120 } 13121 } 13122 } 13123 } 13124 if($Level eq "Binary" 13125 and $OSgroup eq "windows") 13126 { # register the reason of symbol name change 13127 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}}) 13128 { 13129 if($AddedInt{$Level}{$NewSym}) 13130 { 13131 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"}) 13132 { 13133 if($CompleteSignature{2}{$NewSym}{"Static"}) 13134 { 13135 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=( 13136 "Target"=>$tr_name{$Symbol}, 13137 "Old_Value"=>$Symbol, 13138 "New_Value"=>$NewSym ); 13139 } 13140 else 13141 { 13142 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=( 13143 "Target"=>$tr_name{$Symbol}, 13144 "Old_Value"=>$Symbol, 13145 "New_Value"=>$NewSym ); 13146 } 13147 } 13148 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"}) 13149 { 13150 if($CompleteSignature{2}{$NewSym}{"Virt"}) 13151 { 13152 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=( 13153 "Target"=>$tr_name{$Symbol}, 13154 "Old_Value"=>$Symbol, 13155 "New_Value"=>$NewSym ); 13156 } 13157 else 13158 { 13159 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=( 13160 "Target"=>$tr_name{$Symbol}, 13161 "Old_Value"=>$Symbol, 13162 "New_Value"=>$NewSym ); 13163 } 13164 } 13165 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"}; 13166 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"}; 13167 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"}; 13168 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"}; 13169 if($RTName1 ne $RTName2) 13170 { 13171 my $ProblemType = "Symbol_Changed_Return"; 13172 if($CompleteSignature{1}{$Symbol}{"Data"}) { 13173 $ProblemType = "Global_Data_Symbol_Changed_Type"; 13174 } 13175 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=( 13176 "Target"=>$tr_name{$Symbol}, 13177 "Old_Type"=>$RTName1, 13178 "New_Type"=>$RTName2, 13179 "Old_Value"=>$Symbol, 13180 "New_Value"=>$NewSym ); 13181 } 13182 } 13183 } 13184 } 13185 if($Symbol=~/\A(_Z|\?)/) 13186 { # C++ 13187 my $Prefix = get_symbol_prefix($Symbol, 1); 13188 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}}) 13189 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)}) 13190 { # changed signature: params, "const"-qualifier 13191 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]}; 13192 if($CompleteSignature{1}{$Symbol}{"Constructor"}) 13193 { 13194 if($Symbol=~/(C[1-2][EI])/) 13195 { 13196 my $CtorType = $1; 13197 $NewSym=~s/(C[1-2][EI])/$CtorType/g; 13198 } 13199 } 13200 elsif($CompleteSignature{1}{$Symbol}{"Destructor"}) 13201 { 13202 if($Symbol=~/(D[0-2][EI])/) 13203 { 13204 my $DtorType = $1; 13205 $NewSym=~s/(D[0-2][EI])/$DtorType/g; 13206 } 13207 } 13208 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"}; 13209 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"}; 13210 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2)) 13211 { # from the same class and namespace 13212 if($CompleteSignature{1}{$Symbol}{"Const"} 13213 and not $CompleteSignature{2}{$NewSym}{"Const"}) 13214 { # "const" to non-"const" 13215 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=( 13216 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"}, 13217 "Target"=>$tr_name{$Symbol}, 13218 "New_Signature"=>get_Signature($NewSym, 2), 13219 "Old_Value"=>$Symbol, 13220 "New_Value"=>$NewSym ); 13221 } 13222 elsif(not $CompleteSignature{1}{$Symbol}{"Const"} 13223 and $CompleteSignature{2}{$NewSym}{"Const"}) 13224 { # non-"const" to "const" 13225 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=( 13226 "Target"=>$tr_name{$Symbol}, 13227 "New_Signature"=>get_Signature($NewSym, 2), 13228 "Old_Value"=>$Symbol, 13229 "New_Value"=>$NewSym ); 13230 } 13231 if($CompleteSignature{1}{$Symbol}{"Volatile"} 13232 and not $CompleteSignature{2}{$NewSym}{"Volatile"}) 13233 { # "volatile" to non-"volatile" 13234 13235 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=( 13236 "Target"=>$tr_name{$Symbol}, 13237 "New_Signature"=>get_Signature($NewSym, 2), 13238 "Old_Value"=>$Symbol, 13239 "New_Value"=>$NewSym ); 13240 } 13241 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"} 13242 and $CompleteSignature{2}{$NewSym}{"Volatile"}) 13243 { # non-"volatile" to "volatile" 13244 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=( 13245 "Target"=>$tr_name{$Symbol}, 13246 "New_Signature"=>get_Signature($NewSym, 2), 13247 "Old_Value"=>$Symbol, 13248 "New_Value"=>$NewSym ); 13249 } 13250 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0)) 13251 { # params list 13252 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=( 13253 "Target"=>$tr_name{$Symbol}, 13254 "New_Signature"=>get_Signature($NewSym, 2), 13255 "Old_Value"=>$Symbol, 13256 "New_Value"=>$NewSym ); 13257 } 13258 } 13259 } 13260 } 13261 } 13262 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 13263 { # checking symbols 13264 $CurrentSymbol = $Symbol; 13265 13266 my ($SN, $SS, $SV) = separate_symbol($Symbol); 13267 if($Level eq "Source") 13268 { # remove symbol version 13269 $Symbol=$SN; 13270 } 13271 else 13272 { # Binary 13273 if(not $SV) 13274 { # symbol without version 13275 if(my $VSym = $SymVer{1}{$Symbol}) 13276 { # the symbol is linked with versioned symbol 13277 if($CompleteSignature{2}{$VSym}{"MnglName"}) 13278 { # show report for symbol@ver only 13279 next; 13280 } 13281 elsif(not link_symbol($VSym, 2, "-Deps")) 13282 { # changed version: sym@v1 to sym@v2 13283 # do NOT show report for symbol 13284 next; 13285 } 13286 } 13287 } 13288 } 13289 my $PSymbol = $Symbol; 13290 if($Level eq "Source" 13291 and my $S = $SourceReplacement{$Symbol}) 13292 { # take a source-compatible replacement function 13293 $PSymbol = $S; 13294 } 13295 if($CompleteSignature{1}{$Symbol}{"Private"}) 13296 { # private symbols 13297 next; 13298 } 13299 if(not defined $CompleteSignature{1}{$Symbol} 13300 or not defined $CompleteSignature{2}{$PSymbol}) 13301 { # no info 13302 next; 13303 } 13304 if(not $CompleteSignature{1}{$Symbol}{"MnglName"} 13305 or not $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13306 { # no mangled name 13307 next; 13308 } 13309 if(not $CompleteSignature{1}{$Symbol}{"Header"} 13310 or not $CompleteSignature{2}{$PSymbol}{"Header"}) 13311 { # without a header 13312 next; 13313 } 13314 13315 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} 13316 and $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13317 { # became pure 13318 next; 13319 } 13320 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13321 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13322 { # became non-pure 13323 next; 13324 } 13325 13326 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)) 13327 { # exported, target, inline virtual and pure virtual 13328 next; 13329 } 13330 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level)) 13331 { # exported, target, inline virtual and pure virtual 13332 next; 13333 } 13334 13335 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 13336 { 13337 if($CompleteSignature{1}{$Symbol}{"Data"} 13338 and $CompleteSignature{2}{$PSymbol}{"Data"}) 13339 { 13340 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"}; 13341 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"}; 13342 if(defined $Value1) 13343 { 13344 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1); 13345 if(defined $Value2) 13346 { 13347 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2); 13348 if($Value1 ne $Value2) 13349 { 13350 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=( 13351 "Old_Value"=>$Value1, 13352 "New_Value"=>$Value2, 13353 "Target"=>get_Signature($Symbol, 1) ); 13354 } 13355 } 13356 } 13357 } 13358 } 13359 13360 if($CompleteSignature{2}{$PSymbol}{"Private"}) 13361 { 13362 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=( 13363 "Target"=>get_Signature_M($PSymbol, 2) ); 13364 } 13365 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"} 13366 and $CompleteSignature{2}{$PSymbol}{"Protected"}) 13367 { 13368 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=( 13369 "Target"=>get_Signature_M($PSymbol, 2) ); 13370 } 13371 elsif($CompleteSignature{1}{$Symbol}{"Protected"} 13372 and not $CompleteSignature{2}{$PSymbol}{"Protected"}) 13373 { 13374 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=( 13375 "Target"=>get_Signature_M($PSymbol, 2) ); 13376 } 13377 13378 # checking virtual table 13379 mergeVirtualTables($Symbol, $Level); 13380 13381 if($COMPILE_ERRORS) 13382 { # if some errors occurred at the compiling stage 13383 # then some false positives can be skipped here 13384 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"} 13385 and not $GlobalDataObject{2}{$Symbol}) 13386 { # missed information about parameters in newer version 13387 next; 13388 } 13389 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol} 13390 and not $CompleteSignature{2}{$PSymbol}{"Data"}) 13391 { # missed information about parameters in older version 13392 next; 13393 } 13394 } 13395 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 13396 # checking attributes 13397 if($CompleteSignature{2}{$PSymbol}{"Static"} 13398 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13399 { 13400 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=( 13401 "Target"=>get_Signature($Symbol, 1) 13402 ); 13403 } 13404 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"} 13405 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13406 { 13407 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=( 13408 "Target"=>get_Signature($Symbol, 1) 13409 ); 13410 } 13411 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"}) 13412 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"})) 13413 { # relative position of virtual and pure virtual methods 13414 if($Level eq "Binary") 13415 { 13416 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"} 13417 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"}) 13418 { # top-level virtual methods only 13419 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"}; 13420 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"}; 13421 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name} 13422 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol}) 13423 { # check the absolute position of virtual method (including added and removed methods) 13424 my %Class_Type = get_Type($Class_Id, 1); 13425 my $ProblemType = "Virtual_Method_Position"; 13426 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) { 13427 $ProblemType = "Pure_Virtual_Method_Position"; 13428 } 13429 if(isUsedClass($Class_Id, 1, $Level)) 13430 { 13431 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}})); 13432 foreach my $ASymbol (@Affected) 13433 { 13434 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 13435 next; 13436 } 13437 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=( 13438 "Type_Name"=>$Class_Type{"Name"}, 13439 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"}, 13440 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"}, 13441 "Target"=>get_Signature($Symbol, 1)); 13442 } 13443 $VTableChanged_M{$Class_Type{"Name"}} = 1; 13444 } 13445 } 13446 } 13447 } 13448 } 13449 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13450 or $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13451 { # do NOT check type changes in pure virtuals 13452 next; 13453 } 13454 $CheckedSymbols{$Level}{$Symbol} = 1; 13455 if($Symbol=~/\A(_Z|\?)/ 13456 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13457 { # C/C++: changes in parameters 13458 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13459 { # checking parameters 13460 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1); 13461 } 13462 } 13463 else 13464 { # C: added/removed parameters 13465 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13466 { # checking added parameters 13467 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13468 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"}; 13469 last if($PType2_Name eq "..."); 13470 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13471 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:""; 13472 my $ParamPos_Prev = "-1"; 13473 if($PName=~/\Ap\d+\Z/i) 13474 { # added unnamed parameter ( pN ) 13475 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1); 13476 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2); 13477 if($#Positions1==-1 or $#Positions2>$#Positions1) { 13478 $ParamPos_Prev = "lost"; 13479 } 13480 } 13481 else { 13482 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1); 13483 } 13484 if($ParamPos_Prev eq "lost") 13485 { 13486 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13487 { 13488 my $ProblemType = "Added_Parameter"; 13489 if($PName=~/\Ap\d+\Z/) { 13490 $ProblemType = "Added_Unnamed_Parameter"; 13491 } 13492 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13493 "Target"=>$PName, 13494 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13495 "Param_Type"=>$PType2_Name, 13496 "New_Signature"=>get_Signature($Symbol, 2) ); 13497 } 13498 else 13499 { 13500 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2}); 13501 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13502 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1}); 13503 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"}) 13504 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost") 13505 { 13506 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13507 { 13508 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13509 "Target"=>$PName_Old, 13510 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13511 "Param_Type"=>$PType2_Name, 13512 "Old_Value"=>$PName_Old, 13513 "New_Value"=>$PName, 13514 "New_Signature"=>get_Signature($Symbol, 2) ); 13515 } 13516 } 13517 else 13518 { 13519 my $ProblemType = "Added_Middle_Parameter"; 13520 if($PName=~/\Ap\d+\Z/) { 13521 $ProblemType = "Added_Middle_Unnamed_Parameter"; 13522 } 13523 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13524 "Target"=>$PName, 13525 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13526 "Param_Type"=>$PType2_Name, 13527 "New_Signature"=>get_Signature($Symbol, 2) ); 13528 } 13529 } 13530 } 13531 } 13532 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13533 { # check relevant parameters 13534 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13535 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13536 # FIXME: find relevant parameter by name 13537 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}) 13538 { 13539 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13540 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13541 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"} 13542 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) { 13543 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0); 13544 } 13545 } 13546 } 13547 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13548 { # checking removed parameters 13549 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13550 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"}; 13551 last if($PType1_Name eq "..."); 13552 my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13553 my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:""; 13554 my $ParamPos_New = "-1"; 13555 if($PName=~/\Ap\d+\Z/i) 13556 { # removed unnamed parameter ( pN ) 13557 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1); 13558 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2); 13559 if($#Positions2==-1 or $#Positions2<$#Positions1) { 13560 $ParamPos_New = "lost"; 13561 } 13562 } 13563 else { 13564 $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2); 13565 } 13566 if($ParamPos_New eq "lost") 13567 { 13568 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1) 13569 { 13570 my $ProblemType = "Removed_Parameter"; 13571 if($PName=~/\Ap\d+\Z/) { 13572 $ProblemType = "Removed_Unnamed_Parameter"; 13573 } 13574 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13575 "Target"=>$PName, 13576 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13577 "Param_Type"=>$PType1_Name, 13578 "New_Signature"=>get_Signature($Symbol, 2) ); 13579 } 13580 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13581 { 13582 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1}); 13583 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13584 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2}); 13585 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"}) 13586 and find_ParamPair_Pos_byName($PName_New, $Symbol, 1) eq "lost") 13587 { 13588 if($PName_New!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13589 { 13590 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13591 "Target"=>$PName, 13592 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13593 "Param_Type"=>$PType1_Name, 13594 "Old_Value"=>$PName, 13595 "New_Value"=>$PName_New, 13596 "New_Signature"=>get_Signature($Symbol, 2) ); 13597 } 13598 } 13599 else 13600 { 13601 my $ProblemType = "Removed_Middle_Parameter"; 13602 if($PName=~/\Ap\d+\Z/) { 13603 $ProblemType = "Removed_Middle_Unnamed_Parameter"; 13604 } 13605 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13606 "Target"=>$PName, 13607 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13608 "Param_Type"=>$PType1_Name, 13609 "New_Signature"=>get_Signature($Symbol, 2) ); 13610 } 13611 } 13612 } 13613 } 13614 } 13615 # checking return type 13616 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"}; 13617 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"}; 13618 my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); 13619 13620 foreach my $SubProblemType (keys(%RC_SubProblems)) 13621 { 13622 my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"}; 13623 my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"}; 13624 my %ProblemTypes = (); 13625 13626 if($CompleteSignature{1}{$Symbol}{"Data"}) 13627 { 13628 if($SubProblemType eq "Return_Type_And_Size") { 13629 $ProblemTypes{"Global_Data_Type_And_Size"} = 1; 13630 } 13631 elsif($SubProblemType eq "Return_Type_Format") { 13632 $ProblemTypes{"Global_Data_Type_Format"} = 1; 13633 } 13634 else { 13635 $ProblemTypes{"Global_Data_Type"} = 1; 13636 } 13637 13638 # quals 13639 if($SubProblemType eq "Return_Type" 13640 or $SubProblemType eq "Return_Type_And_Size" 13641 or $SubProblemType eq "Return_Type_Format") 13642 { 13643 if(my $RR = removedQual($Old_Value, $New_Value, "const")) 13644 { # const to non-const 13645 if($RR==2) { 13646 $ProblemTypes{"Global_Data_Removed_Const"} = 1; 13647 } 13648 else { 13649 $ProblemTypes{"Global_Data_Became_Non_Const"} = 1; 13650 } 13651 $ProblemTypes{"Global_Data_Type"} = 1; 13652 } 13653 elsif(my $RA = addedQual($Old_Value, $New_Value, "const")) 13654 { # non-const to const 13655 if($RA==2) { 13656 $ProblemTypes{"Global_Data_Added_Const"} = 1; 13657 } 13658 else { 13659 $ProblemTypes{"Global_Data_Became_Const"} = 1; 13660 } 13661 $ProblemTypes{"Global_Data_Type"} = 1; 13662 } 13663 } 13664 } 13665 else 13666 { 13667 # quals 13668 if($SubProblemType eq "Return_Type" 13669 or $SubProblemType eq "Return_Type_And_Size" 13670 or $SubProblemType eq "Return_Type_Format") 13671 { 13672 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 13673 { 13674 if(addedQual($Old_Value, $New_Value, "volatile")) 13675 { 13676 $ProblemTypes{"Return_Value_Became_Volatile"} = 1; 13677 if($Level ne "Source" 13678 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13679 $ProblemTypes{"Return_Type"} = 1; 13680 } 13681 } 13682 } 13683 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 13684 { 13685 if($RA==2) { 13686 $ProblemTypes{"Return_Type_Added_Const"} = 1; 13687 } 13688 else { 13689 $ProblemTypes{"Return_Type_Became_Const"} = 1; 13690 } 13691 if($Level ne "Source" 13692 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13693 $ProblemTypes{"Return_Type"} = 1; 13694 } 13695 } 13696 } 13697 } 13698 if($Level eq "Binary" 13699 and not $CompleteSignature{1}{$Symbol}{"Data"}) 13700 { 13701 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 13702 if($Arch1 eq "unknown" or $Arch2 eq "unknown") 13703 { # if one of the architectures is unknown 13704 # then set other arhitecture to unknown too 13705 ($Arch1, $Arch2) = ("unknown", "unknown"); 13706 } 13707 my (%Conv1, %Conv2) = (); 13708 if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"}) 13709 { 13710 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol}); 13711 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol}); 13712 } 13713 else 13714 { 13715 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 13716 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 13717 } 13718 13719 if($SubProblemType eq "Return_Type_Became_Void") 13720 { 13721 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13722 { # parameters stack has been affected 13723 if($Conv1{"Method"} eq "stack") { 13724 $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1; 13725 } 13726 elsif($Conv1{"Hidden"}) { 13727 $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1; 13728 } 13729 } 13730 } 13731 elsif($SubProblemType eq "Return_Type_From_Void") 13732 { 13733 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13734 { # parameters stack has been affected 13735 if($Conv2{"Method"} eq "stack") { 13736 $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1; 13737 } 13738 elsif($Conv2{"Hidden"}) { 13739 $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1; 13740 } 13741 } 13742 } 13743 elsif($SubProblemType eq "Return_Type" 13744 or $SubProblemType eq "Return_Type_And_Size" 13745 or $SubProblemType eq "Return_Type_Format") 13746 { 13747 if($Conv1{"Method"} ne $Conv2{"Method"}) 13748 { 13749 if($Conv1{"Method"} eq "stack") 13750 { # returns in a register instead of a hidden first parameter 13751 $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1; 13752 } 13753 else { 13754 $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1; 13755 } 13756 } 13757 else 13758 { 13759 if($Conv1{"Method"} eq "reg") 13760 { 13761 if($Conv1{"Registers"} ne $Conv2{"Registers"}) 13762 { 13763 if($Conv1{"Hidden"}) { 13764 $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1; 13765 } 13766 elsif($Conv2{"Hidden"}) { 13767 $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1; 13768 } 13769 else { 13770 $ProblemTypes{"Return_Type_And_Register"} = 1; 13771 } 13772 } 13773 } 13774 } 13775 } 13776 } 13777 13778 if(not keys(%ProblemTypes)) 13779 { # default 13780 $ProblemTypes{$SubProblemType} = 1; 13781 } 13782 13783 foreach my $ProblemType (keys(%ProblemTypes)) 13784 { # additional 13785 $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType}; 13786 } 13787 } 13788 if($ReturnType1_Id and $ReturnType2_Id) 13789 { 13790 @RecurTypes = (); 13791 my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); 13792 13793 my $AddProblems = {}; 13794 13795 if($CompleteSignature{1}{$Symbol}{"Data"}) 13796 { 13797 if($Level eq "Binary") 13798 { 13799 if(get_PLevel($ReturnType1_Id, 1)==0) 13800 { 13801 if(defined $Sub_SubProblems->{"DataType_Size"}) 13802 { # add "Global_Data_Size" problem 13803 13804 foreach my $Loc (keys(%{$Sub_SubProblems->{"DataType_Size"}})) 13805 { 13806 if(index($Loc,"->")==-1) 13807 { 13808 if($Loc eq $Sub_SubProblems->{"DataType_Size"}{$Loc}{"Type_Name"}) 13809 { 13810 $AddProblems->{"Global_Data_Size"}{$Loc} = $Sub_SubProblems->{"DataType_Size"}{$Loc}; # add a new problem 13811 last; 13812 } 13813 } 13814 } 13815 } 13816 } 13817 if(not defined $AddProblems->{"Global_Data_Size"}) 13818 { 13819 if(defined $GlobalDataObject{1}{$Symbol} 13820 and defined $GlobalDataObject{2}{$Symbol}) 13821 { 13822 my $Old_Size = $GlobalDataObject{1}{$Symbol}; 13823 my $New_Size = $GlobalDataObject{2}{$Symbol}; 13824 if($Old_Size!=$New_Size) 13825 { 13826 $AddProblems->{"Global_Data_Size"}{"retval"} = { 13827 "Old_Size"=>$Old_Size*$BYTE_SIZE, 13828 "New_Size"=>$New_Size*$BYTE_SIZE }; 13829 } 13830 } 13831 } 13832 } 13833 } 13834 13835 foreach my $SubProblemType (keys(%{$AddProblems})) 13836 { 13837 foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}})) 13838 { 13839 my $NewLocation = "retval"; 13840 if($SubLocation and $SubLocation ne "retval") { 13841 $NewLocation = "retval->".$SubLocation; 13842 } 13843 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation}; 13844 } 13845 } 13846 13847 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 13848 { 13849 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 13850 { 13851 my $NewLocation = "retval"; 13852 if($SubLocation and $SubLocation ne "retval") { 13853 $NewLocation = "retval->".$SubLocation; 13854 } 13855 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 13856 } 13857 } 13858 } 13859 13860 # checking object type 13861 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"}; 13862 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"}; 13863 if($ObjTId1 and $ObjTId2 13864 and not $CompleteSignature{1}{$Symbol}{"Static"}) 13865 { 13866 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1); 13867 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2); 13868 if($ThisPtr1_Id and $ThisPtr2_Id) 13869 { 13870 @RecurTypes = (); 13871 my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); 13872 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 13873 { 13874 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 13875 { 13876 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this"; 13877 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 13878 } 13879 } 13880 } 13881 } 13882 } 13883 if($Level eq "Binary") { 13884 mergeVTables($Level); 13885 } 13886 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) { 13887 $CheckedSymbols{$Level}{$Symbol} = 1; 13888 } 13889} 13890 13891sub rmQuals($$) 13892{ 13893 my ($Value, $Qual) = @_; 13894 if(not $Qual) { 13895 return $Value; 13896 } 13897 if($Qual eq "all") 13898 { # all quals 13899 $Qual = "const|volatile|restrict"; 13900 } 13901 while($Value=~s/\b$Qual\b//) { 13902 $Value = formatName($Value, "T"); 13903 } 13904 return $Value; 13905} 13906 13907sub cmpBTypes($$$$) 13908{ 13909 my ($T1, $T2, $V1, $V2) = @_; 13910 $T1 = uncover_typedefs($T1, $V1); 13911 $T2 = uncover_typedefs($T2, $V2); 13912 return (rmQuals($T1, "all") eq rmQuals($T2, "all")); 13913} 13914 13915sub addedQual($$$) 13916{ 13917 my ($Old_Value, $New_Value, $Qual) = @_; 13918 return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual); 13919} 13920 13921sub removedQual($$$) 13922{ 13923 my ($Old_Value, $New_Value, $Qual) = @_; 13924 return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual); 13925} 13926 13927sub removedQual_I($$$$$) 13928{ 13929 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_; 13930 $Old_Value = uncover_typedefs($Old_Value, $V1); 13931 $New_Value = uncover_typedefs($New_Value, $V2); 13932 if($Old_Value eq $New_Value) 13933 { # equal types 13934 return 0; 13935 } 13936 if($Old_Value!~/\b$Qual\b/) 13937 { # without a qual 13938 return 0; 13939 } 13940 elsif($New_Value!~/\b$Qual\b/) 13941 { # became non-qual 13942 return 1; 13943 } 13944 else 13945 { 13946 my @BQ1 = getQualModel($Old_Value, $Qual); 13947 my @BQ2 = getQualModel($New_Value, $Qual); 13948 foreach (0 .. $#BQ1) 13949 { # removed qual 13950 if($BQ1[$_]==1 13951 and $BQ2[$_]!=1) 13952 { 13953 return 2; 13954 } 13955 } 13956 } 13957 return 0; 13958} 13959 13960sub getQualModel($$) 13961{ 13962 my ($Value, $Qual) = @_; 13963 if(not $Qual) { 13964 return $Value; 13965 } 13966 13967 # cleaning 13968 while($Value=~/(\w+)/ and $1 ne $Qual) { 13969 $Value=~s/\b$1\b//g; 13970 } 13971 $Value=~s/[^\*\&\w]+//g; 13972 13973 # modeling 13974 # int*const*const == 011 13975 # int**const == 001 13976 my @Model = (); 13977 my @Elems = split(/[\*\&]/, $Value); 13978 if(not @Elems) { 13979 return (0); 13980 } 13981 foreach (@Elems) 13982 { 13983 if($_ eq $Qual) { 13984 push(@Model, 1); 13985 } 13986 else { 13987 push(@Model, 0); 13988 } 13989 } 13990 13991 return @Model; 13992} 13993 13994my %StringTypes = map {$_=>1} ( 13995 "char*", 13996 "char const*" 13997); 13998 13999my %CharTypes = map {$_=>1} ( 14000 "char", 14001 "char const" 14002); 14003 14004sub showVal($$$) 14005{ 14006 my ($Value, $TypeId, $LibVersion) = @_; 14007 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 14008 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion); 14009 if(substr($Value, 0, 2) eq "_Z") 14010 { 14011 if(my $Unmangled = $tr_name{$Value}) { 14012 return $Unmangled; 14013 } 14014 } 14015 elsif(defined $StringTypes{$TName} or $TName=~/string/i) 14016 { # strings 14017 return "\"$Value\""; 14018 } 14019 elsif(defined $CharTypes{$TName}) 14020 { # characters 14021 return "\'$Value\'"; 14022 } 14023 if($Value eq "") 14024 { # other 14025 return "\'\'"; 14026 } 14027 return $Value; 14028} 14029 14030sub getRegs($$$) 14031{ 14032 my ($LibVersion, $Symbol, $Pos) = @_; 14033 14034 if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"}) 14035 { 14036 my %Regs = (); 14037 foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}})) 14038 { 14039 if($Elem=~/\A$Pos([\.\+]|\Z)/) { 14040 $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1; 14041 } 14042 } 14043 14044 return join(", ", sort keys(%Regs)); 14045 } 14046 14047 return undef; 14048} 14049 14050sub mergeParameters($$$$$$) 14051{ 14052 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_; 14053 if(not $Symbol) { 14054 return; 14055 } 14056 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"}; 14057 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"}; 14058 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"}; 14059 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"}; 14060 if(not $PType1_Id 14061 or not $PType2_Id) { 14062 return; 14063 } 14064 14065 if($Symbol=~/\A(_Z|\?)/) 14066 { # do not merge "this" 14067 if($PName1 eq "this" or $PName2 eq "this") { 14068 return; 14069 } 14070 } 14071 14072 my %Type1 = get_Type($PType1_Id, 1); 14073 my %Type2 = get_Type($PType2_Id, 2); 14074 14075 my %PureType1 = get_PureType($PType1_Id, $TypeInfo{1}); 14076 14077 my %BaseType1 = get_BaseType($PType1_Id, 1); 14078 my %BaseType2 = get_BaseType($PType2_Id, 2); 14079 14080 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter"; 14081 14082 if($Level eq "Binary") 14083 { 14084 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1")) 14085 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format) 14086 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14087 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14088 { 14089 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=( 14090 "Target"=>$PName1, 14091 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14092 } 14093 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14094 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14095 { 14096 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=( 14097 "Target"=>$PName1, 14098 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14099 } 14100 } 14101 14102 if(defined $UsedDump{1}{"DWARF"} 14103 and defined $UsedDump{2}{"DWARF"}) 14104 { 14105 if(checkDump(1, "3.0") and checkDump(2, "3.0")) 14106 { 14107 my $Old_Regs = getRegs(1, $Symbol, $ParamPos1); 14108 my $New_Regs = getRegs(2, $PSymbol, $ParamPos2); 14109 if($Old_Regs and $New_Regs) 14110 { 14111 if($Old_Regs ne $New_Regs) 14112 { 14113 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=( 14114 "Target"=>$PName1, 14115 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14116 "Old_Value"=>$Old_Regs, 14117 "New_Value"=>$New_Regs ); 14118 } 14119 } 14120 elsif($Old_Regs and not $New_Regs) 14121 { 14122 %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=( 14123 "Target"=>$PName1, 14124 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14125 "Old_Value"=>$Old_Regs ); 14126 } 14127 elsif(not $Old_Regs and $New_Regs) 14128 { 14129 %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=( 14130 "Target"=>$PName1, 14131 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14132 "New_Value"=>$New_Regs ); 14133 } 14134 if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne "" 14135 and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "") 14136 { 14137 if($Old_Offset ne $New_Offset) 14138 { 14139 my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"}; 14140 my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"}; 14141 14142 $Old_Offset = $Old_Offset - $Start1; 14143 $New_Offset = $New_Offset - $Start2; 14144 14145 if($Old_Offset ne $New_Offset) 14146 { 14147 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( 14148 "Target"=>$PName1, 14149 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14150 "Old_Value"=>$Old_Offset, 14151 "New_Value"=>$New_Offset ); 14152 } 14153 } 14154 } 14155 } 14156 } 14157 } 14158 if(checkDump(1, "2.0") and checkDump(2, "2.0") 14159 and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1") 14160 { # "default" attribute added in ACC 1.22 (dump 2.0 format) 14161 # broken in 3.1, fixed in 3.2 14162 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"}; 14163 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"}; 14164 if(not checkDump(1, "2.13") 14165 and checkDump(2, "2.13")) 14166 { # support for old ABI dumps 14167 if(defined $Value_Old and defined $Value_New) 14168 { 14169 if($PureType1{"Name"} eq "bool" 14170 and $Value_Old eq "false" and $Value_New eq "0") 14171 { # int class::method ( bool p = 0 ); 14172 # old ABI dumps: "false" 14173 # new ABI dumps: "0" 14174 $Value_Old = "0"; 14175 } 14176 } 14177 } 14178 if(not checkDump(1, "2.18") 14179 and checkDump(2, "2.18")) 14180 { # support for old ABI dumps 14181 if(not defined $Value_Old 14182 and substr($Value_New, 0, 2) eq "_Z") { 14183 $Value_Old = $Value_New; 14184 } 14185 } 14186 if(defined $Value_Old) 14187 { 14188 $Value_Old = showVal($Value_Old, $PType1_Id, 1); 14189 if(defined $Value_New) 14190 { 14191 $Value_New = showVal($Value_New, $PType2_Id, 2); 14192 if($Value_Old ne $Value_New) 14193 { # FIXME: how to distinguish "0" and 0 (NULL) 14194 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=( 14195 "Target"=>$PName1, 14196 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14197 "Old_Value"=>$Value_Old, 14198 "New_Value"=>$Value_New ); 14199 } 14200 } 14201 else 14202 { 14203 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=( 14204 "Target"=>$PName1, 14205 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14206 "Old_Value"=>$Value_Old ); 14207 } 14208 } 14209 elsif(defined $Value_New) 14210 { 14211 $Value_New = showVal($Value_New, $PType2_Id, 2); 14212 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=( 14213 "Target"=>$PName1, 14214 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14215 "New_Value"=>$Value_New ); 14216 } 14217 } 14218 14219 if($ChkRnmd) 14220 { 14221 if($PName1 and $PName2 and $PName1 ne $PName2 14222 and $PType1_Id!=-1 and $PType2_Id!=-1 14223 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/) 14224 { # except unnamed "..." value list (Id=-1) 14225 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=( 14226 "Target"=>$PName1, 14227 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14228 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, 14229 "Old_Value"=>$PName1, 14230 "New_Value"=>$PName2, 14231 "New_Signature"=>get_Signature($Symbol, 2) ); 14232 } 14233 } 14234 14235 # checking type change (replace) 14236 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level); 14237 14238 foreach my $SubProblemType (keys(%SubProblems)) 14239 { # add new problems, remove false alarms 14240 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14241 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14242 14243 # quals 14244 if($SubProblemType eq "Parameter_Type" 14245 or $SubProblemType eq "Parameter_Type_And_Size" 14246 or $SubProblemType eq "Parameter_Type_Format") 14247 { 14248 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14249 { 14250 if(addedQual($Old_Value, $New_Value, "restrict")) { 14251 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14252 } 14253 elsif(removedQual($Old_Value, $New_Value, "restrict")) { 14254 %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14255 } 14256 } 14257 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14258 { 14259 if(removedQual($Old_Value, $New_Value, "volatile")) { 14260 %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}}; 14261 } 14262 } 14263 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"} 14264 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14265 { # int to "int const" 14266 delete($SubProblems{$SubProblemType}); 14267 } 14268 elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"} 14269 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14270 { # "int const" to int 14271 delete($SubProblems{$SubProblemType}); 14272 } 14273 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 14274 { # "const" to non-"const" 14275 if($RR==2) { 14276 %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}}; 14277 } 14278 else { 14279 %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}}; 14280 } 14281 } 14282 } 14283 } 14284 14285 if($Level eq "Source") 14286 { 14287 foreach my $SubProblemType (keys(%SubProblems)) 14288 { 14289 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14290 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14291 14292 if($SubProblemType eq "Parameter_Type") 14293 { 14294 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 14295 delete($SubProblems{$SubProblemType}); 14296 } 14297 } 14298 } 14299 } 14300 14301 foreach my $SubProblemType (keys(%SubProblems)) 14302 { # modify/register problems 14303 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14304 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14305 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"}; 14306 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"}; 14307 14308 my $NewProblemType = $SubProblemType; 14309 if($Old_Value eq "..." and $New_Value ne "...") 14310 { # change from "..." to "int" 14311 if($ParamPos1==0) 14312 { # ISO C requires a named argument before "..." 14313 next; 14314 } 14315 $NewProblemType = "Parameter_Became_Non_VaList"; 14316 } 14317 elsif($New_Value eq "..." and $Old_Value ne "...") 14318 { # change from "int" to "..." 14319 if($ParamPos2==0) 14320 { # ISO C requires a named argument before "..." 14321 next; 14322 } 14323 $NewProblemType = "Parameter_Became_VaList"; 14324 } 14325 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size" 14326 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format")) 14327 { 14328 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 14329 if($Arch1 eq "unknown" 14330 or $Arch2 eq "unknown") 14331 { # if one of the architectures is unknown 14332 # then set other arhitecture to unknown too 14333 ($Arch1, $Arch2) = ("unknown", "unknown"); 14334 } 14335 my (%Conv1, %Conv2) = (); 14336 if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"}) 14337 { # real 14338 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1); 14339 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2); 14340 } 14341 else 14342 { # model 14343 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 14344 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 14345 } 14346 if($Conv1{"Method"} eq $Conv2{"Method"}) 14347 { 14348 if($Conv1{"Method"} eq "stack") 14349 { 14350 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset 14351 $NewProblemType = "Parameter_Type_And_Stack"; 14352 } 14353 } 14354 elsif($Conv1{"Method"} eq "reg") 14355 { 14356 if($Conv1{"Registers"} ne $Conv2{"Registers"}) { 14357 $NewProblemType = "Parameter_Type_And_Register"; 14358 } 14359 } 14360 } 14361 else 14362 { 14363 if($Conv1{"Method"} eq "stack") { 14364 $NewProblemType = "Parameter_Type_From_Stack_To_Register"; 14365 } 14366 elsif($Conv1{"Method"} eq "register") { 14367 $NewProblemType = "Parameter_Type_From_Register_To_Stack"; 14368 } 14369 } 14370 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"}; 14371 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"}; 14372 } 14373 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=( 14374 "Target"=>$PName1, 14375 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14376 "New_Signature"=>get_Signature($Symbol, 2) ); 14377 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; 14378 } 14379 14380 @RecurTypes = (); 14381 14382 # checking type definition changes 14383 my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level); 14384 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 14385 { 14386 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 14387 { 14388 my $NewProblemType = $SubProblemType; 14389 if($SubProblemType eq "DataType_Size") 14390 { 14391 if($PureType1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) 14392 { # stack has been affected 14393 $NewProblemType = "DataType_Size_And_Stack"; 14394 } 14395 } 14396 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location; 14397 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 14398 } 14399 } 14400} 14401 14402sub find_ParamPair_Pos_byName($$$) 14403{ 14404 my ($Name, $Symbol, $LibVersion) = @_; 14405 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14406 { 14407 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14408 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name) 14409 { 14410 return $ParamPos; 14411 } 14412 } 14413 return "lost"; 14414} 14415 14416sub find_ParamPair_Pos_byTypeAndPos($$$$$) 14417{ 14418 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_; 14419 my @Positions = (); 14420 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14421 { 14422 next if($Order eq "backward" and $ParamPos>$MediumPos); 14423 next if($Order eq "forward" and $ParamPos<$MediumPos); 14424 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14425 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"}; 14426 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) { 14427 push(@Positions, $ParamPos); 14428 } 14429 } 14430 return @Positions; 14431} 14432 14433sub getTypeIdByName($$) 14434{ 14435 my ($TypeName, $LibVersion) = @_; 14436 return $TName_Tid{$LibVersion}{formatName($TypeName, "T")}; 14437} 14438 14439sub diffTypes($$$) 14440{ 14441 if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) { 14442 return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}; 14443 } 14444 if(isRecurType($_[0], $_[1], \@RecurTypes_Diff)) 14445 { # skip recursive declarations 14446 return 0; 14447 } 14448 14449 pushType($_[0], $_[1], \@RecurTypes_Diff); 14450 my $Diff = diffTypes_I(@_); 14451 pop(@RecurTypes_Diff); 14452 14453 return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff); 14454} 14455 14456sub diffTypes_I($$$) 14457{ 14458 my ($Type1_Id, $Type2_Id, $Level) = @_; 14459 14460 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14461 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14462 14463 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 14464 { # equal types 14465 return 0; 14466 } 14467 if($Type1_Pure{"Name"} eq "void") 14468 { # from void* to something 14469 return 0; 14470 } 14471 if($Type1_Pure{"Name"}=~/\*/ 14472 or $Type2_Pure{"Name"}=~/\*/) 14473 { # compared in detectTypeChange() 14474 return 0; 14475 } 14476 14477 my %FloatType = map {$_=>1} ( 14478 "float", 14479 "double", 14480 "long double" 14481 ); 14482 14483 my $T1 = $Type1_Pure{"Type"}; 14484 my $T2 = $Type2_Pure{"Type"}; 14485 14486 if($T1 eq "Struct" 14487 and $T2 eq "Class") 14488 { # compare as data structures 14489 $T2 = "Struct"; 14490 } 14491 14492 if($T1 eq "Class" 14493 and $T2 eq "Struct") 14494 { # compare as data structures 14495 $T1 = "Struct"; 14496 } 14497 14498 if($T1 ne $T2) 14499 { # different types 14500 if($T1 eq "Intrinsic" 14501 and $T2 eq "Enum") 14502 { # "int" to "enum" 14503 return 0; 14504 } 14505 elsif($T2 eq "Intrinsic" 14506 and $T1 eq "Enum") 14507 { # "enum" to "int" 14508 return 0; 14509 } 14510 else 14511 { # union to struct 14512 # ... 14513 return 1; 14514 } 14515 } 14516 else 14517 { 14518 if($T1 eq "Intrinsic") 14519 { 14520 if($FloatType{$Type1_Pure{"Name"}} 14521 or $FloatType{$Type2_Pure{"Name"}}) 14522 { # "float" to "double" 14523 # "float" to "int" 14524 if($Level eq "Source") 14525 { # Safe 14526 return 0; 14527 } 14528 else { 14529 return 1; 14530 } 14531 } 14532 } 14533 elsif($T1=~/Class|Struct|Union|Enum/) 14534 { 14535 my @Membs1 = keys(%{$Type1_Pure{"Memb"}}); 14536 my @Membs2 = keys(%{$Type2_Pure{"Memb"}}); 14537 if(not @Membs1 14538 or not @Membs2) 14539 { # private 14540 return 0; 14541 } 14542 if($#Membs1!=$#Membs2) 14543 { # different number of elements 14544 return 1; 14545 } 14546 if($T1 eq "Enum") 14547 { 14548 foreach my $Pos (@Membs1) 14549 { # compare elements by name and value 14550 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"} 14551 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"}) 14552 { # different names 14553 return 1; 14554 } 14555 } 14556 } 14557 else 14558 { 14559 foreach my $Pos (@Membs1) 14560 { 14561 if($Level eq "Source") 14562 { 14563 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}) 14564 { # different names 14565 return 1; 14566 } 14567 } 14568 14569 my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}}; 14570 my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}}; 14571 14572 if($MT1{"Name"} ne $MT2{"Name"} 14573 or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"})) 14574 { 14575 my $PL1 = get_PLevel($MT1{"Tid"}, 1); 14576 my $PL2 = get_PLevel($MT2{"Tid"}, 2); 14577 14578 if($PL1 ne $PL2) 14579 { # different pointer level 14580 return 1; 14581 } 14582 14583 # compare base types 14584 my %BT1 = get_BaseType($MT1{"Tid"}, 1); 14585 my %BT2 = get_BaseType($MT2{"Tid"}, 2); 14586 14587 if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level)) 14588 { # different types 14589 return 1; 14590 } 14591 } 14592 } 14593 } 14594 } 14595 else 14596 { 14597 # TODO: arrays, etc. 14598 } 14599 } 14600 return 0; 14601} 14602 14603sub detectTypeChange($$$$) 14604{ 14605 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_; 14606 if(not $Type1_Id or not $Type2_Id) { 14607 return (); 14608 } 14609 my %LocalProblems = (); 14610 my %Type1 = get_Type($Type1_Id, 1); 14611 my %Type2 = get_Type($Type2_Id, 2); 14612 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14613 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14614 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1); 14615 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2); 14616 14617 my $Type1_PLevel = get_PLevel($Type1_Id, 1); 14618 my $Type2_PLevel = get_PLevel($Type2_Id, 2); 14619 return () if(not $Type1{"Name"} or not $Type2{"Name"}); 14620 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"}); 14621 return () if($Type1_PLevel eq "" or $Type2_PLevel eq ""); 14622 if($Type1_Base{"Name"} ne $Type2_Base{"Name"} 14623 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel 14624 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void"))) 14625 { # base type change 14626 if($Type1{"Name"} eq $Type2{"Name"}) 14627 { 14628 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef") 14629 { # will be reported in mergeTypes() as typedef problem 14630 return (); 14631 } 14632 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 14633 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 14634 if(%Typedef_1 and %Typedef_2) 14635 { 14636 if($Typedef_1{"Name"} eq $Typedef_2{"Name"} 14637 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef") 14638 { # const Typedef 14639 return (); 14640 } 14641 } 14642 } 14643 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/) 14644 { 14645 if($Level eq "Binary" 14646 and $Type1_Base{"Size"} and $Type2_Base{"Size"} 14647 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}) 14648 { 14649 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=( 14650 "Old_Value"=>$Type1_Base{"Name"}, 14651 "New_Value"=>$Type2_Base{"Name"}, 14652 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14653 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14654 } 14655 else 14656 { 14657 if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level)) 14658 { # format change 14659 %{$LocalProblems{$Prefix."_BaseType_Format"}}=( 14660 "Old_Value"=>$Type1_Base{"Name"}, 14661 "New_Value"=>$Type2_Base{"Name"}, 14662 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14663 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14664 } 14665 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"})) 14666 { 14667 %{$LocalProblems{$Prefix."_BaseType"}}=( 14668 "Old_Value"=>$Type1_Base{"Name"}, 14669 "New_Value"=>$Type2_Base{"Name"}, 14670 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14671 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14672 } 14673 } 14674 } 14675 } 14676 elsif($Type1{"Name"} ne $Type2{"Name"}) 14677 { # type change 14678 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/) 14679 { 14680 if($Prefix eq "Return" 14681 and $Type1_Pure{"Name"} eq "void") 14682 { 14683 %{$LocalProblems{"Return_Type_From_Void"}}=( 14684 "New_Value"=>$Type2{"Name"}, 14685 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14686 } 14687 elsif($Prefix eq "Return" 14688 and $Type2_Pure{"Name"} eq "void") 14689 { 14690 %{$LocalProblems{"Return_Type_Became_Void"}}=( 14691 "Old_Value"=>$Type1{"Name"}, 14692 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE); 14693 } 14694 else 14695 { 14696 if($Level eq "Binary" 14697 and $Type1{"Size"} and $Type2{"Size"} 14698 and $Type1{"Size"} ne $Type2{"Size"}) 14699 { 14700 %{$LocalProblems{$Prefix."_Type_And_Size"}}=( 14701 "Old_Value"=>$Type1{"Name"}, 14702 "New_Value"=>$Type2{"Name"}, 14703 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14704 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14705 } 14706 else 14707 { 14708 if(diffTypes($Type1_Id, $Type2_Id, $Level)) 14709 { # format change 14710 %{$LocalProblems{$Prefix."_Type_Format"}}=( 14711 "Old_Value"=>$Type1{"Name"}, 14712 "New_Value"=>$Type2{"Name"}, 14713 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14714 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14715 } 14716 elsif(tNameLock($Type1_Id, $Type2_Id)) 14717 { # FIXME: correct this condition 14718 %{$LocalProblems{$Prefix."_Type"}}=( 14719 "Old_Value"=>$Type1{"Name"}, 14720 "New_Value"=>$Type2{"Name"}, 14721 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14722 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14723 } 14724 } 14725 } 14726 } 14727 } 14728 if($Type1_PLevel!=$Type2_PLevel) 14729 { 14730 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..." 14731 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...") 14732 { 14733 if($Level eq "Source") 14734 { 14735 %{$LocalProblems{$Prefix."_PointerLevel"}}=( 14736 "Old_Value"=>$Type1_PLevel, 14737 "New_Value"=>$Type2_PLevel); 14738 } 14739 else 14740 { 14741 if($Type2_PLevel>$Type1_PLevel) 14742 { 14743 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=( 14744 "Old_Value"=>$Type1_PLevel, 14745 "New_Value"=>$Type2_PLevel); 14746 } 14747 else 14748 { 14749 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=( 14750 "Old_Value"=>$Type1_PLevel, 14751 "New_Value"=>$Type2_PLevel); 14752 } 14753 } 14754 } 14755 } 14756 if($Type1_Pure{"Type"} eq "Array" 14757 and $Type1_Pure{"BaseType"}) 14758 { # base_type[N] -> base_type[N] 14759 # base_type: older_structure -> typedef to newer_structure 14760 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level); 14761 foreach my $SubProblemType (keys(%SubProblems)) 14762 { 14763 $SubProblemType=~s/_Type/_BaseType/g; 14764 next if(defined $LocalProblems{$SubProblemType}); 14765 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) { 14766 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr}; 14767 } 14768 } 14769 } 14770 return %LocalProblems; 14771} 14772 14773sub tNameLock($$) 14774{ 14775 my ($Tid1, $Tid2) = @_; 14776 my $Changed = 0; 14777 if(differentDumps("G")) 14778 { # different GCC versions 14779 $Changed = 1; 14780 } 14781 elsif(differentDumps("V")) 14782 { # different versions of ABI dumps 14783 if(not checkDump(1, "2.20") 14784 or not checkDump(2, "2.20")) 14785 { # latest names update 14786 # 2.6: added restrict qualifier 14787 # 2.13: added missed typedefs to qualified types 14788 # 2.20: prefix for struct, union and enum types 14789 $Changed = 1; 14790 } 14791 } 14792 14793 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"}; 14794 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"}; 14795 14796 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"}; 14797 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"}; 14798 14799 if($Changed) 14800 { # different formats 14801 my %Base1 = get_Type($Tid1, 1); 14802 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") { 14803 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1}); 14804 } 14805 my %Base2 = get_Type($Tid2, 2); 14806 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") { 14807 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2}); 14808 } 14809 my $BName1 = uncover_typedefs($Base1{"Name"}, 1); 14810 my $BName2 = uncover_typedefs($Base2{"Name"}, 2); 14811 if($BName1 eq $BName2) 14812 { # equal base types 14813 return 0; 14814 } 14815 14816 if(not checkDump(1, "2.13") 14817 or not checkDump(2, "2.13")) 14818 { # broken array names in ABI dumps < 2.13 14819 if($TT1 eq "Array" 14820 and $TT2 eq "Array") { 14821 return 0; 14822 } 14823 } 14824 14825 if(not checkDump(1, "2.6") 14826 or not checkDump(2, "2.6")) 14827 { # added restrict attribute in 2.6 14828 if($TN1!~/\brestrict\b/ 14829 and $TN2=~/\brestrict\b/) { 14830 return 0; 14831 } 14832 } 14833 14834 if(not checkDump(1, "2.20") 14835 or not checkDump(2, "2.20")) 14836 { # added type prefix in 2.20 14837 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/ 14838 or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 14839 return 0; 14840 } 14841 } 14842 } 14843 else 14844 { 14845 # typedef struct {...} type_t 14846 # typedef struct type_t {...} type_t 14847 if(index($TN1, " ".$TN2)!=-1) 14848 { 14849 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) { 14850 return 0; 14851 } 14852 } 14853 if(index($TN2, " ".$TN1)!=-1) 14854 { 14855 if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 14856 return 0; 14857 } 14858 } 14859 14860 if($TT1 eq "FuncPtr" 14861 and $TT2 eq "FuncPtr") 14862 { 14863 my $TN1_C = $TN1; 14864 my $TN2_C = $TN2; 14865 14866 $TN1_C=~s/\b(struct|union) //g; 14867 $TN2_C=~s/\b(struct|union) //g; 14868 14869 if($TN1_C eq $TN2_C) { 14870 return 0; 14871 } 14872 } 14873 } 14874 14875 my ($N1, $N2) = ($TN1, $TN2); 14876 $N1=~s/\b(struct|union) //g; 14877 $N2=~s/\b(struct|union) //g; 14878 14879 if($N1 eq $N2) 14880 { # QList<struct QUrl> and QList<QUrl> 14881 return 0; 14882 } 14883 14884 return 1; 14885} 14886 14887sub differentDumps($) 14888{ 14889 my $Check = $_[0]; 14890 if(defined $Cache{"differentDumps"}{$Check}) { 14891 return $Cache{"differentDumps"}{$Check}; 14892 } 14893 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"}) 14894 { 14895 if($Check eq "G") 14896 { 14897 if(getGccVersion(1) ne getGccVersion(2)) 14898 { # different GCC versions 14899 return ($Cache{"differentDumps"}{$Check}=1); 14900 } 14901 } 14902 if($Check eq "V") 14903 { 14904 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2), 14905 formatVersion($UsedDump{2}{"V"}, 2))!=0) 14906 { # different dump versions (skip micro version) 14907 return ($Cache{"differentDumps"}{$Check}=1); 14908 } 14909 } 14910 } 14911 return ($Cache{"differentDumps"}{$Check}=0); 14912} 14913 14914sub formatVersion($$) 14915{ # cut off version digits 14916 my ($V, $Digits) = @_; 14917 my @Elems = split(/\./, $V); 14918 return join(".", splice(@Elems, 0, $Digits)); 14919} 14920 14921sub htmlSpecChars($) 14922{ 14923 my $Str = $_[0]; 14924 if(not $Str) { 14925 return $Str; 14926 } 14927 $Str=~s/\&([^#]|\Z)/&$1/g; 14928 $Str=~s/</</g; 14929 $Str=~s/\-\>/->/g; # − 14930 $Str=~s/>/>/g; 14931 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 14932 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 14933 $Str=~s/ / /g; # 14934 $Str=~s/\@SP\@/ /g; 14935 $Str=~s/\n/<br\/>/g; 14936 $Str=~s/\"/"/g; 14937 $Str=~s/\'/'/g; 14938 return $Str; 14939} 14940 14941sub xmlSpecChars($) 14942{ 14943 my $Str = $_[0]; 14944 if(not $Str) { 14945 return $Str; 14946 } 14947 14948 $Str=~s/\&([^#]|\Z)/&$1/g; 14949 $Str=~s/</</g; 14950 $Str=~s/>/>/g; 14951 14952 $Str=~s/\"/"/g; 14953 $Str=~s/\'/'/g; 14954 14955 return $Str; 14956} 14957 14958sub xmlSpecChars_R($) 14959{ 14960 my $Str = $_[0]; 14961 if(not $Str) { 14962 return $Str; 14963 } 14964 14965 $Str=~s/&/&/g; 14966 $Str=~s/</</g; 14967 $Str=~s/>/>/g; 14968 14969 $Str=~s/"/"/g; 14970 $Str=~s/'/'/g; 14971 14972 return $Str; 14973} 14974 14975sub black_name($) 14976{ 14977 my $Name = $_[0]; 14978 return "<span class='iname_b'>".highLight_Signature($Name)."</span>"; 14979} 14980 14981sub highLight_Signature($) 14982{ 14983 my $Signature = $_[0]; 14984 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0); 14985} 14986 14987sub highLight_Signature_Italic_Color($) 14988{ 14989 my $Signature = $_[0]; 14990 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1); 14991} 14992 14993sub separate_symbol($) 14994{ 14995 my $Symbol = $_[0]; 14996 my ($Name, $Spec, $Ver) = ($Symbol, "", ""); 14997 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) { 14998 ($Name, $Spec, $Ver) = ($1, $2, $3); 14999 } 15000 return ($Name, $Spec, $Ver); 15001} 15002 15003sub cut_f_attrs($) 15004{ 15005 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) { 15006 return $2; 15007 } 15008 return ""; 15009} 15010 15011sub highLight_Signature_PPos_Italic($$$$$) 15012{ 15013 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_; 15014 $Param_Pos = "" if(not defined $Param_Pos); 15015 if($CheckObjectsOnly) { 15016 $ItalicParams=$ColorParams=0; 15017 } 15018 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature); 15019 my $Return = ""; 15020 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) { 15021 $Return = $2; 15022 } 15023 my $SCenter = find_center($Signature, "("); 15024 if(not $SCenter) 15025 { # global data 15026 $Signature = htmlSpecChars($Signature); 15027 $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g; 15028 $Signature .= (($SymbolVersion)?"<span class='sym_ver'> $VersionSpec $SymbolVersion</span>":""); 15029 if($Return and $ShowReturn) { 15030 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15031 } 15032 return $Signature; 15033 } 15034 my ($Begin, $End) = (substr($Signature, 0, $SCenter), ""); 15035 $Begin.=" " if($Begin!~/ \Z/); 15036 $End = cut_f_attrs($Signature); 15037 my @Parts = (); 15038 my ($Short, $Params) = split_Signature($Signature); 15039 my @SParts = separate_Params($Params, 1, 1); 15040 foreach my $Pos (0 .. $#SParts) 15041 { 15042 my $Part = $SParts[$Pos]; 15043 $Part=~s/\A\s+|\s+\Z//g; 15044 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), ""); 15045 if($Part=~/\([\*]+(\w+)\)/i) { 15046 $ParamName = $1;#func-ptr 15047 } 15048 elsif($Part=~/(\w+)[\,\)]*\Z/i) { 15049 $ParamName = $1; 15050 } 15051 if(not $ParamName) 15052 { 15053 push(@Parts, $Part_Styled); 15054 next; 15055 } 15056 if($ItalicParams and not $TName_Tid{1}{$Part} 15057 and not $TName_Tid{2}{$Part}) 15058 { 15059 my $Style = "param"; 15060 if($Param_Pos ne "" 15061 and $Pos==$Param_Pos) { 15062 $Style = "focus_p"; 15063 } 15064 elsif($ColorParams) { 15065 $Style = "color_p"; 15066 } 15067 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig; 15068 } 15069 $Part_Styled=~s/,(\w)/, $1/g; 15070 push(@Parts, $Part_Styled); 15071 } 15072 if(@Parts) 15073 { 15074 foreach my $Num (0 .. $#Parts) 15075 { 15076 if($Num==$#Parts) 15077 { # add ")" to the last parameter 15078 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>"; 15079 } 15080 elsif(length($Parts[$Num])<=45) { 15081 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>"; 15082 } 15083 } 15084 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( ".join(" ", @Parts)."</span>".$End; 15085 } 15086 else { 15087 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( )</span>".$End; 15088 } 15089 if($Return and $ShowReturn) { 15090 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15091 } 15092 $Signature=~s!\[\]![ ]!g; 15093 $Signature=~s!operator=!operator =!g; 15094 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g; 15095 if($SymbolVersion) { 15096 $Signature .= "<span class='sym_ver'> $VersionSpec $SymbolVersion</span>"; 15097 } 15098 return $Signature; 15099} 15100 15101sub split_Signature($) 15102{ 15103 my $Signature = $_[0]; 15104 if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) 15105 { 15106 $Signature=~s/\A\Q$ShortName\E\(//g; 15107 cut_f_attrs($Signature); 15108 $Signature=~s/\)\Z//; 15109 return ($ShortName, $Signature); 15110 } 15111 15112 # error 15113 return ($Signature, ""); 15114} 15115 15116sub separate_Params($$$) 15117{ 15118 my ($Params, $Comma, $Sp) = @_; 15119 my @Parts = (); 15120 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15121 my $Part = 0; 15122 foreach my $Pos (0 .. length($Params) - 1) 15123 { 15124 my $S = substr($Params, $Pos, 1); 15125 if(defined $B{$S}) { 15126 $B{$S} += 1; 15127 } 15128 if($S eq "," and 15129 $B{"("}==$B{")"} and $B{"<"}==$B{">"}) 15130 { 15131 if($Comma) 15132 { # include comma 15133 $Parts[$Part] .= $S; 15134 } 15135 $Part += 1; 15136 } 15137 else { 15138 $Parts[$Part] .= $S; 15139 } 15140 } 15141 if(not $Sp) 15142 { # remove spaces 15143 foreach (@Parts) 15144 { 15145 s/\A //g; 15146 s/ \Z//g; 15147 } 15148 } 15149 return @Parts; 15150} 15151 15152sub find_center($$) 15153{ 15154 my ($Sign, $Target) = @_; 15155 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15156 my $Center = 0; 15157 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g) 15158 { # operators 15159 $Center+=length($1); 15160 } 15161 foreach my $Pos (0 .. length($Sign)-1) 15162 { 15163 my $S = substr($Sign, $Pos, 1); 15164 if($S eq $Target) 15165 { 15166 if($B{"("}==$B{")"} 15167 and $B{"<"}==$B{">"}) { 15168 return $Center; 15169 } 15170 } 15171 if(defined $B{$S}) { 15172 $B{$S}+=1; 15173 } 15174 $Center+=1; 15175 } 15176 return 0; 15177} 15178 15179sub appendFile($$) 15180{ 15181 my ($Path, $Content) = @_; 15182 return if(not $Path); 15183 if(my $Dir = get_dirname($Path)) { 15184 mkpath($Dir); 15185 } 15186 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n"); 15187 print FILE $Content; 15188 close(FILE); 15189} 15190 15191sub writeFile($$) 15192{ 15193 my ($Path, $Content) = @_; 15194 return if(not $Path); 15195 if(my $Dir = get_dirname($Path)) { 15196 mkpath($Dir); 15197 } 15198 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n"); 15199 print FILE $Content; 15200 close(FILE); 15201} 15202 15203sub readFile($) 15204{ 15205 my $Path = $_[0]; 15206 return "" if(not $Path or not -f $Path); 15207 open(FILE, $Path); 15208 local $/ = undef; 15209 my $Content = <FILE>; 15210 close(FILE); 15211 if($Path!~/\.(tu|class|abi)\Z/) { 15212 $Content=~s/\r/\n/g; 15213 } 15214 return $Content; 15215} 15216 15217sub get_filename($) 15218{ # much faster than basename() from File::Basename module 15219 if(defined $Cache{"get_filename"}{$_[0]}) { 15220 return $Cache{"get_filename"}{$_[0]}; 15221 } 15222 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) { 15223 return ($Cache{"get_filename"}{$_[0]}=$1); 15224 } 15225 return ($Cache{"get_filename"}{$_[0]}=""); 15226} 15227 15228sub get_dirname($) 15229{ # much faster than dirname() from File::Basename module 15230 if(defined $Cache{"get_dirname"}{$_[0]}) { 15231 return $Cache{"get_dirname"}{$_[0]}; 15232 } 15233 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) { 15234 return ($Cache{"get_dirname"}{$_[0]}=$1); 15235 } 15236 return ($Cache{"get_dirname"}{$_[0]}=""); 15237} 15238 15239sub separate_path($) { 15240 return (get_dirname($_[0]), get_filename($_[0])); 15241} 15242 15243sub esc($) 15244{ 15245 my $Str = $_[0]; 15246 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g; 15247 return $Str; 15248} 15249 15250sub readLineNum($$) 15251{ 15252 my ($Path, $Num) = @_; 15253 return "" if(not $Path or not -f $Path); 15254 open(FILE, $Path); 15255 foreach (1 ... $Num) { 15256 <FILE>; 15257 } 15258 my $Line = <FILE>; 15259 close(FILE); 15260 return $Line; 15261} 15262 15263sub readAttributes($$) 15264{ 15265 my ($Path, $Num) = @_; 15266 return () if(not $Path or not -f $Path); 15267 my %Attributes = (); 15268 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/) 15269 { 15270 foreach my $AttrVal (split(/;/, $1)) 15271 { 15272 if($AttrVal=~/(.+):(.+)/) 15273 { 15274 my ($Name, $Value) = ($1, $2); 15275 $Attributes{$Name} = $Value; 15276 } 15277 } 15278 } 15279 return \%Attributes; 15280} 15281 15282sub is_abs($) { 15283 return ($_[0]=~/\A(\/|\w+:[\/\\])/); 15284} 15285 15286sub get_abs_path($) 15287{ # abs_path() should NOT be called for absolute inputs 15288 # because it can change them 15289 my $Path = $_[0]; 15290 if(not is_abs($Path)) { 15291 $Path = abs_path($Path); 15292 } 15293 return $Path; 15294} 15295 15296sub get_OSgroup() 15297{ 15298 my $N = $Config{"osname"}; 15299 if($N=~/macos|darwin|rhapsody/i) { 15300 return "macos"; 15301 } 15302 elsif($N=~/freebsd|openbsd|netbsd/i) { 15303 return "bsd"; 15304 } 15305 elsif($N=~/haiku|beos/i) { 15306 return "beos"; 15307 } 15308 elsif($N=~/symbian|epoc/i) { 15309 return "symbian"; 15310 } 15311 elsif($N=~/win/i) { 15312 return "windows"; 15313 } 15314 else { 15315 return $N; 15316 } 15317} 15318 15319sub getGccVersion($) 15320{ 15321 my $LibVersion = $_[0]; 15322 if($GCC_VERSION{$LibVersion}) 15323 { # dump version 15324 return $GCC_VERSION{$LibVersion}; 15325 } 15326 elsif($UsedDump{$LibVersion}{"V"}) 15327 { # old-version dumps 15328 return "unknown"; 15329 } 15330 my $GccVersion = get_dumpversion($GCC_PATH); # host version 15331 if(not $GccVersion) { 15332 return "unknown"; 15333 } 15334 return $GccVersion; 15335} 15336 15337sub showArch($) 15338{ 15339 my $Arch = $_[0]; 15340 if($Arch eq "arm" 15341 or $Arch eq "mips") { 15342 return uc($Arch); 15343 } 15344 return $Arch; 15345} 15346 15347sub getArch($) 15348{ 15349 my $LibVersion = $_[0]; 15350 15351 if($TargetArch) { 15352 return $TargetArch; 15353 } 15354 elsif($CPU_ARCH{$LibVersion}) 15355 { # dump version 15356 return $CPU_ARCH{$LibVersion}; 15357 } 15358 elsif($UsedDump{$LibVersion}{"V"}) 15359 { # old-version dumps 15360 return "unknown"; 15361 } 15362 15363 return getArch_GCC($LibVersion); 15364} 15365 15366sub get_Report_Title($) 15367{ 15368 my $Level = $_[0]; 15369 15370 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>"; 15371 if(getArch(1) ne getArch(2) 15372 or getArch(1) eq "unknown" 15373 or $Level eq "Source") 15374 { # don't show architecture in the header 15375 $ArchInfo=""; 15376 } 15377 my $Title = ""; 15378 if($Level eq "Source") { 15379 $Title .= "Source compatibility"; 15380 } 15381 elsif($Level eq "Binary") { 15382 $Title .= "Binary compatibility"; 15383 } 15384 else { 15385 $Title .= "API compatibility"; 15386 } 15387 15388 if($UsedDump{1}{"DWARF"} and $UsedDump{2}{"DWARF"}) 15389 { 15390 my $M1 = $UsedDump{1}{"M"}; 15391 my $M2 = $UsedDump{2}{"M"}; 15392 15393 if($M1 eq $M2) 15394 { 15395 $Title .= " report for the <span style='color:Blue;'>$M1</span> object"; 15396 $Title .= " between <span style='color:Red;'>".$Descriptor{1}{"Version"}."</span> and <span style='color:Red;'>".$Descriptor{2}{"Version"}."</span> versions"; 15397 } 15398 else 15399 { 15400 $Title .= " report between <span style='color:Blue;'>$M1</span> (<span style='color:Red;'>".$Descriptor{1}{"Version"}."</span>)"; 15401 $Title .= " and <span style='color:Blue;'>$M2</span> (<span style='color:Red;'>".$Descriptor{2}{"Version"}."</span>) objects"; 15402 } 15403 } 15404 else 15405 { 15406 $Title .= " report for the <span style='color:Blue;'>$TargetTitle</span> $TargetComponent"; 15407 $Title .= " between <span style='color:Red;'>".$Descriptor{1}{"Version"}."</span> and <span style='color:Red;'>".$Descriptor{2}{"Version"}."</span> versions"; 15408 } 15409 15410 $Title .= $ArchInfo; 15411 15412 if($AppPath) { 15413 $Title .= " <span class='nowrap'> (relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>"; 15414 } 15415 $Title = "<h1>".$Title."</h1>\n"; 15416 return $Title; 15417} 15418 15419sub get_CheckedHeaders($) 15420{ 15421 my $LibVersion = $_[0]; 15422 15423 my @Headers = (); 15424 15425 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 15426 { 15427 my $File = get_filename($Path); 15428 if(not is_target_header($File, $LibVersion)) { 15429 next; 15430 } 15431 15432 if(skipHeader($File, $LibVersion)) { 15433 next; 15434 } 15435 15436 push(@Headers, $Path); 15437 } 15438 15439 return @Headers; 15440} 15441 15442sub get_SourceInfo() 15443{ 15444 my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", ""); 15445 if(not $CheckObjectsOnly) 15446 { 15447 if(my @Headers = get_CheckedHeaders(1)) 15448 { 15449 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".($#Headers+1).")</h2><hr/>\n"; 15450 $CheckedHeaders .= "<div class='h_list'>\n"; 15451 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 15452 { 15453 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"}; 15454 my $Name = get_filename($Identity); 15455 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15456 $CheckedHeaders .= $Name.$Comment."<br/>\n"; 15457 } 15458 $CheckedHeaders .= "</div>\n"; 15459 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n"; 15460 } 15461 15462 if(my @Sources = keys(%{$Registered_Sources{1}})) 15463 { 15464 $CheckedSources = "<a name='Sources'></a><h2>Source Files (".($#Sources+1).")</h2><hr/>\n"; 15465 $CheckedSources .= "<div class='h_list'>\n"; 15466 foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 15467 { 15468 my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"}; 15469 my $Name = get_filename($Identity); 15470 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15471 $CheckedSources .= $Name.$Comment."<br/>\n"; 15472 } 15473 $CheckedSources .= "</div>\n"; 15474 $CheckedSources .= "<br/>$TOP_REF<br/>\n"; 15475 } 15476 } 15477 if(not $CheckHeadersOnly) 15478 { 15479 $CheckedLibs = "<a name='Libs'></a><h2>".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n"; 15480 $CheckedLibs .= "<div class='lib_list'>\n"; 15481 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) 15482 { 15483 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/); 15484 $CheckedLibs .= $Library."<br/>\n"; 15485 } 15486 $CheckedLibs .= "</div>\n"; 15487 $CheckedLibs .= "<br/>$TOP_REF<br/>\n"; 15488 } 15489 return $CheckedHeaders.$CheckedSources.$CheckedLibs; 15490} 15491 15492sub get_ObjTitle() 15493{ 15494 if(defined $UsedDump{1}{"DWARF"}) { 15495 return "Objects"; 15496 } 15497 else { 15498 return ucfirst($SLIB_TYPE)." Libraries"; 15499 } 15500} 15501 15502sub get_TypeProblems_Count($$$) 15503{ 15504 my ($TypeChanges, $TargetPriority, $Level) = @_; 15505 my $Type_Problems_Count = 0; 15506 foreach my $Type_Name (sort keys(%{$TypeChanges})) 15507 { 15508 my %Kinds_Target = (); 15509 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}})) 15510 { 15511 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}})) 15512 { 15513 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"}; 15514 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15515 next if($Severity ne $TargetPriority); 15516 if($Kinds_Target{$Kind}{$Target}) { 15517 next; 15518 } 15519 15520 if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}) 15521 { 15522 if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 15523 { # select a problem with the highest priority 15524 next; 15525 } 15526 } 15527 $Kinds_Target{$Kind}{$Target} = 1; 15528 $Type_Problems_Count += 1; 15529 } 15530 } 15531 } 15532 return $Type_Problems_Count; 15533} 15534 15535sub get_Summary($) 15536{ 15537 my $Level = $_[0]; 15538 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High, 15539 $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); 15540 %{$RESULT{$Level}} = ( 15541 "Problems"=>0, 15542 "Warnings"=>0, 15543 "Affected"=>0 ); 15544 # check rules 15545 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15546 { 15547 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 15548 { 15549 if(not defined $CompatRules{$Level}{$Kind}) 15550 { # unknown rule 15551 if(not $UnknownRules{$Level}{$Kind}) 15552 { # only one warning 15553 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15554 $UnknownRules{$Level}{$Kind}=1; 15555 } 15556 delete($CompatProblems{$Level}{$Interface}{$Kind}); 15557 } 15558 } 15559 } 15560 foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}})) 15561 { 15562 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 15563 { 15564 if(not defined $CompatRules{$Level}{$Kind}) 15565 { # unknown rule 15566 if(not $UnknownRules{$Level}{$Kind}) 15567 { # only one warning 15568 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15569 $UnknownRules{$Level}{$Kind}=1; 15570 } 15571 delete($CompatProblems_Constants{$Level}{$Constant}{$Kind}); 15572 } 15573 } 15574 } 15575 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15576 { 15577 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 15578 { 15579 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols") 15580 { 15581 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 15582 { 15583 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15584 if($Kind eq "Added_Symbol") { 15585 $Added += 1; 15586 } 15587 elsif($Kind eq "Removed_Symbol") 15588 { 15589 $Removed += 1; 15590 $TotalAffected{$Level}{$Interface} = $Severity; 15591 } 15592 else 15593 { 15594 if($Severity eq "Safe") { 15595 $I_Other += 1; 15596 } 15597 elsif($Severity eq "High") { 15598 $I_Problems_High += 1; 15599 } 15600 elsif($Severity eq "Medium") { 15601 $I_Problems_Medium += 1; 15602 } 15603 elsif($Severity eq "Low") { 15604 $I_Problems_Low += 1; 15605 } 15606 if(($Severity ne "Low" or $StrictCompat) 15607 and $Severity ne "Safe") { 15608 $TotalAffected{$Level}{$Interface} = $Severity; 15609 } 15610 } 15611 } 15612 } 15613 } 15614 } 15615 my %TypeChanges = (); 15616 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15617 { 15618 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 15619 { 15620 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 15621 { 15622 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 15623 { 15624 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; 15625 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; 15626 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15627 my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}; 15628 15629 if($MaxSeverity and $Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 15630 { # select a problem with the highest priority 15631 next; 15632 } 15633 15634 if(($Severity ne "Low" or $StrictCompat) 15635 and $Severity ne "Safe") 15636 { 15637 if(defined $TotalAffected{$Level}{$Interface}) 15638 { 15639 if($Severity_Val{$Severity}>$Severity_Val{$TotalAffected{$Level}{$Interface}}) { 15640 $TotalAffected{$Level}{$Interface} = $Severity; 15641 } 15642 } 15643 else { 15644 $TotalAffected{$Level}{$Interface} = $Severity; 15645 } 15646 } 15647 15648 $TypeChanges{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; 15649 15650 if($MaxSeverity) 15651 { 15652 if($Severity_Val{$Severity}>$Severity_Val{$MaxSeverity}) { 15653 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; 15654 } 15655 } 15656 else { 15657 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; 15658 } 15659 } 15660 } 15661 } 15662 } 15663 15664 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level); 15665 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level); 15666 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level); 15667 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level); 15668 15669 %TypeChanges = (); # free memory 15670 15671 if($CheckObjectsOnly) 15672 { # only removed exported symbols 15673 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}}); 15674 } 15675 else 15676 { # changed and removed public symbols 15677 my $SCount = keys(%{$CheckedSymbols{$Level}}); 15678 if($ExtendedCheck) 15679 { # don't count external_func_0 for constants 15680 $SCount-=1; 15681 } 15682 if($SCount) 15683 { 15684 my %Weight = ( 15685 "High" => 100, 15686 "Medium" => 50, 15687 "Low" => 25 15688 ); 15689 foreach (keys(%{$TotalAffected{$Level}})) { 15690 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}}; 15691 } 15692 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount; 15693 } 15694 else { 15695 $RESULT{$Level}{"Affected"} = 0; 15696 } 15697 } 15698 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"}); 15699 if($RESULT{$Level}{"Affected"}>=100) { 15700 $RESULT{$Level}{"Affected"} = 100; 15701 } 15702 15703 $RESULT{$Level}{"Problems"} += $Removed; 15704 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High; 15705 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium; 15706 if($StrictCompat) { 15707 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low; 15708 } 15709 else { 15710 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low; 15711 } 15712 15713 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 15714 { 15715 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 15716 { 15717 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15718 if($Severity eq "Safe") 15719 { 15720 $C_Other+=1; 15721 } 15722 elsif($Severity eq "Low") 15723 { 15724 $C_Problems_Low+=1; 15725 } 15726 } 15727 } 15728 15729 if($C_Problems_Low) 15730 { 15731 if($StrictCompat) { 15732 $RESULT{$Level}{"Problems"} += $C_Problems_Low; 15733 } 15734 else { 15735 $RESULT{$Level}{"Warnings"} += $C_Problems_Low; 15736 } 15737 } 15738 if($RESULT{$Level}{"Problems"} 15739 and $RESULT{$Level}{"Affected"}) { 15740 $RESULT{$Level}{"Verdict"} = "incompatible"; 15741 } 15742 else { 15743 $RESULT{$Level}{"Verdict"} = "compatible"; 15744 } 15745 15746 my $TotalTypes = keys(%{$CheckedTypes{$Level}}); 15747 if(not $TotalTypes) 15748 { # list all the types 15749 $TotalTypes = keys(%{$TName_Tid{1}}); 15750 } 15751 15752 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 15753 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2)); 15754 15755 my ($TestInfo, $TestResults, $Problem_Summary) = (); 15756 15757 if($ReportFormat eq "xml") 15758 { # XML 15759 # test info 15760 $TestInfo .= " <library>$TargetLibraryName</library>\n"; 15761 $TestInfo .= " <version1>\n"; 15762 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n"; 15763 $TestInfo .= " <arch>$Arch1</arch>\n"; 15764 $TestInfo .= " <gcc>$GccV1</gcc>\n"; 15765 $TestInfo .= " </version1>\n"; 15766 15767 $TestInfo .= " <version2>\n"; 15768 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n"; 15769 $TestInfo .= " <arch>$Arch2</arch>\n"; 15770 $TestInfo .= " <gcc>$GccV2</gcc>\n"; 15771 $TestInfo .= " </version2>\n"; 15772 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n"; 15773 15774 # test results 15775 if(my @Headers = keys(%{$Registered_Headers{1}})) 15776 { 15777 $TestResults .= " <headers>\n"; 15778 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 15779 { 15780 my $Identity = $Registered_Headers{1}{$Name}{"Identity"}; 15781 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15782 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 15783 } 15784 $TestResults .= " </headers>\n"; 15785 } 15786 15787 if(my @Sources = keys(%{$Registered_Sources{1}})) 15788 { 15789 $TestResults .= " <sources>\n"; 15790 foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 15791 { 15792 my $Identity = $Registered_Sources{1}{$Name}{"Identity"}; 15793 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15794 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 15795 } 15796 $TestResults .= " </sources>\n"; 15797 } 15798 15799 $TestResults .= " <libs>\n"; 15800 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) 15801 { 15802 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/); 15803 $TestResults .= " <name>$Library</name>\n"; 15804 } 15805 $TestResults .= " </libs>\n"; 15806 15807 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n"; 15808 $TestResults .= " <types>".$TotalTypes."</types>\n"; 15809 15810 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n"; 15811 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n"; 15812 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n"; 15813 15814 # problem summary 15815 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n"; 15816 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n"; 15817 15818 $Problem_Summary .= " <problems_with_types>\n"; 15819 $Problem_Summary .= " <high>$T_Problems_High</high>\n"; 15820 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n"; 15821 $Problem_Summary .= " <low>$T_Problems_Low</low>\n"; 15822 $Problem_Summary .= " <safe>$T_Other</safe>\n"; 15823 $Problem_Summary .= " </problems_with_types>\n"; 15824 15825 $Problem_Summary .= " <problems_with_symbols>\n"; 15826 $Problem_Summary .= " <high>$I_Problems_High</high>\n"; 15827 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n"; 15828 $Problem_Summary .= " <low>$I_Problems_Low</low>\n"; 15829 $Problem_Summary .= " <safe>$I_Other</safe>\n"; 15830 $Problem_Summary .= " </problems_with_symbols>\n"; 15831 15832 $Problem_Summary .= " <problems_with_constants>\n"; 15833 $Problem_Summary .= " <low>$C_Problems_Low</low>\n"; 15834 $Problem_Summary .= " </problems_with_constants>\n"; 15835 15836 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n"; 15837 15838 return ($TestInfo.$TestResults.$Problem_Summary, ""); 15839 } 15840 else 15841 { # HTML 15842 # test info 15843 $TestInfo = "<h2>Test Info</h2><hr/>\n"; 15844 $TestInfo .= "<table class='summary'>\n"; 15845 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetTitle</td></tr>\n"; 15846 15847 my (@VInf1, @VInf2, $AddTestInfo) = (); 15848 if($Arch1 ne "unknown" 15849 and $Arch2 ne "unknown") 15850 { # CPU arch 15851 if($Arch1 eq $Arch2) 15852 { # go to the separate section 15853 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n"; 15854 } 15855 else 15856 { # go to the version number 15857 push(@VInf1, showArch($Arch1)); 15858 push(@VInf2, showArch($Arch2)); 15859 } 15860 } 15861 if($GccV1 ne "unknown" 15862 and $GccV2 ne "unknown" 15863 and $OStarget ne "windows") 15864 { # GCC version 15865 if($GccV1 eq $GccV2) 15866 { # go to the separate section 15867 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n"; 15868 } 15869 else 15870 { # go to the version number 15871 push(@VInf1, "gcc ".$GccV1); 15872 push(@VInf2, "gcc ".$GccV2); 15873 } 15874 } 15875 # show long version names with GCC version and CPU architecture name (if different) 15876 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n"; 15877 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n"; 15878 $TestInfo .= $AddTestInfo; 15879 #if($COMMON_LANGUAGE{1}) { 15880 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n"; 15881 #} 15882 if($ExtendedCheck) { 15883 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n"; 15884 } 15885 if($JoinReport) 15886 { 15887 if($Level eq "Binary") { 15888 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time 15889 } 15890 if($Level eq "Source") { 15891 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time 15892 } 15893 } 15894 $TestInfo .= "</table>\n"; 15895 15896 # test results 15897 $TestResults = "<h2>Test Results</h2><hr/>\n"; 15898 $TestResults .= "<table class='summary'>"; 15899 15900 if(my @Headers = get_CheckedHeaders(1)) 15901 { 15902 my $Headers_Link = "<a href='#Headers' style='color:Blue;'>".($#Headers + 1)."</a>"; 15903 $TestResults .= "<tr><th>Total Header Files</th><td>".$Headers_Link."</td></tr>\n"; 15904 } 15905 elsif($CheckObjectsOnly) { 15906 $TestResults .= "<tr><th>Total Header Files</th><td>0 (not analyzed)</td></tr>\n"; 15907 } 15908 15909 if(my @Sources = keys(%{$Registered_Sources{1}})) 15910 { 15911 my $Src_Link = "<a href='#Sources' style='color:Blue;'>".($#Sources + 1)."</a>"; 15912 $TestResults .= "<tr><th>Total Source Files</th><td>".$Src_Link."</td></tr>\n"; 15913 } 15914 15915 if(not $ExtendedCheck) 15916 { 15917 my $Libs_Link = "0"; 15918 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0); 15919 $TestResults .= "<tr><th>Total ".get_ObjTitle()."</th><td>".($CheckHeadersOnly?"0 (not analyzed)":$Libs_Link)."</td></tr>\n"; 15920 } 15921 15922 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n"; 15923 15924 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";"; 15925 if($JoinReport) { 15926 $META_DATA = "kind:".lc($Level).";".$META_DATA; 15927 } 15928 $TestResults .= "<tr><th>Verdict</th>"; 15929 if($RESULT{$Level}{"Verdict"} eq "incompatible") { 15930 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>"; 15931 } 15932 else { 15933 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>"; 15934 } 15935 $TestResults .= "</tr>\n"; 15936 $TestResults .= "</table>\n"; 15937 15938 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents 15939 # problem summary 15940 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n"; 15941 $Problem_Summary .= "<table class='summary'>"; 15942 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>"; 15943 15944 my $Added_Link = "0"; 15945 if($Added>0) 15946 { 15947 if($JoinReport) { 15948 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>"; 15949 } 15950 else { 15951 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>"; 15952 } 15953 } 15954 $META_DATA .= "added:$Added;"; 15955 $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n"; 15956 15957 my $Removed_Link = "0"; 15958 if($Removed>0) 15959 { 15960 if($JoinReport) { 15961 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>" 15962 } 15963 else { 15964 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>" 15965 } 15966 } 15967 $META_DATA .= "removed:$Removed;"; 15968 $Problem_Summary .= "<tr><th>Removed Symbols</th>"; 15969 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n"; 15970 15971 my $TH_Link = "0"; 15972 $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0); 15973 $TH_Link = "n/a" if($CheckObjectsOnly); 15974 $META_DATA .= "type_problems_high:$T_Problems_High;"; 15975 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>"; 15976 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n"; 15977 15978 my $TM_Link = "0"; 15979 $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0); 15980 $TM_Link = "n/a" if($CheckObjectsOnly); 15981 $META_DATA .= "type_problems_medium:$T_Problems_Medium;"; 15982 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n"; 15983 15984 my $TL_Link = "0"; 15985 $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0); 15986 $TL_Link = "n/a" if($CheckObjectsOnly); 15987 $META_DATA .= "type_problems_low:$T_Problems_Low;"; 15988 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n"; 15989 15990 my $IH_Link = "0"; 15991 $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0); 15992 $IH_Link = "n/a" if($CheckObjectsOnly); 15993 $META_DATA .= "interface_problems_high:$I_Problems_High;"; 15994 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>"; 15995 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n"; 15996 15997 my $IM_Link = "0"; 15998 $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0); 15999 $IM_Link = "n/a" if($CheckObjectsOnly); 16000 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;"; 16001 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n"; 16002 16003 my $IL_Link = "0"; 16004 $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0); 16005 $IL_Link = "n/a" if($CheckObjectsOnly); 16006 $META_DATA .= "interface_problems_low:$I_Problems_Low;"; 16007 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n"; 16008 16009 my $ChangedConstants_Link = "0"; 16010 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) { 16011 $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>"; 16012 } 16013 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly); 16014 $META_DATA .= "changed_constants:$C_Problems_Low;"; 16015 $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n"; 16016 16017 # Safe Changes 16018 if($T_Other and not $CheckObjectsOnly) 16019 { 16020 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>"; 16021 $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n"; 16022 } 16023 16024 if($I_Other and not $CheckObjectsOnly) 16025 { 16026 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>"; 16027 $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n"; 16028 } 16029 16030 if($C_Other and not $CheckObjectsOnly) 16031 { 16032 my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>"; 16033 $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "S", $C_Other).">$CS_Link</td></tr>\n"; 16034 } 16035 16036 $META_DATA .= "tool_version:$TOOL_VERSION"; 16037 $Problem_Summary .= "</table>\n"; 16038 # $TestInfo = getLegend().$TestInfo; 16039 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA); 16040 } 16041} 16042 16043sub getStyle($$$) 16044{ 16045 my ($Subj, $Act, $Num) = @_; 16046 my %Style = ( 16047 "A"=>"new", 16048 "R"=>"failed", 16049 "S"=>"passed", 16050 "L"=>"warning", 16051 "M"=>"failed", 16052 "H"=>"failed" 16053 ); 16054 if($Num>0) { 16055 return " class='".$Style{$Act}."'"; 16056 } 16057 return ""; 16058} 16059 16060sub show_number($) 16061{ 16062 if($_[0]) 16063 { 16064 my $Num = cut_off_number($_[0], 2, 0); 16065 if($Num eq "0") 16066 { 16067 foreach my $P (3 .. 7) 16068 { 16069 $Num = cut_off_number($_[0], $P, 1); 16070 if($Num ne "0") { 16071 last; 16072 } 16073 } 16074 } 16075 if($Num eq "0") { 16076 $Num = $_[0]; 16077 } 16078 return $Num; 16079 } 16080 return $_[0]; 16081} 16082 16083sub cut_off_number($$$) 16084{ 16085 my ($num, $digs_to_cut, $z) = @_; 16086 if($num!~/\./) 16087 { 16088 $num .= "."; 16089 foreach (1 .. $digs_to_cut-1) { 16090 $num .= "0"; 16091 } 16092 } 16093 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1) 16094 { 16095 foreach (1 .. $digs_to_cut - 1 - length($1)) { 16096 $num .= "0"; 16097 } 16098 } 16099 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) { 16100 $num=sprintf("%.".($digs_to_cut-1)."f", $num); 16101 } 16102 $num=~s/\.[0]+\Z//g; 16103 if($z) { 16104 $num=~s/(\.[1-9]+)[0]+\Z/$1/g; 16105 } 16106 return $num; 16107} 16108 16109sub get_Report_ChangedConstants($$) 16110{ 16111 my ($TargetSeverity, $Level) = @_; 16112 my $CHANGED_CONSTANTS = ""; 16113 16114 my %ReportMap = (); 16115 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 16116 { 16117 my $Header = $Constants{1}{$Constant}{"Header"}; 16118 if(not $Header) 16119 { # added 16120 $Header = $Constants{2}{$Constant}{"Header"} 16121 } 16122 16123 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 16124 { 16125 if(not defined $CompatRules{$Level}{$Kind}) { 16126 next; 16127 } 16128 if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) { 16129 next; 16130 } 16131 $ReportMap{$Header}{$Constant}{$Kind} = 1; 16132 } 16133 } 16134 16135 if($ReportFormat eq "xml") 16136 { # XML 16137 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16138 { 16139 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n"; 16140 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16141 { 16142 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n"; 16143 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16144 { 16145 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16146 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16147 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}; 16148 16149 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n"; 16150 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n"; 16151 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n"; 16152 if($Overcome) { 16153 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n"; 16154 } 16155 $CHANGED_CONSTANTS .= " </problem>\n"; 16156 } 16157 $CHANGED_CONSTANTS .= " </constant>\n"; 16158 } 16159 $CHANGED_CONSTANTS .= " </header>\n"; 16160 } 16161 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n"; 16162 } 16163 else 16164 { # HTML 16165 my $Number = 0; 16166 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16167 { 16168 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n"; 16169 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16170 { 16171 my $Report = ""; 16172 16173 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16174 { 16175 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind}); 16176 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16177 $Report .= "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n"; 16178 $Number += 1; 16179 } 16180 if($Report) 16181 { 16182 $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n"; 16183 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report; 16184 $Report = insertIDs($Report); 16185 } 16186 $CHANGED_CONSTANTS .= $Report; 16187 } 16188 $CHANGED_CONSTANTS .= "<br/>\n"; 16189 } 16190 if($CHANGED_CONSTANTS) 16191 { 16192 my $Title = "Problems with Constants, $TargetSeverity Severity"; 16193 if($TargetSeverity eq "Safe") 16194 { # Safe Changes 16195 $Title = "Other Changes in Constants"; 16196 } 16197 $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a><h2>$Title ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n"; 16198 } 16199 } 16200 return $CHANGED_CONSTANTS; 16201} 16202 16203sub getTitle($$$) 16204{ 16205 my ($Header, $Library, $NameSpace) = @_; 16206 my $Title = ""; 16207 if($Library and $Library!~/\.\w+\Z/) { 16208 $Library .= " (.$LIB_EXT)"; 16209 } 16210 if($Header and $Library) 16211 { 16212 $Title .= "<span class='h_name'>$Header</span>"; 16213 $Title .= ", <span class='lib_name'>$Library</span><br/>\n"; 16214 } 16215 elsif($Library) { 16216 $Title .= "<span class='lib_name'>$Library</span><br/>\n"; 16217 } 16218 elsif($Header) { 16219 $Title .= "<span class='h_name'>$Header</span><br/>\n"; 16220 } 16221 if($NameSpace) { 16222 $Title .= "<span class='ns'>namespace <b>$NameSpace</b></span><br/>\n"; 16223 } 16224 return $Title; 16225} 16226 16227sub get_Report_Added($) 16228{ 16229 my $Level = $_[0]; 16230 my $ADDED_INTERFACES = ""; 16231 my %ReportMap = (); 16232 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 16233 { 16234 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 16235 { 16236 if($Kind eq "Added_Symbol") 16237 { 16238 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"}; 16239 my $DyLib = $Symbol_Library{2}{$Interface}; 16240 if($Level eq "Source" and $ReportFormat eq "html") 16241 { # do not show library name in HTML report 16242 $DyLib = ""; 16243 } 16244 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1; 16245 } 16246 } 16247 } 16248 if($ReportFormat eq "xml") 16249 { # XML 16250 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16251 { 16252 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16253 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16254 { 16255 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16256 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16257 $ADDED_INTERFACES .= " <name>$Interface</name>\n"; 16258 } 16259 $ADDED_INTERFACES .= " </library>\n"; 16260 } 16261 $ADDED_INTERFACES .= " </header>\n"; 16262 } 16263 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n"; 16264 } 16265 else 16266 { # HTML 16267 my $Added_Number = 0; 16268 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16269 { 16270 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16271 { 16272 my %NameSpaceSymbols = (); 16273 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16274 $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1; 16275 } 16276 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16277 { 16278 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16279 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16280 foreach my $Interface (@SortedInterfaces) 16281 { 16282 $Added_Number += 1; 16283 my $Signature = get_Signature($Interface, 2); 16284 if($NameSpace) { 16285 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16286 } 16287 if($Interface=~/\A(_Z|\?)/) 16288 { 16289 if($Signature) { 16290 $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span><br/><br/>".$ContentDivEnd."\n"); 16291 } 16292 else { 16293 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16294 } 16295 } 16296 else 16297 { 16298 if($Signature) { 16299 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16300 } 16301 else { 16302 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16303 } 16304 } 16305 } 16306 $ADDED_INTERFACES .= "<br/>\n"; 16307 } 16308 } 16309 } 16310 if($ADDED_INTERFACES) 16311 { 16312 my $Anchor = "<a name='Added'></a>"; 16313 if($JoinReport) { 16314 $Anchor = "<a name='".$Level."_Added'></a>"; 16315 } 16316 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n"; 16317 } 16318 } 16319 return $ADDED_INTERFACES; 16320} 16321 16322sub get_Report_Removed($) 16323{ 16324 my $Level = $_[0]; 16325 my $REMOVED_INTERFACES = ""; 16326 my %ReportMap = (); 16327 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16328 { 16329 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16330 { 16331 if($Kind eq "Removed_Symbol") 16332 { 16333 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16334 my $DyLib = $Symbol_Library{1}{$Symbol}; 16335 if($Level eq "Source" and $ReportFormat eq "html") 16336 { # do not show library name in HTML report 16337 $DyLib = ""; 16338 } 16339 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16340 } 16341 } 16342 } 16343 if($ReportFormat eq "xml") 16344 { # XML 16345 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16346 { 16347 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16348 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16349 { 16350 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16351 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16352 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n"; 16353 } 16354 $REMOVED_INTERFACES .= " </library>\n"; 16355 } 16356 $REMOVED_INTERFACES .= " </header>\n"; 16357 } 16358 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n"; 16359 } 16360 else 16361 { # HTML 16362 my $Removed_Number = 0; 16363 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16364 { 16365 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16366 { 16367 my %NameSpaceSymbols = (); 16368 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16369 $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1; 16370 } 16371 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16372 { 16373 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16374 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16375 foreach my $Symbol (@SortedInterfaces) 16376 { 16377 $Removed_Number += 1; 16378 my $SubReport = ""; 16379 my $Signature = get_Signature($Symbol, 1); 16380 if($NameSpace) { 16381 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16382 } 16383 if($Symbol=~/\A(_Z|\?)/) 16384 { 16385 if($Signature) { 16386 $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n"); 16387 } 16388 else { 16389 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16390 } 16391 } 16392 else 16393 { 16394 if($Signature) { 16395 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16396 } 16397 else { 16398 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16399 } 16400 } 16401 } 16402 } 16403 $REMOVED_INTERFACES .= "<br/>\n"; 16404 } 16405 } 16406 if($REMOVED_INTERFACES) 16407 { 16408 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>"; 16409 if($JoinReport) { 16410 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>"; 16411 } 16412 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n"; 16413 } 16414 } 16415 return $REMOVED_INTERFACES; 16416} 16417 16418sub getXmlParams($$) 16419{ 16420 my ($Content, $Problem) = @_; 16421 return "" if(not $Content or not $Problem); 16422 my %XMLparams = (); 16423 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16424 { 16425 my $Macro = "\@".lc($Attr); 16426 if($Content=~/\Q$Macro\E/) { 16427 $XMLparams{lc($Attr)} = $Problem->{$Attr}; 16428 } 16429 } 16430 my @PString = (); 16431 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) { 16432 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\""); 16433 } 16434 if(@PString) { 16435 return " ".join(" ", @PString); 16436 } 16437 else { 16438 return ""; 16439 } 16440} 16441 16442sub addMarkup($) 16443{ 16444 my $Content = $_[0]; 16445 # auto-markup 16446 $Content=~s/\n[ ]*//; # spaces 16447 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size) 16448 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list) 16449 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g; 16450 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ... 16451 if($Content=~/\ANOTE:/) 16452 { # notes 16453 $Content=~s!(NOTE):!<b>$1</b>:!g; 16454 } 16455 else { 16456 $Content=~s!(NOTE):!<br/><b>$1</b>:!g; 16457 } 16458 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters 16459 my @Keywords = ( 16460 "void", 16461 "const", 16462 "static", 16463 "restrict", 16464 "volatile", 16465 "register", 16466 "virtual" 16467 ); 16468 my $MKeys = join("|", @Keywords); 16469 foreach (@Keywords) { 16470 $MKeys .= "|non-".$_; 16471 } 16472 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers 16473 16474 # Markdown 16475 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig; 16476 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig; 16477 return $Content; 16478} 16479 16480sub applyMacroses($$$$) 16481{ 16482 my ($Level, $Kind, $Content, $Problem) = @_; 16483 return "" if(not $Content or not $Problem); 16484 $Problem->{"Word_Size"} = $WORD_SIZE{2}; 16485 $Content = addMarkup($Content); 16486 # macros 16487 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16488 { 16489 my $Macro = "\@".lc($Attr); 16490 my $Value = $Problem->{$Attr}; 16491 if(not defined $Value 16492 or $Value eq "") { 16493 next; 16494 } 16495 if($Value=~/\s\(/ and $Value!~/['"]/) 16496 { # functions 16497 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals 16498 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names 16499 $Value = black_name($Value); 16500 } 16501 elsif($Value=~/\s/) { 16502 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>"; 16503 } 16504 elsif($Value=~/\A\d+\Z/ 16505 and ($Attr eq "Old_Size" or $Attr eq "New_Size")) 16506 { # bits to bytes 16507 if($Value % $BYTE_SIZE) 16508 { # bits 16509 if($Value==1) { 16510 $Value = "<b>".$Value."</b> bit"; 16511 } 16512 else { 16513 $Value = "<b>".$Value."</b> bits"; 16514 } 16515 } 16516 else 16517 { # bytes 16518 $Value /= $BYTE_SIZE; 16519 if($Value==1) { 16520 $Value = "<b>".$Value."</b> byte"; 16521 } 16522 else { 16523 $Value = "<b>".$Value."</b> bytes"; 16524 } 16525 } 16526 } 16527 else 16528 { 16529 $Value = "<b>".htmlSpecChars($Value)."</b>"; 16530 } 16531 $Content=~s/\Q$Macro\E/$Value/g; 16532 } 16533 16534 if($Content=~/(\A|[^\@\w])\@\w/) 16535 { 16536 if(not $IncompleteRules{$Level}{$Kind}) 16537 { # only one warning 16538 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")"); 16539 $IncompleteRules{$Level}{$Kind} = 1; 16540 } 16541 } 16542 return $Content; 16543} 16544 16545sub get_Report_SymbolProblems($$) 16546{ 16547 my ($TargetSeverity, $Level) = @_; 16548 my $INTERFACE_PROBLEMS = ""; 16549 my (%ReportMap, %SymbolChanges) = (); 16550 16551 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16552 { 16553 my ($SN, $SS, $SV) = separate_symbol($Symbol); 16554 if($SV and defined $CompatProblems{$Level}{$SN}) { 16555 next; 16556 } 16557 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16558 { 16559 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols" 16560 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol") 16561 { 16562 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16563 my $DyLib = $Symbol_Library{1}{$Symbol}; 16564 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol}) 16565 { # Symbol with Version 16566 $DyLib = $Symbol_Library{1}{$VSym}; 16567 } 16568 if(not $DyLib) 16569 { # const global data 16570 $DyLib = ""; 16571 } 16572 if($Level eq "Source" and $ReportFormat eq "html") 16573 { # do not show library name in HTML report 16574 $DyLib = ""; 16575 } 16576 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}}; 16577 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16578 { 16579 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16580 if($Severity ne $TargetSeverity) { 16581 delete($SymbolChanges{$Symbol}{$Kind}{$Location}); 16582 } 16583 } 16584 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16585 { 16586 delete($SymbolChanges{$Symbol}{$Kind}); 16587 next; 16588 } 16589 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16590 } 16591 } 16592 if(not keys(%{$SymbolChanges{$Symbol}})) { 16593 delete($SymbolChanges{$Symbol}); 16594 } 16595 } 16596 16597 if($ReportFormat eq "xml") 16598 { # XML 16599 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16600 { 16601 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 16602 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16603 { 16604 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n"; 16605 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$ReportMap{$HeaderName}{$DyLib}}); 16606 foreach my $Symbol (@SortedInterfaces) 16607 { 16608 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n"; 16609 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}})) 16610 { 16611 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16612 { 16613 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 16614 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 16615 16616 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 16617 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16618 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 16619 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16620 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 16621 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 16622 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 16623 } 16624 $INTERFACE_PROBLEMS .= " </problem>\n"; 16625 } 16626 } 16627 $INTERFACE_PROBLEMS .= " </symbol>\n"; 16628 } 16629 $INTERFACE_PROBLEMS .= " </library>\n"; 16630 } 16631 $INTERFACE_PROBLEMS .= " </header>\n"; 16632 } 16633 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n"; 16634 } 16635 else 16636 { # HTML 16637 my $ProblemsNum = 0; 16638 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16639 { 16640 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16641 { 16642 my (%NameSpaceSymbols, %NewSignature) = (); 16643 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16644 $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 16645 } 16646 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16647 { 16648 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace); 16649 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$NameSpaceSymbols{$NameSpace}}); 16650 foreach my $Symbol (@SortedInterfaces) 16651 { 16652 my $Signature = get_Signature($Symbol, 1); 16653 my $SYMBOL_REPORT = ""; 16654 my $ProblemNum = 1; 16655 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}})) 16656 { 16657 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16658 { 16659 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 16660 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 16661 if($Problem{"New_Signature"}) { 16662 $NewSignature{$Symbol} = $Problem{"New_Signature"}; 16663 } 16664 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 16665 { 16666 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 16667 $SYMBOL_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>".$Effect."</td></tr>\n"; 16668 $ProblemNum += 1; 16669 $ProblemsNum += 1; 16670 } 16671 } 16672 } 16673 $ProblemNum -= 1; 16674 if($SYMBOL_REPORT) 16675 { 16676 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> "; 16677 if($Signature) { 16678 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature); 16679 } 16680 else { 16681 $INTERFACE_PROBLEMS .= $Symbol; 16682 } 16683 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n"; 16684 $INTERFACE_PROBLEMS .= $ContentDivStart."\n"; 16685 if($NewSignature{$Symbol}) 16686 { # argument list changed to 16687 $INTERFACE_PROBLEMS .= "\n<span class='new_sign_lbl'>changed to:</span><br/><span class='new_sign'>".highLight_Signature_Italic_Color($NewSignature{$Symbol})."</span><br/>\n"; 16688 } 16689 if($Symbol=~/\A(_Z|\?)/) { 16690 $INTERFACE_PROBLEMS .= "<span class='mangled'>    [symbol: <b>$Symbol</b>]</span><br/>\n"; 16691 } 16692 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n"; 16693 $INTERFACE_PROBLEMS .= $ContentDivEnd; 16694 if($NameSpace) { 16695 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g; 16696 } 16697 } 16698 } 16699 $INTERFACE_PROBLEMS .= "<br/>"; 16700 } 16701 } 16702 } 16703 16704 if($INTERFACE_PROBLEMS) 16705 { 16706 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS); 16707 my $Title = "Problems with Symbols, $TargetSeverity Severity"; 16708 if($TargetSeverity eq "Safe") 16709 { # Safe Changes 16710 $Title = "Other Changes in Symbols"; 16711 } 16712 $INTERFACE_PROBLEMS = "<a name=\'".get_Anchor("Symbol", $Level, $TargetSeverity)."\'></a><a name=\'".get_Anchor("Interface", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$INTERFACE_PROBLEMS.$TOP_REF."<br/>\n"; 16713 } 16714 } 16715 return $INTERFACE_PROBLEMS; 16716} 16717 16718sub get_Report_TypeProblems($$) 16719{ 16720 my ($TargetSeverity, $Level) = @_; 16721 my $TYPE_PROBLEMS = ""; 16722 my (%ReportMap, %TypeChanges) = (); 16723 16724 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 16725 { 16726 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 16727 { 16728 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 16729 { 16730 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 16731 { 16732 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; 16733 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; 16734 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16735 16736 if($Severity eq "Safe" 16737 and $TargetSeverity ne "Safe") { 16738 next; 16739 } 16740 16741 if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}) 16742 { 16743 if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 16744 { # select a problem with the highest priority 16745 next; 16746 } 16747 } 16748 16749 $TypeChanges{$TypeName}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; 16750 } 16751 } 16752 } 16753 } 16754 16755 my %Kinds_Locations = (); 16756 foreach my $TypeName (keys(%TypeChanges)) 16757 { 16758 my %Kind_Target = (); 16759 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}})) 16760 { 16761 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16762 { 16763 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16764 if($Severity ne $TargetSeverity) 16765 { # other priority 16766 delete($TypeChanges{$TypeName}{$Kind}{$Location}); 16767 next; 16768 } 16769 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1; 16770 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"}; 16771 if($Kind_Target{$Kind}{$Target}) 16772 { # duplicate target 16773 delete($TypeChanges{$TypeName}{$Kind}{$Location}); 16774 next; 16775 } 16776 $Kind_Target{$Kind}{$Target} = 1; 16777 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"}; 16778 $ReportMap{$HeaderName}{$TypeName} = 1; 16779 } 16780 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) { 16781 delete($TypeChanges{$TypeName}{$Kind}); 16782 } 16783 } 16784 if(not keys(%{$TypeChanges{$TypeName}})) { 16785 delete($TypeChanges{$TypeName}); 16786 } 16787 } 16788 16789 my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}}); 16790 if($ReportFormat eq "xml") 16791 { # XML 16792 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16793 { 16794 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 16795 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) 16796 { 16797 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n"; 16798 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) 16799 { 16800 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16801 { 16802 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; 16803 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 16804 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16805 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 16806 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16807 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 16808 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 16809 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 16810 } 16811 $TYPE_PROBLEMS .= " </problem>\n"; 16812 } 16813 } 16814 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); 16815 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { 16816 $TYPE_PROBLEMS .= showVTables($TypeName); 16817 } 16818 $TYPE_PROBLEMS .= " </type>\n"; 16819 } 16820 $TYPE_PROBLEMS .= " </header>\n"; 16821 } 16822 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n"; 16823 } 16824 else 16825 { # HTML 16826 my $ProblemsNum = 0; 16827 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16828 { 16829 my (%NameSpace_Type) = (); 16830 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) { 16831 $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1; 16832 } 16833 foreach my $NameSpace (sort keys(%NameSpace_Type)) 16834 { 16835 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace); 16836 my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}}); 16837 foreach my $TypeName (@SortedTypes) 16838 { 16839 my $ProblemNum = 1; 16840 my $TYPE_REPORT = ""; 16841 16842 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) 16843 { 16844 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16845 { 16846 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; 16847 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 16848 { 16849 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 16850 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n"; 16851 $ProblemNum += 1; 16852 $ProblemsNum += 1; 16853 } 16854 } 16855 } 16856 $ProblemNum -= 1; 16857 if($TYPE_REPORT) 16858 { 16859 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); 16860 my $ShowVTables = ""; 16861 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { 16862 $ShowVTables = showVTables($TypeName); 16863 } 16864 16865 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ".show_Type($TypeName, 1, 1)." ($ProblemNum)".$ContentSpanEnd; 16866 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n"; 16867 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n"; 16868 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n"; 16869 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n"; 16870 if($NameSpace) { 16871 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g; 16872 } 16873 } 16874 } 16875 $TYPE_PROBLEMS .= "<br/>"; 16876 } 16877 } 16878 16879 if($TYPE_PROBLEMS) 16880 { 16881 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS); 16882 my $Title = "Problems with Data Types, $TargetSeverity Severity"; 16883 if($TargetSeverity eq "Safe") 16884 { # Safe Changes 16885 $Title = "Other Changes in Data Types"; 16886 } 16887 $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n"; 16888 } 16889 } 16890 return $TYPE_PROBLEMS; 16891} 16892 16893sub show_Type($$$) 16894{ 16895 my ($Name, $Html, $LibVersion) = @_; 16896 my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"}; 16897 $TType = lc($TType); 16898 if($TType=~/struct|union|enum/) { 16899 $Name=~s/\A\Q$TType\E //g; 16900 } 16901 if($Html) { 16902 $Name = "<span class='ttype'>".$TType."</span> ".htmlSpecChars($Name); 16903 } 16904 else { 16905 $Name = $TType." ".$Name; 16906 } 16907 return $Name; 16908} 16909 16910sub get_Anchor($$$) 16911{ 16912 my ($Kind, $Level, $Severity) = @_; 16913 if($JoinReport) 16914 { 16915 if($Severity eq "Safe") { 16916 return "Other_".$Level."_Changes_In_".$Kind."s"; 16917 } 16918 else { 16919 return $Kind."_".$Level."_Problems_".$Severity; 16920 } 16921 } 16922 else 16923 { 16924 if($Severity eq "Safe") { 16925 return "Other_Changes_In_".$Kind."s"; 16926 } 16927 else { 16928 return $Kind."_Problems_".$Severity; 16929 } 16930 } 16931} 16932 16933sub showVTables($) 16934{ 16935 my $TypeName = $_[0]; 16936 my $TypeId1 = $TName_Tid{1}{$TypeName}; 16937 my %Type1 = get_Type($TypeId1, 1); 16938 if(defined $Type1{"VTable"} 16939 and keys(%{$Type1{"VTable"}})) 16940 { 16941 my $TypeId2 = $TName_Tid{2}{$TypeName}; 16942 my %Type2 = get_Type($TypeId2, 2); 16943 if(defined $Type2{"VTable"} 16944 and keys(%{$Type2{"VTable"}})) 16945 { 16946 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}})); 16947 my %Entries = (); 16948 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes))) 16949 { 16950 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index}); 16951 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index}); 16952 } 16953 my $VTABLES = ""; 16954 if($ReportFormat eq "xml") 16955 { # XML 16956 $VTABLES .= " <vtable>\n"; 16957 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 16958 { 16959 $VTABLES .= " <entry offset=\"".$Index."\">\n"; 16960 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n"; 16961 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n"; 16962 $VTABLES .= " </entry>\n"; 16963 } 16964 $VTABLES .= " </vtable>\n\n"; 16965 } 16966 else 16967 { # HTML 16968 $VTABLES .= "<table class='vtable'>"; 16969 $VTABLES .= "<tr><th>Offset</th>"; 16970 $VTABLES .= "<th>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>"; 16971 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>"; 16972 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 16973 { 16974 my ($Color1, $Color2) = ("", ""); 16975 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"}) 16976 { 16977 if($Entries{$Index}{"E1"}) 16978 { 16979 $Color1 = " class='failed'"; 16980 $Color2 = " class='failed'"; 16981 } 16982 else { 16983 $Color2 = " class='warning'"; 16984 } 16985 } 16986 $VTABLES .= "<tr><th>".$Index."</th>\n"; 16987 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n"; 16988 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n"; 16989 } 16990 $VTABLES .= "</table><br/>\n"; 16991 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd; 16992 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES; 16993 } 16994 return $VTABLES; 16995 } 16996 } 16997 return ""; 16998} 16999 17000sub simpleVEntry($) 17001{ 17002 my $VEntry = $_[0]; 17003 if(not defined $VEntry 17004 or $VEntry eq "") { 17005 return ""; 17006 } 17007 17008 $VEntry=~s/ \[.+?\]\Z//; # support for ABI Dumper 17009 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks 17010 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo 17011 if($VEntry=~/\A_ZThn.+\Z/) { 17012 $VEntry = "non-virtual thunk"; 17013 } 17014 $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i; 17015 # support for old GCC versions 17016 $VEntry=~s/\A0u\Z/(int (*)(...))0/; 17017 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/; 17018 $VEntry=~s/\A&_Z\Z/& _Z/; 17019 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors 17020 return $VEntry; 17021} 17022 17023sub adjustParamPos($$$) 17024{ 17025 my ($Pos, $Symbol, $LibVersion) = @_; 17026 if(defined $CompleteSignature{$LibVersion}{$Symbol}) 17027 { 17028 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"} 17029 and $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 17030 { 17031 return $Pos-1; 17032 } 17033 17034 return $Pos; 17035 } 17036 17037 return undef; 17038} 17039 17040sub getParamPos($$$) 17041{ 17042 my ($Name, $Symbol, $LibVersion) = @_; 17043 17044 if(defined $CompleteSignature{$LibVersion}{$Symbol} 17045 and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}) 17046 { 17047 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17048 foreach (keys(%{$Info->{"Param"}})) 17049 { 17050 if($Info->{"Param"}{$_}{"name"} eq $Name) 17051 { 17052 return $_; 17053 } 17054 } 17055 } 17056 17057 return undef; 17058} 17059 17060sub getParamName($) 17061{ 17062 my $Loc = $_[0]; 17063 $Loc=~s/\->.*//g; 17064 return $Loc; 17065} 17066 17067sub getAffectedSymbols($$$$) 17068{ 17069 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_; 17070 my $LIMIT = 10; 17071 17072 if(defined $AffectLimit) 17073 { 17074 $LIMIT = $AffectLimit; 17075 } 17076 17077 my %SymSel = (); 17078 my %SymLocKind = (); 17079 17080 foreach my $Symbol (@{$Syms}) 17081 { 17082 if(index($Symbol, "_Z")==0 17083 and $Symbol=~/(C2|D2|D0)[EI]/) 17084 { # duplicated problems for C2 constructors, D2 and D0 destructors 17085 next; 17086 } 17087 17088 foreach my $Kind (sort keys(%{$Kinds_Locations})) 17089 { 17090 if(not defined $CompatProblems{$Level}{$Symbol} 17091 or not defined $CompatProblems{$Level}{$Symbol}{$Kind}) { 17092 next; 17093 } 17094 17095 foreach my $Loc (sort keys(%{$Kinds_Locations->{$Kind}})) 17096 { 17097 if(not defined $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}) { 17098 next; 17099 } 17100 17101 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17102 if($Level eq "Source") 17103 { # remove symbol version 17104 $Symbol = $SN; 17105 } 17106 17107 if($SV and defined $CompatProblems{$Level}{$SN} 17108 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Loc}) 17109 { # duplicated problems for versioned symbols 17110 next; 17111 } 17112 17113 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}{"Type_Name"}; 17114 if($Type_Name ne $Target_TypeName) { 17115 next; 17116 } 17117 17118 $SymLocKind{$Symbol}{$Loc}{$Kind} = 1; 17119 } 17120 } 17121 } 17122 17123 foreach my $Symbol (sort keys(%SymLocKind)) 17124 { 17125 LOOP: foreach my $Loc (sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$SymLocKind{$Symbol}})) 17126 { 17127 foreach my $Kind (keys(%{$SymLocKind{$Symbol}{$Loc}})) 17128 { 17129 $SymSel{$Symbol}{"Loc"} = $Loc; 17130 $SymSel{$Symbol}{"Kind"} = $Kind; 17131 17132 last LOOP; 17133 } 17134 } 17135 } 17136 17137 my $Affected = ""; 17138 my $Num = 0; 17139 17140 if($ReportFormat eq "xml") 17141 { # XML 17142 $Affected .= " <affected>\n"; 17143 17144 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17145 { 17146 my $PName = getParamName($Loc); 17147 my $Desc = getAffectDesc($Level, $Symbol, $SymSel{$Symbol}{"Kind"}, $SymSel{$Symbol}{"Loc"}); 17148 17149 my $Target = ""; 17150 if($PName) 17151 { 17152 $Target .= " param=\"$PName\""; 17153 $Desc=~s/parameter $PName /parameter \@param /; 17154 } 17155 elsif($Loc=~/\Aretval(\-|\Z)/i) { 17156 $Target .= " affected=\"retval\""; 17157 } 17158 elsif($Loc=~/\Athis(\-|\Z)/i) { 17159 $Target .= " affected=\"this\""; 17160 } 17161 17162 if($Desc=~s/\AField ([^\s]+) /Field \@field /) { 17163 $Target .= " field=\"$1\""; 17164 } 17165 17166 $Affected .= " <symbol name=\"$Symbol\"$Target>\n"; 17167 $Affected .= " <comment>".xmlSpecChars($Desc)."</comment>\n"; 17168 $Affected .= " </symbol>\n"; 17169 17170 if($Num>$LIMIT) { 17171 last LOOP; 17172 } 17173 17174 $Num += 1; 17175 } 17176 $Affected .= " </affected>\n"; 17177 } 17178 else 17179 { # HTML 17180 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17181 { 17182 my $Desc = getAffectDesc($Level, $Symbol, $SymSel{$Symbol}{"Kind"}, $SymSel{$Symbol}{"Loc"}); 17183 my $S = get_Signature($Symbol, 1); 17184 my $PName = getParamName($SymSel{$Symbol}{"Loc"});print "$Symbol\n" if($Symbol eq "sftp_file_set_blocking"); 17185 my $Pos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1); 17186 17187 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($S, $Pos, 1, 0, 0)."</span><br/>"; 17188 $Affected .= "<div class='affect'>".htmlSpecChars($Desc)."</div>\n"; 17189 17190 if($Num>$LIMIT) { 17191 last; 17192 } 17193 17194 $Num += 1; 17195 } 17196 17197 if(keys(%SymSel)>$LIMIT) { 17198 $Affected .= " ...<br/>"; # and others ... 17199 } 17200 17201 $Affected = "<div class='affected'>".$Affected."</div>"; 17202 if($Affected) 17203 { 17204 $Affected = $ContentDivStart.$Affected.$ContentDivEnd; 17205 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".keys(%SymSel).")".$ContentSpanEnd.$Affected; 17206 } 17207 } 17208 17209 return $Affected; 17210} 17211 17212sub cmpLocations($$) 17213{ 17214 my ($L1, $L2) = @_; 17215 if($L2=~/\A(retval|this)\b/ 17216 and $L1!~/\A(retval|this)\b/) 17217 { 17218 if($L1!~/\-\>/) { 17219 return 1; 17220 } 17221 elsif($L2=~/\-\>/) { 17222 return 1; 17223 } 17224 } 17225 return 0; 17226} 17227 17228sub getAffectDesc($$$$) 17229{ 17230 my ($Level, $Symbol, $Kind, $Location) = @_; 17231 17232 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}}; 17233 17234 my $Location_I = $Location; 17235 $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field 17236 17237 my @Sentence = (); 17238 17239 if($Kind eq "Overridden_Virtual_Method" 17240 or $Kind eq "Overridden_Virtual_Method_B") { 17241 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method."); 17242 } 17243 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 17244 { 17245 my %SymInfo = %{$CompleteSignature{1}{$Symbol}}; 17246 17247 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/) 17248 { 17249 my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method"; 17250 my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"}; 17251 17252 if($ClassName eq $Problem{"Type_Name"}) { 17253 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class."); 17254 } 17255 else { 17256 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'."); 17257 } 17258 } 17259 else 17260 { 17261 my $TypeID = undef; 17262 17263 if($Location=~/retval/) 17264 { # return value 17265 if(index($Location, "->")!=-1) { 17266 push(@Sentence, "Field \'".$Location."\' in return value"); 17267 } 17268 else { 17269 push(@Sentence, "Return value"); 17270 } 17271 17272 $TypeID = $SymInfo{"Return"}; 17273 } 17274 elsif($Location=~/this/) 17275 { # "this" pointer 17276 if(index($Location, "->")!=-1) { 17277 push(@Sentence, "Field \'".$Location."\' in the object of this method"); 17278 } 17279 else { 17280 push(@Sentence, "\'this\' pointer"); 17281 } 17282 17283 $TypeID = $SymInfo{"Class"}; 17284 } 17285 else 17286 { # parameters 17287 17288 my $PName = getParamName($Location); 17289 my $PPos = getParamPos($PName, $Symbol, 1); 17290 17291 if(index($Location, "->")!=-1) { 17292 push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17293 } 17294 else { 17295 push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17296 } 17297 if($PName) { 17298 push(@Sentence, "\'".$PName."\'"); 17299 } 17300 17301 $TypeID = $SymInfo{"Param"}{$PPos}{"type"}; 17302 } 17303 17304 if($Location!~/this/) 17305 { 17306 if(my %PureType = get_PureType($TypeID, $TypeInfo{1})) 17307 { 17308 if($PureType{"Type"} eq "Pointer") { 17309 push(@Sentence, "(pointer)"); 17310 } 17311 elsif($PureType{"Type"} eq "Ref") { 17312 push(@Sentence, "(reference)"); 17313 } 17314 } 17315 } 17316 17317 if($Location eq "this") { 17318 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17319 } 17320 else 17321 { 17322 my $Location_T = $Location; 17323 $Location_T=~s/\A\w+(\->|\Z)//; # location in type 17324 17325 my $TypeID_Problem = $TypeID; 17326 if($Location_T) { 17327 $TypeID_Problem = getFieldType($Location_T, $TypeID, 1); 17328 } 17329 17330 if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) { 17331 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); 17332 } 17333 else { 17334 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17335 } 17336 } 17337 } 17338 } 17339 if($ExtendedSymbols{$Symbol}) { 17340 push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling."); 17341 } 17342 17343 my $Sent = join(" ", @Sentence); 17344 17345 $Sent=~s/->/./g; 17346 17347 if($ReportFormat eq "xml") 17348 { 17349 $Sent=~s/'//g; 17350 } 17351 17352 return $Sent; 17353} 17354 17355sub getFieldType($$$) 17356{ 17357 my ($Location, $TypeId, $LibVersion) = @_; 17358 17359 my @Fields = split(/\->/, $Location); 17360 17361 foreach my $Name (@Fields) 17362 { 17363 my %Info = get_BaseType($TypeId, $LibVersion); 17364 17365 foreach my $Pos (keys(%{$Info{"Memb"}})) 17366 { 17367 if($Info{"Memb"}{$Pos}{"name"} eq $Name) 17368 { 17369 $TypeId = $Info{"Memb"}{$Pos}{"type"}; 17370 last; 17371 } 17372 } 17373 } 17374 17375 return $TypeId; 17376} 17377 17378sub get_XmlSign($$) 17379{ 17380 my ($Symbol, $LibVersion) = @_; 17381 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17382 my $Report = ""; 17383 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}})) 17384 { 17385 my $Name = $Info->{"Param"}{$Pos}{"name"}; 17386 my $Type = $Info->{"Param"}{$Pos}{"type"}; 17387 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"}; 17388 foreach my $Typedef (keys(%ChangedTypedef)) 17389 { 17390 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 17391 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g; 17392 } 17393 } 17394 $Report .= " <param pos=\"$Pos\">\n"; 17395 $Report .= " <name>".$Name."</name>\n"; 17396 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n"; 17397 $Report .= " </param>\n"; 17398 } 17399 if(my $Return = $Info->{"Return"}) 17400 { 17401 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"}; 17402 $Report .= " <retval>\n"; 17403 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n"; 17404 $Report .= " </retval>\n"; 17405 } 17406 return $Report; 17407} 17408 17409sub get_Report_SymbolsInfo($) 17410{ 17411 my $Level = $_[0]; 17412 my $Report = "<symbols_info>\n"; 17413 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 17414 { 17415 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17416 if($SV and defined $CompatProblems{$Level}{$SN}) { 17417 next; 17418 } 17419 $Report .= " <symbol name=\"$Symbol\">\n"; 17420 my ($S1, $P1, $S2, $P2) = (); 17421 if(not $AddedInt{$Level}{$Symbol}) 17422 { 17423 if(defined $CompleteSignature{1}{$Symbol} 17424 and defined $CompleteSignature{1}{$Symbol}{"Header"}) 17425 { 17426 $P1 = get_XmlSign($Symbol, 1); 17427 $S1 = get_Signature($Symbol, 1); 17428 } 17429 elsif($Symbol=~/\A(_Z|\?)/) { 17430 $S1 = $tr_name{$Symbol}; 17431 } 17432 } 17433 if(not $RemovedInt{$Level}{$Symbol}) 17434 { 17435 if(defined $CompleteSignature{2}{$Symbol} 17436 and defined $CompleteSignature{2}{$Symbol}{"Header"}) 17437 { 17438 $P2 = get_XmlSign($Symbol, 2); 17439 $S2 = get_Signature($Symbol, 2); 17440 } 17441 elsif($Symbol=~/\A(_Z|\?)/) { 17442 $S2 = $tr_name{$Symbol}; 17443 } 17444 } 17445 if($S1) 17446 { 17447 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n"; 17448 $Report .= $P1; 17449 $Report .= " </old>\n"; 17450 } 17451 if($S2 and $S2 ne $S1) 17452 { 17453 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n"; 17454 $Report .= $P2; 17455 $Report .= " </new>\n"; 17456 } 17457 $Report .= " </symbol>\n"; 17458 } 17459 $Report .= "</symbols_info>\n"; 17460 return $Report; 17461} 17462 17463sub writeReport($$) 17464{ 17465 my ($Level, $Report) = @_; 17466 if($ReportFormat eq "xml") { 17467 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report; 17468 } 17469 if($StdOut) 17470 { # --stdout option 17471 print STDOUT $Report; 17472 } 17473 else 17474 { 17475 my $RPath = getReportPath($Level); 17476 mkpath(get_dirname($RPath)); 17477 17478 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n"); 17479 print REPORT $Report; 17480 close(REPORT); 17481 } 17482} 17483 17484sub getReport($) 17485{ 17486 my $Level = $_[0]; 17487 if($ReportFormat eq "xml") 17488 { # XML 17489 if($Level eq "Join") 17490 { 17491 my $Report = "<reports>\n"; 17492 $Report .= getReport("Binary"); 17493 $Report .= getReport("Source"); 17494 $Report .= "</reports>\n"; 17495 return $Report; 17496 } 17497 else 17498 { 17499 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n"; 17500 my ($Summary, $MetaData) = get_Summary($Level); 17501 $Report .= $Summary."\n"; 17502 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17503 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17504 17505 # additional symbols info (if needed) 17506 # $Report .= get_Report_SymbolsInfo($Level); 17507 17508 $Report .= "</report>\n"; 17509 return $Report; 17510 } 17511 } 17512 else 17513 { # HTML 17514 my $CssStyles = readModule("Styles", "Report.css"); 17515 my $JScripts = readModule("Scripts", "Sections.js"); 17516 if($Level eq "Join") 17517 { 17518 $CssStyles .= "\n".readModule("Styles", "Tabs.css"); 17519 $JScripts .= "\n".readModule("Scripts", "Tabs.js"); 17520 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report"; 17521 my $Keywords = $TargetTitle.", compatibility, API, report"; 17522 my $Description = "Compatibility report for the $TargetTitle $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17523 my ($BSummary, $BMetaData) = get_Summary("Binary"); 17524 my ($SSummary, $SMetaData) = get_Summary("Source"); 17525 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>"; 17526 $Report .= get_Report_Title("Join")." 17527 <br/><div class='tabset'> 17528 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a> 17529 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a> 17530 </div>"; 17531 $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>"; 17532 $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>"; 17533 $Report .= getReportFooter($TargetTitle, not $JoinReport); 17534 $Report .= "\n</body></html>\n"; 17535 return $Report; 17536 } 17537 else 17538 { 17539 my ($Summary, $MetaData) = get_Summary($Level); 17540 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report"; 17541 my $Keywords = $TargetTitle.", ".lc($Level)." compatibility, API, report"; 17542 my $Description = "$Level compatibility report for the ".$TargetTitle." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17543 if($Level eq "Binary") 17544 { 17545 if(getArch(1) eq getArch(2) 17546 and getArch(1) ne "unknown") { 17547 $Description .= " on ".showArch(getArch(1)); 17548 } 17549 } 17550 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n"; 17551 $Report .= get_Report_Title($Level)."\n".$Summary."\n"; 17552 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17553 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17554 $Report .= get_SourceInfo(); 17555 $Report .= "</div>\n<br/><br/><br/><hr/>\n"; 17556 $Report .= getReportFooter($TargetTitle, not $JoinReport); 17557 $Report .= "\n</body></html>\n"; 17558 return $Report; 17559 } 17560 } 17561} 17562 17563sub getLegend() 17564{ 17565 return "<br/> 17566<table class='summary'> 17567<tr> 17568 <td class='new'>added</td> 17569 <td class='passed'>compatible</td> 17570</tr> 17571<tr> 17572 <td class='warning'>warning</td> 17573 <td class='failed'>incompatible</td> 17574</tr></table>\n"; 17575} 17576 17577sub createReport() 17578{ 17579 if($JoinReport) 17580 { # --stdout 17581 writeReport("Join", getReport("Join")); 17582 } 17583 elsif($DoubleReport) 17584 { # default 17585 writeReport("Binary", getReport("Binary")); 17586 writeReport("Source", getReport("Source")); 17587 } 17588 elsif($BinaryOnly) 17589 { # --binary 17590 writeReport("Binary", getReport("Binary")); 17591 } 17592 elsif($SourceOnly) 17593 { # --source 17594 writeReport("Source", getReport("Source")); 17595 } 17596} 17597 17598sub getReportFooter($$) 17599{ 17600 my ($LibName, $Single) = @_; 17601 my $Class = "footer"; 17602 if(not $Single) { 17603 $Class .= " double_report"; 17604 } 17605 my $Footer = "<div class=\'$Class\' align='right'><i>Generated on ".(localtime time); 17606 $Footer .= " by <a href='".$HomePage."'>ABI Compliance Checker</a> $TOOL_VERSION  "; 17607 $Footer .= "</i></div>"; 17608 $Footer .= "<br/>"; 17609 return $Footer; 17610} 17611 17612sub get_Report_Problems($$) 17613{ 17614 my ($Severity, $Level) = @_; 17615 17616 my $Report = get_Report_TypeProblems($Severity, $Level); 17617 if(my $SProblems = get_Report_SymbolProblems($Severity, $Level)) { 17618 $Report .= $SProblems; 17619 } 17620 17621 if($Severity eq "Low" or $Severity eq "Safe") { 17622 $Report .= get_Report_ChangedConstants($Severity, $Level); 17623 } 17624 17625 if($ReportFormat eq "html") 17626 { 17627 if($Report) 17628 { # add anchor 17629 if($JoinReport) 17630 { 17631 if($Severity eq "Safe") { 17632 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report; 17633 } 17634 else { 17635 $Report = "<a name=\'".$Severity."_Risk_".$Level."_Problems\'></a>".$Report; 17636 } 17637 } 17638 else 17639 { 17640 if($Severity eq "Safe") { 17641 $Report = "<a name=\'Other_Changes\'></a>".$Report; 17642 } 17643 else { 17644 $Report = "<a name=\'".$Severity."_Risk_Problems\'></a>".$Report; 17645 } 17646 } 17647 } 17648 } 17649 return $Report; 17650} 17651 17652sub composeHTML_Head($$$$$) 17653{ 17654 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_; 17655 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> 17656 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"> 17657 <head> 17658 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> 17659 <meta name=\"keywords\" content=\"$Keywords\" /> 17660 <meta name=\"description\" content=\"$Description\" /> 17661 <title> 17662 $Title 17663 </title> 17664 <style type=\"text/css\"> 17665 $Styles 17666 </style> 17667 <script type=\"text/javascript\" language=\"JavaScript\"> 17668 <!-- 17669 $Scripts 17670 --> 17671 </script> 17672 </head>"; 17673} 17674 17675sub insertIDs($) 17676{ 17677 my $Text = $_[0]; 17678 while($Text=~/CONTENT_ID/) 17679 { 17680 if(int($Content_Counter)%2) { 17681 $ContentID -= 1; 17682 } 17683 $Text=~s/CONTENT_ID/c_$ContentID/; 17684 $ContentID += 1; 17685 $Content_Counter += 1; 17686 } 17687 return $Text; 17688} 17689 17690sub checkPreprocessedUnit($) 17691{ 17692 my $Path = $_[0]; 17693 my ($CurHeader, $CurHeaderName) = ("", ""); 17694 my $CurClass = ""; # extra info 17695 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n"); 17696 17697 while(my $Line = <PREPROC>) 17698 { # detecting public and private constants 17699 if(substr($Line, 0, 1) eq "#") 17700 { 17701 chomp($Line); 17702 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/) 17703 { 17704 $CurHeader = path_format($1, $OSgroup); 17705 $CurHeaderName = get_filename($CurHeader); 17706 $CurClass = ""; 17707 17708 if(index($CurHeader, $TMP_DIR)==0) { 17709 next; 17710 } 17711 17712 if(substr($CurHeaderName, 0, 1) eq "<") 17713 { # <built-in>, <command-line>, etc. 17714 $CurHeaderName = ""; 17715 $CurHeader = ""; 17716 } 17717 17718 if($ExtraInfo) 17719 { 17720 if($CurHeaderName) { 17721 $PreprocessedHeaders{$Version}{$CurHeader} = 1; 17722 } 17723 } 17724 } 17725 if(not $ExtraDump) 17726 { 17727 if($CurHeaderName) 17728 { 17729 if(not $Include_Neighbors{$Version}{$CurHeaderName} 17730 and not $Registered_Headers{$Version}{$CurHeader}) 17731 { # not a target 17732 next; 17733 } 17734 if(not is_target_header($CurHeaderName, 1) 17735 and not is_target_header($CurHeaderName, 2)) 17736 { # user-defined header 17737 next; 17738 } 17739 } 17740 } 17741 17742 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/) 17743 { 17744 my ($Name, $Value) = ($1, $2); 17745 if(not $Constants{$Version}{$Name}{"Access"}) 17746 { 17747 $Constants{$Version}{$Name}{"Access"} = "public"; 17748 $Constants{$Version}{$Name}{"Value"} = $Value; 17749 if($CurHeaderName) { 17750 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName; 17751 } 17752 } 17753 } 17754 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) { 17755 $Constants{$Version}{$1}{"Access"} = "private"; 17756 } 17757 } 17758 else 17759 { 17760 if(defined $ExtraDump) 17761 { 17762 if($Line=~/(\w+)\s*\(/) 17763 { # functions 17764 $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 17765 } 17766 #elsif($Line=~/(\w+)\s*;/) 17767 #{ # data 17768 # $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 17769 #} 17770 elsif($Line=~/(\A|\s)class\s+(\w+)/) { 17771 $CurClass = $2; 17772 } 17773 } 17774 } 17775 } 17776 close(PREPROC); 17777 foreach my $Constant (keys(%{$Constants{$Version}})) 17778 { 17779 if($Constants{$Version}{$Constant}{"Access"} eq "private") 17780 { 17781 delete($Constants{$Version}{$Constant}); 17782 next; 17783 } 17784 if(not $ExtraDump and ($Constant=~/_h\Z/i 17785 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) 17786 { # skip 17787 delete($Constants{$Version}{$Constant}); 17788 } 17789 else { 17790 delete($Constants{$Version}{$Constant}{"Access"}); 17791 } 17792 } 17793 if($Debug) 17794 { 17795 mkpath($DEBUG_PATH{$Version}); 17796 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt"); 17797 } 17798} 17799 17800sub uncoverConstant($$) 17801{ 17802 my ($LibVersion, $Constant) = @_; 17803 return "" if(not $LibVersion or not $Constant); 17804 return $Constant if(isCyclical(\@RecurConstant, $Constant)); 17805 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) { 17806 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant}; 17807 } 17808 17809 if(defined $Constants{$LibVersion}{$Constant}) 17810 { 17811 my $Value = $Constants{$LibVersion}{$Constant}{"Value"}; 17812 if(defined $Constants{$LibVersion}{$Value}) 17813 { 17814 push(@RecurConstant, $Constant); 17815 my $Uncovered = uncoverConstant($LibVersion, $Value); 17816 if($Uncovered ne "") { 17817 $Value = $Uncovered; 17818 } 17819 pop(@RecurConstant); 17820 } 17821 17822 # FIXME: uncover $Value using all the enum constants 17823 # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define) 17824 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value); 17825 } 17826 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = ""); 17827} 17828 17829sub simpleConstant($$) 17830{ 17831 my ($LibVersion, $Value) = @_; 17832 if($Value=~/\W/) 17833 { 17834 my $Value_Copy = $Value; 17835 while($Value_Copy=~s/([a-z_]\w+)/\@/i) 17836 { 17837 my $Word = $1; 17838 if($Value!~/$Word\s*\(/) 17839 { 17840 my $Val = uncoverConstant($LibVersion, $Word); 17841 if($Val ne "") 17842 { 17843 $Value=~s/\b$Word\b/$Val/g; 17844 } 17845 } 17846 } 17847 } 17848 return $Value; 17849} 17850 17851sub computeValue($) 17852{ 17853 my $Value = $_[0]; 17854 17855 if($Value=~/\A\((-?[\d]+)\)\Z/) { 17856 return $1; 17857 } 17858 17859 if($Value=~/\A[\d\-\+()]+\Z/) { 17860 return eval($Value); 17861 } 17862 17863 return $Value; 17864} 17865 17866my %IgnoreConstant = map {$_=>1} ( 17867 "VERSION", 17868 "VERSIONCODE", 17869 "VERNUM", 17870 "VERS_INFO", 17871 "PATCHLEVEL", 17872 "INSTALLPREFIX", 17873 "VBUILD", 17874 "VPATCH", 17875 "VMINOR", 17876 "BUILD_STRING", 17877 "BUILD_TIME", 17878 "PACKAGE_STRING", 17879 "PRODUCTION", 17880 "CONFIGURE_COMMAND", 17881 "INSTALLDIR", 17882 "BINDIR", 17883 "CONFIG_FILE_PATH", 17884 "DATADIR", 17885 "EXTENSION_DIR", 17886 "INCLUDE_PATH", 17887 "LIBDIR", 17888 "LOCALSTATEDIR", 17889 "SBINDIR", 17890 "SYSCONFDIR", 17891 "RELEASE", 17892 "SOURCE_ID", 17893 "SUBMINOR", 17894 "MINOR", 17895 "MINNOR", 17896 "MINORVERSION", 17897 "MAJOR", 17898 "MAJORVERSION", 17899 "MICRO", 17900 "MICROVERSION", 17901 "BINARY_AGE", 17902 "INTERFACE_AGE", 17903 "CORE_ABI", 17904 "PATCH", 17905 "COPYRIGHT", 17906 "TIMESTAMP", 17907 "REVISION", 17908 "PACKAGE_TAG", 17909 "PACKAGEDATE", 17910 "NUMVERSION", 17911 "Release", 17912 "Version" 17913); 17914 17915sub constantFilter($$$) 17916{ 17917 my ($Name, $Value, $Level) = @_; 17918 17919 if($Level eq "Binary") 17920 { 17921 if($Name=~/_t\Z/) 17922 { # __malloc_ptr_t 17923 return 1; 17924 } 17925 foreach (keys(%IgnoreConstant)) 17926 { 17927 if($Name=~/(\A|_)$_(_|\Z)/) 17928 { # version 17929 return 1; 17930 } 17931 if(/\A[A-Z].*[a-z]\Z/) 17932 { 17933 if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/) 17934 { # version 17935 return 1; 17936 } 17937 } 17938 } 17939 if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i) 17940 { # version 17941 return 1; 17942 } 17943 if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/) 17944 { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ... 17945 return 1; 17946 } 17947 17948 if($Value=~/\A["'].*['"]/i) 17949 { # string 17950 return 0; 17951 } 17952 17953 if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i) 17954 { # static int gcry_pth_init 17955 # extern ABC 17956 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE... 17957 # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ... 17958 return 1; 17959 } 17960 if($Value=~/\w+\s*\(/i) 17961 { # foo(p) 17962 return 1; 17963 } 17964 if($Value=~/\A[a-z_]+\w*\Z/i) 17965 { # asn1_node_st 17966 # __SMTH_P 17967 return 1; 17968 } 17969 } 17970 17971 return 0; 17972} 17973 17974sub mergeConstants($) 17975{ 17976 my $Level = $_[0]; 17977 foreach my $Constant (keys(%{$Constants{1}})) 17978 { 17979 if($SkipConstants{1}{$Constant}) 17980 { # skipped by the user 17981 next; 17982 } 17983 17984 if(my $Header = $Constants{1}{$Constant}{"Header"}) 17985 { 17986 if(not is_target_header($Header, 1) 17987 and not is_target_header($Header, 2)) 17988 { # user-defined header 17989 next; 17990 } 17991 } 17992 else { 17993 next; 17994 } 17995 17996 my $Old_Value = uncoverConstant(1, $Constant); 17997 17998 if(constantFilter($Constant, $Old_Value, $Level)) 17999 { # separate binary and source problems 18000 next; 18001 } 18002 18003 if(not defined $Constants{2}{$Constant}{"Value"}) 18004 { # removed 18005 %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = ( 18006 "Target"=>$Constant, 18007 "Old_Value"=>$Old_Value ); 18008 next; 18009 } 18010 18011 if($Constants{2}{$Constant}{"Value"} eq "") 18012 { # empty value 18013 # TODO: implement a rule 18014 next; 18015 } 18016 18017 my $New_Value = uncoverConstant(2, $Constant); 18018 18019 my $Old_Value_Pure = $Old_Value; 18020 my $New_Value_Pure = $New_Value; 18021 18022 $Old_Value_Pure=~s/(\W)\s+/$1/g; 18023 $Old_Value_Pure=~s/\s+(\W)/$1/g; 18024 $New_Value_Pure=~s/(\W)\s+/$1/g; 18025 $New_Value_Pure=~s/\s+(\W)/$1/g; 18026 18027 next if($New_Value_Pure eq "" or $Old_Value_Pure eq ""); 18028 18029 if($New_Value_Pure ne $Old_Value_Pure) 18030 { # different values 18031 if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value)) 18032 { # complex values 18033 next; 18034 } 18035 if(computeValue($Old_Value) eq computeValue($New_Value)) 18036 { # expressions 18037 next; 18038 } 18039 if(convert_integer($Old_Value) eq convert_integer($New_Value)) 18040 { # 0x0001 and 0x1, 0x1 and 1 equal constants 18041 next; 18042 } 18043 if($Old_Value eq "0" and $New_Value eq "NULL") 18044 { # 0 => NULL 18045 next; 18046 } 18047 if($Old_Value eq "NULL" and $New_Value eq "0") 18048 { # NULL => 0 18049 next; 18050 } 18051 %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = ( 18052 "Target"=>$Constant, 18053 "Old_Value"=>$Old_Value, 18054 "New_Value"=>$New_Value ); 18055 } 18056 } 18057 18058 foreach my $Constant (keys(%{$Constants{2}})) 18059 { 18060 if(not defined $Constants{1}{$Constant}{"Value"}) 18061 { 18062 if($SkipConstants{2}{$Constant}) 18063 { # skipped by the user 18064 next; 18065 } 18066 18067 if(my $Header = $Constants{2}{$Constant}{"Header"}) 18068 { 18069 if(not is_target_header($Header, 1) 18070 and not is_target_header($Header, 2)) 18071 { # user-defined header 18072 next; 18073 } 18074 } 18075 else { 18076 next; 18077 } 18078 18079 my $New_Value = uncoverConstant(2, $Constant); 18080 if(not defined $New_Value or $New_Value eq "") { 18081 next; 18082 } 18083 18084 if(constantFilter($Constant, $New_Value, $Level)) 18085 { # separate binary and source problems 18086 next; 18087 } 18088 18089 %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = ( 18090 "Target"=>$Constant, 18091 "New_Value"=>$New_Value ); 18092 } 18093 } 18094} 18095 18096sub convert_integer($) 18097{ 18098 my $Value = $_[0]; 18099 if($Value=~/\A0x[a-f0-9]+\Z/) 18100 { # hexadecimal 18101 return hex($Value); 18102 } 18103 elsif($Value=~/\A0[0-7]+\Z/) 18104 { # octal 18105 return oct($Value); 18106 } 18107 elsif($Value=~/\A0b[0-1]+\Z/) 18108 { # binary 18109 return oct($Value); 18110 } 18111 else { 18112 return $Value; 18113 } 18114} 18115 18116sub readSymbols($) 18117{ 18118 my $LibVersion = $_[0]; 18119 my @LibPaths = getSOPaths($LibVersion); 18120 if($#LibPaths==-1 and not $CheckHeadersOnly) 18121 { 18122 if($LibVersion==1) 18123 { 18124 printMsg("WARNING", "checking headers only"); 18125 $CheckHeadersOnly = 1; 18126 } 18127 else { 18128 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"}); 18129 } 18130 } 18131 18132 foreach my $LibPath (@LibPaths) { 18133 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1); 18134 } 18135 18136 if($CheckUndefined) 18137 { 18138 my %UndefinedLibs = (); 18139 18140 my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}})); 18141 18142 foreach my $LibName (sort @Libs) 18143 { 18144 if(defined $UndefinedSymbols{$LibVersion}{$LibName}) 18145 { 18146 foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}})) 18147 { 18148 if($Symbol_Library{$LibVersion}{$Symbol} 18149 or $DepSymbol_Library{$LibVersion}{$Symbol}) 18150 { # exported by target library 18151 next; 18152 } 18153 if(index($Symbol, '@')!=-1) 18154 { # exported default symbol version (@@) 18155 $Symbol=~s/\@/\@\@/; 18156 if($Symbol_Library{$LibVersion}{$Symbol} 18157 or $DepSymbol_Library{$LibVersion}{$Symbol}) { 18158 next; 18159 } 18160 } 18161 foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) { 18162 $UndefinedLibs{$Path} = 1; 18163 } 18164 } 18165 } 18166 } 18167 if($ExtraInfo) 18168 { # extra information for other tools 18169 if(my @Paths = sort keys(%UndefinedLibs)) 18170 { 18171 my $LibString = ""; 18172 my %Dirs = (); 18173 foreach (@Paths) 18174 { 18175 $KnownLibs{$_} = 1; 18176 my ($Dir, $Name) = separate_path($_); 18177 18178 if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) { 18179 $Dirs{esc($Dir)} = 1; 18180 } 18181 18182 $Name = parse_libname($Name, "name", $OStarget); 18183 $Name=~s/\Alib//; 18184 18185 $LibString .= " -l$Name"; 18186 } 18187 18188 foreach my $Dir (sort {$b cmp $a} keys(%Dirs)) 18189 { 18190 $LibString = " -L".esc($Dir).$LibString; 18191 } 18192 18193 writeFile($ExtraInfo."/libs-string", $LibString); 18194 } 18195 } 18196 } 18197 18198 if($ExtraInfo) { 18199 writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs))); 18200 } 18201 18202 if(not $CheckHeadersOnly) 18203 { 18204 if($#LibPaths!=-1) 18205 { 18206 if(not keys(%{$Symbol_Library{$LibVersion}})) 18207 { 18208 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)"); 18209 printMsg("WARNING", "checking headers only"); 18210 $CheckHeadersOnly = 1; 18211 } 18212 } 18213 } 18214 18215 # clean memory 18216 %SystemObjects = (); 18217} 18218 18219my %Prefix_Lib_Map=( 18220 # symbols for autodetecting library dependencies (by prefix) 18221 "pthread_" => ["libpthread"], 18222 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"], 18223 "cairo_" => ["libcairo"], 18224 "gtk_" => ["libgtk-x11-2.0"], 18225 "atk_" => ["libatk-1.0"], 18226 "gdk_" => ["libgdk-x11-2.0"], 18227 "gl" => ["libGL"], 18228 "glu" => ["libGLU"], 18229 "popt" => ["libpopt"], 18230 "Py" => ["libpython"], 18231 "jpeg_" => ["libjpeg"], 18232 "BZ2_" => ["libbz2"], 18233 "Fc" => ["libfontconfig"], 18234 "Xft" => ["libXft"], 18235 "SSL_" => ["libssl"], 18236 "sem_" => ["libpthread"], 18237 "snd_" => ["libasound"], 18238 "art_" => ["libart_lgpl_2"], 18239 "dbus_g" => ["libdbus-glib-1"], 18240 "GOMP_" => ["libgomp"], 18241 "omp_" => ["libgomp"], 18242 "cms" => ["liblcms"] 18243); 18244 18245my %Pattern_Lib_Map=( 18246 "SL[a-z]" => ["libslang"] 18247); 18248 18249my %Symbol_Lib_Map=( 18250 # symbols for autodetecting library dependencies (by name) 18251 "pow" => "libm", 18252 "fmod" => "libm", 18253 "sin" => "libm", 18254 "floor" => "libm", 18255 "cos" => "libm", 18256 "dlopen" => "libdl", 18257 "deflate" => "libz", 18258 "inflate" => "libz", 18259 "move_panel" => "libpanel", 18260 "XOpenDisplay" => "libX11", 18261 "resize_term" => "libncurses", 18262 "clock_gettime" => "librt", 18263 "crypt" => "libcrypt" 18264); 18265 18266sub find_SymbolLibs($$) 18267{ 18268 my ($LibVersion, $Symbol) = @_; 18269 18270 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/) 18271 { # debug symbols 18272 return (); 18273 } 18274 18275 my %Paths = (); 18276 18277 if(my $LibName = $Symbol_Lib_Map{$Symbol}) 18278 { 18279 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18280 $Paths{$Path} = 1; 18281 } 18282 } 18283 18284 if(my $SymbolPrefix = getPrefix($Symbol)) 18285 { 18286 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) { 18287 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}}; 18288 } 18289 18290 if(not keys(%Paths)) 18291 { 18292 if(defined $Prefix_Lib_Map{$SymbolPrefix}) 18293 { 18294 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}}) 18295 { 18296 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18297 $Paths{$Path} = 1; 18298 } 18299 } 18300 } 18301 } 18302 18303 if(not keys(%Paths)) 18304 { 18305 foreach my $Prefix (sort keys(%Pattern_Lib_Map)) 18306 { 18307 if($Symbol=~/\A$Prefix/) 18308 { 18309 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}}) 18310 { 18311 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18312 $Paths{$Path} = 1; 18313 } 18314 } 18315 } 18316 } 18317 } 18318 18319 if(not keys(%Paths)) 18320 { 18321 if($SymbolPrefix) 18322 { # try to find a library by symbol prefix 18323 if($SymbolPrefix eq "inotify" and 18324 index($Symbol, "\@GLIBC")!=-1) 18325 { 18326 if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) { 18327 $Paths{$Path} = 1; 18328 } 18329 } 18330 else 18331 { 18332 if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) { 18333 $Paths{$Path} = 1; 18334 } 18335 } 18336 } 18337 } 18338 18339 if(my @Paths = keys(%Paths)) { 18340 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths; 18341 } 18342 } 18343 return keys(%Paths); 18344} 18345 18346sub get_LibPath_Prefix($$) 18347{ 18348 my ($LibVersion, $Prefix) = @_; 18349 18350 $Prefix = lc($Prefix); 18351 $Prefix=~s/[_]+\Z//g; 18352 18353 foreach ("-2", "2", "-1", "1", "") 18354 { # libgnome-2.so 18355 # libxml2.so 18356 # libdbus-1.so 18357 if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) { 18358 return $Path; 18359 } 18360 } 18361 return ""; 18362} 18363 18364sub getPrefix($) 18365{ 18366 my $Str = $_[0]; 18367 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/) 18368 { # XmuValidArea: Xmu 18369 return $1; 18370 } 18371 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/) 18372 { # snfReadFont: snf 18373 return $1; 18374 } 18375 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/) 18376 { # XRRTimes: XRR 18377 return $1; 18378 } 18379 elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i) 18380 { # H5HF_delete: H5 18381 return $1; 18382 } 18383 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i) 18384 { # alarm_event_add: alarm_ 18385 return $1; 18386 } 18387 elsif($Str=~/\A(([a-z])\2{1,})/i) 18388 { # ffopen 18389 return $1; 18390 } 18391 return ""; 18392} 18393 18394sub getSymbolSize($$) 18395{ # size from the shared library 18396 my ($Symbol, $LibVersion) = @_; 18397 return 0 if(not $Symbol); 18398 if(defined $Symbol_Library{$LibVersion}{$Symbol} 18399 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol}) 18400 { 18401 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol} 18402 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol}) 18403 { 18404 if($Size<0) { 18405 return -$Size; 18406 } 18407 } 18408 } 18409 return 0; 18410} 18411 18412sub canonifyName($$) 18413{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*) 18414 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*) 18415 my ($Name, $Type) = @_; 18416 18417 # single 18418 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3) 18419 { 18420 my $P = $1; 18421 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g; 18422 } 18423 18424 # double 18425 if($Name=~/$DEFAULT_STD_PARMS/) 18426 { 18427 if($Type eq "S") 18428 { 18429 my ($ShortName, $FuncParams) = split_Signature($Name); 18430 18431 foreach my $FParam (separate_Params($FuncParams, 0, 0)) 18432 { 18433 if(index($FParam, "<")!=-1) 18434 { 18435 $FParam=~s/>([^<>]+)\Z/>/; # remove quals 18436 my $FParam_N = canonifyName($FParam, "T"); 18437 if($FParam_N ne $FParam) { 18438 $Name=~s/\Q$FParam\E/$FParam_N/g; 18439 } 18440 } 18441 } 18442 } 18443 elsif($Type eq "T") 18444 { 18445 my ($ShortTmpl, $TmplParams) = template_Base($Name); 18446 18447 my @TParams = separate_Params($TmplParams, 0, 0); 18448 if($#TParams>=1) 18449 { 18450 my $FParam = $TParams[0]; 18451 foreach my $Pos (1 .. $#TParams) 18452 { 18453 my $TParam = $TParams[$Pos]; 18454 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) { 18455 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g; 18456 } 18457 } 18458 } 18459 } 18460 } 18461 if($Type eq "S") { 18462 return formatName($Name, "S"); 18463 } 18464 return $Name; 18465} 18466 18467sub translateSymbols(@) 18468{ 18469 my $LibVersion = pop(@_); 18470 my (@MnglNames1, @MnglNames2, @UnmangledNames) = (); 18471 foreach my $Symbol (sort @_) 18472 { 18473 if(index($Symbol, "_Z")==0) 18474 { 18475 next if($tr_name{$Symbol}); 18476 $Symbol=~s/[\@\$]+(.*)\Z//; 18477 push(@MnglNames1, $Symbol); 18478 } 18479 elsif(index($Symbol, "?")==0) 18480 { 18481 next if($tr_name{$Symbol}); 18482 push(@MnglNames2, $Symbol); 18483 } 18484 else 18485 { # not mangled 18486 $tr_name{$Symbol} = $Symbol; 18487 $mangled_name_gcc{$Symbol} = $Symbol; 18488 $mangled_name{$LibVersion}{$Symbol} = $Symbol; 18489 } 18490 } 18491 if($#MnglNames1 > -1) 18492 { # GCC names 18493 @UnmangledNames = reverse(unmangleArray(@MnglNames1)); 18494 foreach my $MnglName (@MnglNames1) 18495 { 18496 if(my $Unmangled = pop(@UnmangledNames)) 18497 { 18498 $tr_name{$MnglName} = canonifyName($Unmangled, "S"); 18499 if(not $mangled_name_gcc{$tr_name{$MnglName}}) { 18500 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName; 18501 } 18502 if(index($MnglName, "_ZTV")==0 18503 and $tr_name{$MnglName}=~/vtable for (.+)/) 18504 { # bind class name and v-table symbol 18505 my $ClassName = $1; 18506 $ClassVTable{$ClassName} = $MnglName; 18507 $VTableClass{$MnglName} = $ClassName; 18508 } 18509 } 18510 } 18511 } 18512 if($#MnglNames2 > -1) 18513 { # MSVC names 18514 @UnmangledNames = reverse(unmangleArray(@MnglNames2)); 18515 foreach my $MnglName (@MnglNames2) 18516 { 18517 if(my $Unmangled = pop(@UnmangledNames)) 18518 { 18519 $tr_name{$MnglName} = formatName($Unmangled, "S"); 18520 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName; 18521 } 18522 } 18523 } 18524 return \%tr_name; 18525} 18526 18527sub link_symbol($$$) 18528{ 18529 my ($Symbol, $RunWith, $Deps) = @_; 18530 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) { 18531 return 1; 18532 } 18533 if($Deps eq "+Deps") 18534 { # check the dependencies 18535 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) { 18536 return 1; 18537 } 18538 } 18539 return 0; 18540} 18541 18542sub link_symbol_internal($$$) 18543{ 18544 my ($Symbol, $RunWith, $Where) = @_; 18545 return 0 if(not $Where or not $Symbol); 18546 if($Where->{$RunWith}{$Symbol}) 18547 { # the exact match by symbol name 18548 return 1; 18549 } 18550 if(my $VSym = $SymVer{$RunWith}{$Symbol}) 18551 { # indirect symbol version, i.e. 18552 # foo_old and its symlink foo@v (or foo@@v) 18553 # foo_old may be in symtab table 18554 if($Where->{$RunWith}{$VSym}) { 18555 return 1; 18556 } 18557 } 18558 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol); 18559 if($Sym and $Ver) 18560 { # search for the symbol with the same version 18561 # or without version 18562 if($Where->{$RunWith}{$Sym}) 18563 { # old: foo@v|foo@@v 18564 # new: foo 18565 return 1; 18566 } 18567 if($Where->{$RunWith}{$Sym."\@".$Ver}) 18568 { # old: foo|foo@@v 18569 # new: foo@v 18570 return 1; 18571 } 18572 if($Where->{$RunWith}{$Sym."\@\@".$Ver}) 18573 { # old: foo|foo@v 18574 # new: foo@@v 18575 return 1; 18576 } 18577 } 18578 return 0; 18579} 18580 18581sub readSymbols_App($) 18582{ 18583 my $Path = $_[0]; 18584 return () if(not $Path); 18585 my @Imported = (); 18586 if($OSgroup eq "macos") 18587 { 18588 my $NM = get_CmdPath("nm"); 18589 if(not $NM) { 18590 exitStatus("Not_Found", "can't find \"nm\""); 18591 } 18592 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |"); 18593 while(<APP>) 18594 { 18595 if(/ U _([\w\$]+)\s*\Z/) { 18596 push(@Imported, $1); 18597 } 18598 } 18599 close(APP); 18600 } 18601 elsif($OSgroup eq "windows") 18602 { 18603 my $DumpBinCmd = get_CmdPath("dumpbin"); 18604 if(not $DumpBinCmd) { 18605 exitStatus("Not_Found", "can't find \"dumpbin.exe\""); 18606 } 18607 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |"); 18608 while(<APP>) 18609 { 18610 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) { 18611 push(@Imported, $1); 18612 } 18613 } 18614 close(APP); 18615 } 18616 else 18617 { 18618 my $ReadelfCmd = get_CmdPath("readelf"); 18619 if(not $ReadelfCmd) { 18620 exitStatus("Not_Found", "can't find \"readelf\""); 18621 } 18622 open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |"); 18623 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 18624 while(<APP>) 18625 { 18626 if(defined $symtab) 18627 { # do nothing with symtab 18628 if(index($_, "'.dynsym'")!=-1) 18629 { # dynamic table 18630 $symtab = undef; 18631 } 18632 } 18633 elsif(index($_, "'.symtab'")!=-1) 18634 { # symbol table 18635 $symtab = 1; 18636 } 18637 elsif(my @Info = readline_ELF($_)) 18638 { 18639 my ($Ndx, $Symbol) = ($Info[5], $Info[6]); 18640 if($Ndx eq "UND") 18641 { # only imported symbols 18642 push(@Imported, $Symbol); 18643 } 18644 } 18645 } 18646 close(APP); 18647 } 18648 return @Imported; 18649} 18650 18651my %ELF_BIND = map {$_=>1} ( 18652 "WEAK", 18653 "GLOBAL" 18654); 18655 18656my %ELF_TYPE = map {$_=>1} ( 18657 "FUNC", 18658 "IFUNC", 18659 "OBJECT", 18660 "COMMON" 18661); 18662 18663my %ELF_VIS = map {$_=>1} ( 18664 "DEFAULT", 18665 "PROTECTED" 18666); 18667 18668sub readline_ELF($) 18669{ # read the line of 'readelf' output corresponding to the symbol 18670 my @Info = split(/\s+/, $_[0]); 18671 # Num: Value Size Type Bind Vis Ndx Name 18672 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4 18673 # 135: 00000000 0 FUNC GLOBAL DEFAULT UND av_image_fill_pointers@LIBAVUTIL_52 (3) 18674 shift(@Info); # spaces 18675 shift(@Info); # num 18676 18677 if($#Info==7) 18678 { # UND SYMBOL (N) 18679 if($Info[7]=~/\(\d+\)/) { 18680 pop(@Info); 18681 } 18682 } 18683 18684 if($#Info!=6) 18685 { # other lines 18686 return (); 18687 } 18688 return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND"); 18689 return () if(not defined $ELF_BIND{$Info[3]}); 18690 return () if(not defined $ELF_VIS{$Info[4]}); 18691 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/) 18692 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3 18693 return (); 18694 } 18695 if($OStarget eq "symbian") 18696 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll 18697 if(index($Info[6], "_._.absent_export_")!=-1) 18698 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll 18699 return (); 18700 } 18701 $Info[6]=~s/\@.+//g; # remove version 18702 } 18703 if(index($Info[2], "0x") == 0) 18704 { # size == 0x3d158 18705 $Info[2] = hex($Info[2]); 18706 } 18707 return @Info; 18708} 18709 18710sub get_LibPath($$) 18711{ 18712 my ($LibVersion, $Name) = @_; 18713 return "" if(not $LibVersion or not $Name); 18714 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) { 18715 return $Cache{"get_LibPath"}{$LibVersion}{$Name}; 18716 } 18717 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name)); 18718} 18719 18720sub get_LibPath_I($$) 18721{ 18722 my ($LibVersion, $Name) = @_; 18723 if(is_abs($Name)) 18724 { 18725 if(-f $Name) 18726 { # absolute path 18727 return $Name; 18728 } 18729 else 18730 { # broken 18731 return ""; 18732 } 18733 } 18734 if(defined $RegisteredObjects{$LibVersion}{$Name}) 18735 { # registered paths 18736 return $RegisteredObjects{$LibVersion}{$Name}; 18737 } 18738 if(defined $RegisteredSONAMEs{$LibVersion}{$Name}) 18739 { # registered paths 18740 return $RegisteredSONAMEs{$LibVersion}{$Name}; 18741 } 18742 if(my $DefaultPath = $DyLib_DefaultPath{$Name}) 18743 { # ldconfig default paths 18744 return $DefaultPath; 18745 } 18746 foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}}) 18747 { # search in default linker directories 18748 # and then in all system paths 18749 if(-f $Dir."/".$Name) { 18750 return join_P($Dir,$Name); 18751 } 18752 } 18753 if(not defined $Cache{"checkSystemFiles"}) { 18754 checkSystemFiles(); 18755 } 18756 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) { 18757 return $AllObjects[0]; 18758 } 18759 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget)) 18760 { 18761 if($ShortName ne $Name) 18762 { # FIXME: check this case 18763 if(my $Path = get_LibPath($LibVersion, $ShortName)) { 18764 return $Path; 18765 } 18766 } 18767 } 18768 # can't find 18769 return ""; 18770} 18771 18772sub readSymbols_Lib($$$$$$) 18773{ 18774 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; 18775 return () if(not $LibVersion or not $Lib_Path); 18776 18777 my $Real_Path = realpath($Lib_Path); 18778 18779 if(not $Real_Path) 18780 { # broken link 18781 return (); 18782 } 18783 18784 my $Lib_Name = get_filename($Real_Path); 18785 18786 if($ExtraInfo) 18787 { 18788 $KnownLibs{$Real_Path} = 1; 18789 $KnownLibs{$Lib_Path} = 1; # links 18790 } 18791 18792 if($IsNeededLib) 18793 { 18794 if($CheckedDyLib{$LibVersion}{$Lib_Name}) { 18795 return (); 18796 } 18797 } 18798 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1); 18799 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1; 18800 18801 push(@RecurLib, $Lib_Name); 18802 my (%Value_Interface, %Interface_Value, %NeededLib) = (); 18803 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget); 18804 18805 if(not $IsNeededLib) 18806 { # special cases: libstdc++ and libc 18807 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget)) 18808 { 18809 if($ShortName eq "libstdc++") 18810 { # libstdc++.so.6 18811 $STDCXX_TESTING = 1; 18812 } 18813 elsif($ShortName eq "libc") 18814 { # libc-2.11.3.so 18815 $GLIBC_TESTING = 1; 18816 } 18817 } 18818 } 18819 my $DebugPath = ""; 18820 if($Debug and not $DumpSystem) 18821 { # debug mode 18822 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt"; 18823 mkpath(get_dirname($DebugPath)); 18824 } 18825 if($OStarget eq "macos") 18826 { # Mac OS X: *.dylib, *.a 18827 my $NM = get_CmdPath("nm"); 18828 if(not $NM) { 18829 exitStatus("Not_Found", "can't find \"nm\""); 18830 } 18831 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 18832 if($DebugPath) 18833 { # debug mode 18834 # write to file 18835 system($NM." >\"$DebugPath\""); 18836 open(LIB, $DebugPath); 18837 } 18838 else 18839 { # write to pipe 18840 open(LIB, $NM." |"); 18841 } 18842 while(<LIB>) 18843 { 18844 if($CheckUndefined) 18845 { 18846 if(not $IsNeededLib) 18847 { 18848 if(/ U _([\w\$]+)\s*\Z/) 18849 { 18850 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0; 18851 next; 18852 } 18853 } 18854 } 18855 18856 if(/ [STD] _([\w\$]+)\s*\Z/) 18857 { 18858 my $Symbol = $1; 18859 if($IsNeededLib) 18860 { 18861 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 18862 { 18863 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 18864 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 18865 } 18866 } 18867 else 18868 { 18869 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 18870 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 18871 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 18872 { 18873 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 18874 setLanguage($LibVersion, "C++"); 18875 } 18876 } 18877 if($CheckObjectsOnly 18878 and $LibVersion==1) { 18879 $CheckedSymbols{"Binary"}{$Symbol} = 1; 18880 } 18881 } 18882 } 18883 } 18884 close(LIB); 18885 18886 if($Deps) 18887 { 18888 if($LIB_TYPE eq "dynamic") 18889 { # dependencies 18890 18891 my $OtoolCmd = get_CmdPath("otool"); 18892 if(not $OtoolCmd) { 18893 exitStatus("Not_Found", "can't find \"otool\""); 18894 } 18895 18896 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 18897 while(<LIB>) 18898 { 18899 if(/\s*([\/\\].+\.$LIB_EXT)\s*/ 18900 and $1 ne $Lib_Path) { 18901 $NeededLib{$1} = 1; 18902 } 18903 } 18904 close(LIB); 18905 } 18906 } 18907 } 18908 elsif($OStarget eq "windows") 18909 { # Windows *.dll, *.lib 18910 my $DumpBinCmd = get_CmdPath("dumpbin"); 18911 if(not $DumpBinCmd) { 18912 exitStatus("Not_Found", "can't find \"dumpbin\""); 18913 } 18914 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null"; 18915 if($DebugPath) 18916 { # debug mode 18917 # write to file 18918 system($DumpBinCmd." >\"$DebugPath\""); 18919 open(LIB, $DebugPath); 18920 } 18921 else 18922 { # write to pipe 18923 open(LIB, $DumpBinCmd." |"); 18924 } 18925 while(<LIB>) 18926 { # 1197 4AC 0000A620 SetThreadStackGuarantee 18927 # 1198 4AD SetThreadToken (forwarded to ...) 18928 # 3368 _o2i_ECPublicKey 18929 # 1 0 00005B30 ??0?N = ... (with pdb) 18930 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i 18931 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ 18932 or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) 18933 { # dynamic, static and forwarded symbols 18934 my $realname = $1; 18935 if($IsNeededLib) 18936 { 18937 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 18938 { 18939 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name; 18940 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 18941 } 18942 } 18943 else 18944 { 18945 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name; 18946 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 18947 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 18948 { 18949 if(index($realname, "_Z")==0 or index($realname, "?")==0) { 18950 setLanguage($LibVersion, "C++"); 18951 } 18952 } 18953 if($CheckObjectsOnly 18954 and $LibVersion==1) { 18955 $CheckedSymbols{"Binary"}{$realname} = 1; 18956 } 18957 } 18958 } 18959 } 18960 close(LIB); 18961 18962 if($Deps) 18963 { 18964 if($LIB_TYPE eq "dynamic") 18965 { # dependencies 18966 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 18967 while(<LIB>) 18968 { 18969 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i 18970 and $1 ne $Lib_Path) { 18971 $NeededLib{path_format($1, $OSgroup)} = 1; 18972 } 18973 } 18974 close(LIB); 18975 } 18976 } 18977 } 18978 else 18979 { # Unix; *.so, *.a 18980 # Symbian: *.dso, *.lib 18981 my $ReadelfCmd = get_CmdPath("readelf"); 18982 if(not $ReadelfCmd) { 18983 exitStatus("Not_Found", "can't find \"readelf\""); 18984 } 18985 my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 18986 if($DebugPath) 18987 { # debug mode 18988 # write to file 18989 system($Cmd." >\"$DebugPath\""); 18990 open(LIB, $DebugPath); 18991 } 18992 else 18993 { # write to pipe 18994 open(LIB, $Cmd." |"); 18995 } 18996 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 18997 while(<LIB>) 18998 { 18999 if($LIB_TYPE eq "dynamic") 19000 { # dynamic library specifics 19001 if(defined $symtab) 19002 { 19003 if(index($_, "'.dynsym'")!=-1) 19004 { # dynamic table 19005 $symtab = undef; 19006 } 19007 # do nothing with symtab 19008 next; 19009 } 19010 elsif(index($_, "'.symtab'")!=-1) 19011 { # symbol table 19012 $symtab = 1; 19013 next; 19014 } 19015 } 19016 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_)) 19017 { # read ELF entry 19018 if($Ndx eq "UND") 19019 { # ignore interfaces that are imported from somewhere else 19020 if($CheckUndefined) 19021 { 19022 if(not $IsNeededLib) { 19023 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0; 19024 } 19025 } 19026 next; 19027 } 19028 if($Bind eq "WEAK") 19029 { 19030 $WeakSymbols{$LibVersion}{$Symbol} = 1; 19031 if($Weak eq "-Weak") 19032 { # skip WEAK symbols 19033 next; 19034 } 19035 } 19036 my $Short = $Symbol; 19037 $Short=~s/\@.+//g; 19038 if($Type eq "OBJECT") 19039 { # global data 19040 $GlobalDataObject{$LibVersion}{$Symbol} = $Size; 19041 $GlobalDataObject{$LibVersion}{$Short} = $Size; 19042 } 19043 if($IsNeededLib) 19044 { 19045 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19046 { 19047 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19048 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19049 } 19050 } 19051 else 19052 { 19053 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19054 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19055 if($Vers) 19056 { 19057 if($LIB_EXT eq "so") 19058 { # value 19059 $Interface_Value{$LibVersion}{$Symbol} = $Value; 19060 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1; 19061 } 19062 } 19063 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19064 { 19065 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 19066 setLanguage($LibVersion, "C++"); 19067 } 19068 } 19069 if($CheckObjectsOnly 19070 and $LibVersion==1) { 19071 $CheckedSymbols{"Binary"}{$Symbol} = 1; 19072 } 19073 } 19074 } 19075 } 19076 close(LIB); 19077 19078 if($Deps and $LIB_TYPE eq "dynamic") 19079 { # dynamic library specifics 19080 $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19081 open(LIB, $Cmd." |"); 19082 19083 while(<LIB>) 19084 { 19085 if(/NEEDED.+\[([^\[\]]+)\]/) 19086 { # dependencies: 19087 # 0x00000001 (NEEDED) Shared library: [libc.so.6] 19088 $NeededLib{$1} = 1; 19089 } 19090 } 19091 19092 close(LIB); 19093 } 19094 } 19095 if($Vers) 19096 { 19097 if(not $IsNeededLib and $LIB_EXT eq "so") 19098 { # get symbol versions 19099 my %Found = (); 19100 19101 # by value 19102 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19103 { 19104 next if(index($Symbol,"\@")==-1); 19105 if(my $Value = $Interface_Value{$LibVersion}{$Symbol}) 19106 { 19107 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}})) 19108 { 19109 if($Symbol_SameValue ne $Symbol 19110 and index($Symbol_SameValue,"\@")==-1) 19111 { 19112 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol; 19113 $Found{$Symbol} = 1; 19114 last; 19115 } 19116 } 19117 } 19118 } 19119 19120 # default 19121 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19122 { 19123 next if(defined $Found{$Symbol}); 19124 next if(index($Symbol,"\@\@")==-1); 19125 19126 if($Symbol=~/\A([^\@]*)\@\@/ 19127 and not $SymVer{$LibVersion}{$1}) 19128 { 19129 $SymVer{$LibVersion}{$1} = $Symbol; 19130 $Found{$Symbol} = 1; 19131 } 19132 } 19133 19134 # non-default 19135 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19136 { 19137 next if(defined $Found{$Symbol}); 19138 next if(index($Symbol,"\@")==-1); 19139 19140 if($Symbol=~/\A([^\@]*)\@([^\@]*)/ 19141 and not $SymVer{$LibVersion}{$1}) 19142 { 19143 $SymVer{$LibVersion}{$1} = $Symbol; 19144 $Found{$Symbol} = 1; 19145 } 19146 } 19147 } 19148 } 19149 if($Deps) 19150 { 19151 foreach my $DyLib (sort keys(%NeededLib)) 19152 { 19153 $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1; 19154 19155 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) 19156 { 19157 if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) { 19158 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers); 19159 } 19160 } 19161 } 19162 } 19163 pop(@RecurLib); 19164 return $Library_Symbol{$LibVersion}; 19165} 19166 19167sub get_prefixes($) 19168{ 19169 my %Prefixes = (); 19170 get_prefixes_I([$_[0]], \%Prefixes); 19171 return keys(%Prefixes); 19172} 19173 19174sub get_prefixes_I($$) 19175{ 19176 foreach my $P (@{$_[0]}) 19177 { 19178 my @Parts = reverse(split(/[\/\\]+/, $P)); 19179 my $Name = $Parts[0]; 19180 foreach (1 .. $#Parts) 19181 { 19182 $_[1]->{$Name}{$P} = 1; 19183 last if($_>4 or $Parts[$_] eq "include"); 19184 $Name = $Parts[$_].$SLASH.$Name; 19185 } 19186 } 19187} 19188 19189sub checkSystemFiles() 19190{ 19191 $Cache{"checkSystemFiles"} = 1; 19192 19193 my @SysHeaders = (); 19194 19195 foreach my $DevelPath (@{$SystemPaths{"lib"}}) 19196 { 19197 next if(not -d $DevelPath); 19198 19199 my @Files = cmd_find($DevelPath,"f"); 19200 foreach my $Link (cmd_find($DevelPath,"l")) 19201 { # add symbolic links 19202 if(-f $Link) { 19203 push(@Files, $Link); 19204 } 19205 } 19206 19207 if(not $CheckObjectsOnly) 19208 { 19209 # search for headers in /usr/lib 19210 my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; 19211 @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; 19212 push(@SysHeaders, @Headers); 19213 } 19214 19215 # search for libraries in /usr/lib (including symbolic links) 19216 my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files; 19217 foreach my $Path (@Libs) 19218 { 19219 my $N = get_filename($Path); 19220 $SystemObjects{$N}{$Path} = 1; 19221 $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1; 19222 } 19223 } 19224 19225 if(not $CheckObjectsOnly) 19226 { 19227 foreach my $DevelPath (@{$SystemPaths{"include"}}) 19228 { 19229 next if(not -d $DevelPath); 19230 # search for all header files in the /usr/include 19231 # with or without extension (ncurses.h, QtCore, ...) 19232 push(@SysHeaders, cmd_find($DevelPath,"f")); 19233 foreach my $Link (cmd_find($DevelPath,"l")) 19234 { # add symbolic links 19235 if(-f $Link) { 19236 push(@SysHeaders, $Link); 19237 } 19238 } 19239 } 19240 get_prefixes_I(\@SysHeaders, \%SystemHeaders); 19241 } 19242} 19243 19244sub getSOPaths($) 19245{ 19246 my $LibVersion = $_[0]; 19247 my @Paths = (); 19248 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"})) 19249 { 19250 if(not -e $Dest) { 19251 exitStatus("Access_Error", "can't access \'$Dest\'"); 19252 } 19253 $Dest = get_abs_path($Dest); 19254 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion); 19255 foreach (@SoPaths_Dest) { 19256 push(@Paths, $_); 19257 } 19258 } 19259 return sort @Paths; 19260} 19261 19262sub skipLib($$) 19263{ 19264 my ($Path, $LibVersion) = @_; 19265 return 1 if(not $Path or not $LibVersion); 19266 my $Name = get_filename($Path); 19267 if($SkipLibs{$LibVersion}{"Name"}{$Name}) { 19268 return 1; 19269 } 19270 my $ShortName = parse_libname($Name, "name+ext", $OStarget); 19271 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) { 19272 return 1; 19273 } 19274 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}})) 19275 { 19276 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) { 19277 return 1; 19278 } 19279 } 19280 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}})) 19281 { 19282 if($Name=~/$P/) { 19283 return 1; 19284 } 19285 if($P=~/[\/\\]/ and $Path=~/$P/) { 19286 return 1; 19287 } 19288 } 19289 return 0; 19290} 19291 19292sub specificHeader($$) 19293{ 19294 my ($Header, $Spec) = @_; 19295 my $Name = get_filename($Header); 19296 19297 if($Spec eq "windows") 19298 {# MS Windows 19299 return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i); 19300 return 1 if($Name=~/([._-]w|win)(32|64)/i); 19301 return 1 if($Name=~/\A(Win|Windows)[A-Z]/); 19302 return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i); 19303 my @Dirs = ( 19304 "win32", 19305 "win64", 19306 "win", 19307 "windows", 19308 "msvcrt" 19309 ); # /gsf-win32/ 19310 if(my $DIRs = join("|", @Dirs)) { 19311 return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19312 } 19313 } 19314 elsif($Spec eq "macos") 19315 { # Mac OS 19316 return 1 if($Name=~/(\A|[_-])mac[._-]/i); 19317 } 19318 19319 return 0; 19320} 19321 19322sub skipAlienHeader($) 19323{ 19324 my $Path = $_[0]; 19325 my $Name = get_filename($Path); 19326 my $Dir = get_dirname($Path); 19327 19328 if($Tolerance=~/2/) 19329 { # 2 - skip internal headers 19330 my @Terms = ( 19331 "p", 19332 "priv", 19333 "int", 19334 "impl", 19335 "implementation", 19336 "internal", 19337 "private", 19338 "old", 19339 "compat", 19340 "debug", 19341 "test", 19342 "gen" 19343 ); 19344 19345 my @Dirs = ( 19346 "private", 19347 "priv", 19348 "port", 19349 "impl", 19350 "internal", 19351 "detail", 19352 "details", 19353 "old", 19354 "compat", 19355 "debug", 19356 "config", 19357 "compiler", 19358 "platform", 19359 "test" 19360 ); 19361 19362 if(my $TERMs = join("|", @Terms)) { 19363 return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i); 19364 } 19365 if(my $DIRs = join("|", @Dirs)) { 19366 return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19367 } 19368 19369 return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/); 19370 } 19371 19372 if($Tolerance=~/1/) 19373 { # 1 - skip non-Linux headers 19374 if($OSgroup ne "windows") 19375 { 19376 if(specificHeader($Path, "windows")) { 19377 return 1; 19378 } 19379 } 19380 if($OSgroup ne "macos") 19381 { 19382 if(specificHeader($Path, "macos")) { 19383 return 1; 19384 } 19385 } 19386 } 19387 19388 # valid 19389 return 0; 19390} 19391 19392sub skipHeader($$) 19393{ 19394 my ($Path, $LibVersion) = @_; 19395 return 1 if(not $Path or not $LibVersion); 19396 if(defined $Cache{"skipHeader"}{$Path}) { 19397 return $Cache{"skipHeader"}{$Path}; 19398 } 19399 if(defined $Tolerance and $Tolerance=~/1|2/) 19400 { # --tolerant 19401 if(skipAlienHeader($Path)) { 19402 return ($Cache{"skipHeader"}{$Path} = 1); 19403 } 19404 } 19405 if(not keys(%{$SkipHeaders{$LibVersion}})) { 19406 return 0; 19407 } 19408 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_)); 19409} 19410 19411sub skipHeader_I($$) 19412{ # returns: 19413 # 1 - if header should NOT be included and checked 19414 # 2 - if header should NOT be included, but should be checked 19415 my ($Path, $LibVersion) = @_; 19416 my $Name = get_filename($Path); 19417 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) { 19418 return $Kind; 19419 } 19420 foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}} 19421 keys(%{$SkipHeaders{$LibVersion}{"Path"}})) 19422 { 19423 if(index($Path, $D)!=-1) 19424 { 19425 if($Path=~/\Q$D\E([\/\\]|\Z)/) { 19426 return $SkipHeaders{$LibVersion}{"Path"}{$D}; 19427 } 19428 } 19429 } 19430 foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}} 19431 keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) 19432 { 19433 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P}) 19434 { 19435 if($Name=~/$P/) { 19436 return $Kind; 19437 } 19438 if($P=~/[\/\\]/ and $Path=~/$P/) { 19439 return $Kind; 19440 } 19441 } 19442 } 19443 19444 return 0; 19445} 19446 19447sub registerObject_Dir($$) 19448{ 19449 my ($Dir, $LibVersion) = @_; 19450 if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}}) 19451 { # system directory 19452 return; 19453 } 19454 if($RegisteredObject_Dirs{$LibVersion}{$Dir}) 19455 { # already registered 19456 return; 19457 } 19458 foreach my $Path (find_libs($Dir,"",1)) 19459 { 19460 next if(ignore_path($Path)); 19461 next if(skipLib($Path, $LibVersion)); 19462 registerObject($Path, $LibVersion); 19463 } 19464 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1; 19465} 19466 19467sub registerObject($$) 19468{ 19469 my ($Path, $LibVersion) = @_; 19470 19471 my $Name = get_filename($Path); 19472 $RegisteredObjects{$LibVersion}{$Name} = $Path; 19473 if($OSgroup=~/linux|bsd/i) 19474 { 19475 if(my $SONAME = getSONAME($Path)) { 19476 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path; 19477 } 19478 } 19479 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) { 19480 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path; 19481 } 19482 19483 if(not $CheckedArch{$LibVersion} and -f $Path) 19484 { 19485 if(my $ObjArch = getArch_Object($Path)) 19486 { 19487 if($ObjArch ne getArch_GCC($LibVersion)) 19488 { # translation unit dump generated by the GCC compiler should correspond to the input objects 19489 $CheckedArch{$LibVersion} = 1; 19490 printMsg("WARNING", "the architectures of input objects and the used GCC compiler are not equal, please change the compiler by --gcc-path=PATH option."); 19491 } 19492 } 19493 } 19494} 19495 19496sub getArch_Object($) 19497{ 19498 my $Path = $_[0]; 19499 19500 my %MachineType = ( 19501 "14C" => "x86", 19502 "8664" => "x86_64", 19503 "1C0" => "arm", 19504 "200" => "ia64" 19505 ); 19506 19507 my %ArchName = ( 19508 "s390:31-bit" => "s390", 19509 "s390:64-bit" => "s390x", 19510 "powerpc:common" => "ppc32", 19511 "powerpc:common64" => "ppc64", 19512 "i386:x86-64" => "x86_64", 19513 "mips:3000" => "mips", 19514 "sparc:v8plus" => "sparcv9" 19515 ); 19516 19517 if($OSgroup eq "windows") 19518 { 19519 my $DumpbinCmd = get_CmdPath("dumpbin"); 19520 if(not $DumpbinCmd) { 19521 exitStatus("Not_Found", "can't find \"dumpbin\""); 19522 } 19523 19524 my $Cmd = $DumpbinCmd." /headers \"$Path\""; 19525 my $Out = `$Cmd`; 19526 19527 if($Out=~/(\w+)\smachine/) 19528 { 19529 if(my $Type = $MachineType{uc($1)}) 19530 { 19531 return $Type; 19532 } 19533 } 19534 } 19535 elsif($OSgroup=~/linux|bsd/) 19536 { 19537 my $ObjdumpCmd = get_CmdPath("objdump"); 19538 if(not $ObjdumpCmd) { 19539 exitStatus("Not_Found", "can't find \"objdump\""); 19540 } 19541 19542 my $Cmd = $ObjdumpCmd." -f \"$Path\""; 19543 my $Out = `$Cmd`; 19544 19545 if($Out=~/architecture:\s+([\w\-\:]+)/) 19546 { 19547 my $Arch = $1; 19548 if($Arch=~s/\:(.+)//) 19549 { 19550 my $Suffix = $1; 19551 19552 if(my $Name = $ArchName{$Arch.":".$Suffix}) 19553 { 19554 $Arch = $Name; 19555 } 19556 } 19557 19558 if($Arch=~/i[3-6]86/) { 19559 $Arch = "x86"; 19560 } 19561 19562 if($Arch eq "x86-64") { 19563 $Arch = "x86_64"; 19564 } 19565 19566 if($Arch eq "ia64-elf64") { 19567 $Arch = "ia64"; 19568 } 19569 19570 return $Arch; 19571 } 19572 } 19573 else 19574 { # macos, etc. 19575 # TODO 19576 } 19577 19578 return undef; 19579} 19580 19581sub getSONAME($) 19582{ 19583 my $Path = $_[0]; 19584 return if(not $Path); 19585 if(defined $Cache{"getSONAME"}{$Path}) { 19586 return $Cache{"getSONAME"}{$Path}; 19587 } 19588 my $ObjdumpCmd = get_CmdPath("objdump"); 19589 if(not $ObjdumpCmd) { 19590 exitStatus("Not_Found", "can't find \"objdump\""); 19591 } 19592 my $SonameCmd = "$ObjdumpCmd -x \"$Path\" 2>$TMP_DIR/null"; 19593 if($OSgroup eq "windows") { 19594 $SonameCmd .= " | find \"SONAME\""; 19595 } 19596 else { 19597 $SonameCmd .= " | grep SONAME"; 19598 } 19599 if(my $SonameInfo = `$SonameCmd`) 19600 { 19601 if($SonameInfo=~/SONAME\s+([^\s]+)/) { 19602 return ($Cache{"getSONAME"}{$Path} = $1); 19603 } 19604 } 19605 return ($Cache{"getSONAME"}{$Path}=""); 19606} 19607 19608sub getSOPaths_Dest($$) 19609{ 19610 my ($Dest, $LibVersion) = @_; 19611 if(skipLib($Dest, $LibVersion)) { 19612 return (); 19613 } 19614 if(-f $Dest) 19615 { 19616 if(not parse_libname($Dest, "name", $OStarget)) { 19617 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'"); 19618 } 19619 registerObject($Dest, $LibVersion); 19620 registerObject_Dir(get_dirname($Dest), $LibVersion); 19621 return ($Dest); 19622 } 19623 elsif(-d $Dest) 19624 { 19625 $Dest=~s/[\/\\]+\Z//g; 19626 my %Libs = (); 19627 if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}}) 19628 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor 19629 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...) 19630 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2)) 19631 { # all files and symlinks that match the name of a library 19632 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i) 19633 { 19634 registerObject($Path, $LibVersion); 19635 $Libs{realpath($Path)}=1; 19636 } 19637 } 19638 } 19639 else 19640 { # search for all files and symlinks 19641 foreach my $Path (find_libs($Dest,"","")) 19642 { 19643 next if(ignore_path($Path)); 19644 next if(skipLib($Path, $LibVersion)); 19645 registerObject($Path, $LibVersion); 19646 $Libs{realpath($Path)}=1; 19647 } 19648 if($OSgroup eq "macos") 19649 { # shared libraries on MacOS X may have no extension 19650 foreach my $Path (cmd_find($Dest,"f")) 19651 { 19652 next if(ignore_path($Path)); 19653 next if(skipLib($Path, $LibVersion)); 19654 if(get_filename($Path)!~/\./ 19655 and cmd_file($Path)=~/(shared|dynamic)\s+library/i) 19656 { 19657 registerObject($Path, $LibVersion); 19658 $Libs{realpath($Path)}=1; 19659 } 19660 } 19661 } 19662 } 19663 return keys(%Libs); 19664 } 19665 else { 19666 return (); 19667 } 19668} 19669 19670sub isCyclical($$) 19671{ 19672 my ($Stack, $Value) = @_; 19673 return (grep {$_ eq $Value} @{$Stack}); 19674} 19675 19676sub getGCC_Opts($) 19677{ # to use in module 19678 my $LibVersion = $_[0]; 19679 19680 my @Opts = (); 19681 19682 if($CompilerOptions{$LibVersion}) 19683 { # user-defined options 19684 push(@Opts, $CompilerOptions{$LibVersion}); 19685 } 19686 if($GccOptions) 19687 { # additional 19688 push(@Opts, $GccOptions); 19689 } 19690 19691 if(@Opts) { 19692 return join(" ", @Opts); 19693 } 19694 19695 return undef; 19696} 19697 19698sub getArch_GCC($) 19699{ 19700 my $LibVersion = $_[0]; 19701 19702 if(defined $Cache{"getArch_GCC"}{$LibVersion}) { 19703 return $Cache{"getArch_GCC"}{$LibVersion}; 19704 } 19705 19706 my $Arch = undef; 19707 19708 if($GCC_PATH) 19709 { 19710 writeFile("$TMP_DIR/test.c", "int main(){return 0;}\n"); 19711 19712 my $Cmd = $GCC_PATH." test.c -o test"; 19713 if(my $Opts = getGCC_Opts($LibVersion)) 19714 { # user-defined options 19715 $Cmd .= " ".$Opts; 19716 } 19717 19718 chdir($TMP_DIR); 19719 system($Cmd); 19720 chdir($ORIG_DIR); 19721 19722 $Arch = getArch_Object("$TMP_DIR/test"); 19723 19724 unlink("$TMP_DIR/test.c"); 19725 unlink("$TMP_DIR/test"); 19726 } 19727 19728 if(not $Arch) { 19729 exitStatus("Error", "can't check ARCH type"); 19730 } 19731 19732 return ($Cache{"getArch_GCC"}{$LibVersion} = $Arch); 19733} 19734 19735sub detectWordSize($) 19736{ 19737 my $LibVersion = $_[0]; 19738 19739 my $Size = undef; 19740 19741 # speed up detection 19742 if(my $Arch = getArch($LibVersion)) 19743 { 19744 if($Arch=~/\A(x86_64|s390x|ppc64|ia64|alpha)\Z/) { 19745 $Size = "8"; 19746 } 19747 elsif($Arch=~/\A(x86|s390|ppc32)\Z/) { 19748 $Size = "4"; 19749 } 19750 } 19751 19752 if($GCC_PATH) 19753 { 19754 writeFile("$TMP_DIR/empty.h", ""); 19755 19756 my $Cmd = $GCC_PATH." -E -dD empty.h"; 19757 if(my $Opts = getGCC_Opts($LibVersion)) 19758 { # user-defined options 19759 $Cmd .= " ".$Opts; 19760 } 19761 19762 chdir($TMP_DIR); 19763 my $Defines = `$Cmd`; 19764 chdir($ORIG_DIR); 19765 19766 unlink("$TMP_DIR/empty.h"); 19767 19768 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/) 19769 { # GCC 4 19770 $Size = $1; 19771 } 19772 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/) 19773 { # GCC 3 19774 my $PTRDIFF = $1; 19775 if($PTRDIFF=~/long/) { 19776 $Size = "8"; 19777 } 19778 else { 19779 $Size = "4"; 19780 } 19781 } 19782 } 19783 19784 if(not $Size) { 19785 exitStatus("Error", "can't check WORD size"); 19786 } 19787 19788 return $Size; 19789} 19790 19791sub getWordSize($) 19792{ # to use in module 19793 return $WORD_SIZE{$_[0]}; 19794} 19795 19796sub majorVersion($) 19797{ 19798 my $V = $_[0]; 19799 return 0 if(not $V); 19800 my @VParts = split(/\./, $V); 19801 return $VParts[0]; 19802} 19803 19804sub cmpVersions($$) 19805{ # compare two versions in dotted-numeric format 19806 my ($V1, $V2) = @_; 19807 return 0 if($V1 eq $V2); 19808 my @V1Parts = split(/\./, $V1); 19809 my @V2Parts = split(/\./, $V2); 19810 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) 19811 { 19812 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); 19813 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); 19814 } 19815 return -1 if($#V1Parts < $#V2Parts); 19816 return 1 if($#V1Parts > $#V2Parts); 19817 return 0; 19818} 19819 19820sub read_ABI_Dump($$) 19821{ 19822 my ($LibVersion, $Path) = @_; 19823 return if(not $LibVersion or not -e $Path); 19824 my $FilePath = ""; 19825 if(isDump_U($Path)) 19826 { # input *.abi 19827 $FilePath = $Path; 19828 } 19829 else 19830 { # input *.abi.tar.gz 19831 $FilePath = unpackDump($Path); 19832 if(not isDump_U($FilePath)) { 19833 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 19834 } 19835 } 19836 19837 my $ABI = {}; 19838 19839 my $Line = readLineNum($FilePath, 0); 19840 if($Line=~/xml/) 19841 { # XML format 19842 loadModule("XmlDump"); 19843 $ABI = readXmlDump($FilePath); 19844 } 19845 else 19846 { # Perl Data::Dumper format (default) 19847 open(DUMP, $FilePath); 19848 local $/ = undef; 19849 my $Content = <DUMP>; 19850 close(DUMP); 19851 19852 if(get_dirname($FilePath) eq $TMP_DIR."/unpack") 19853 { # remove temp file 19854 unlink($FilePath); 19855 } 19856 if($Content!~/};\s*\Z/) { 19857 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 19858 } 19859 $ABI = eval($Content); 19860 if(not $ABI) { 19861 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 19862 } 19863 } 19864 # new dumps (>=1.22) have a personal versioning 19865 my $DVersion = $ABI->{"ABI_DUMP_VERSION"}; 19866 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}; 19867 if(not $DVersion) 19868 { # old dumps (<=1.21.6) have been marked by the tool version 19869 $DVersion = $ToolVersion; 19870 } 19871 $UsedDump{$LibVersion}{"V"} = $DVersion; 19872 $UsedDump{$LibVersion}{"M"} = $ABI->{"LibraryName"}; 19873 19874 if($ABI->{"ABI_DUMP_VERSION"}) 19875 { 19876 if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0) 19877 { # Don't know how to parse future dump formats 19878 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)"); 19879 } 19880 } 19881 else 19882 { # support for old ABI dumps 19883 if(cmpVersions($DVersion, $TOOL_VERSION)>0) 19884 { # Don't know how to parse future dump formats 19885 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)"); 19886 } 19887 } 19888 19889 if(majorVersion($DVersion)<2) 19890 { 19891 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)"); 19892 } 19893 19894 if(defined $ABI->{"ABI_DUMPER_VERSION"}) 19895 { # DWARF ABI Dump 19896 $UseConv_Real{$LibVersion}{"P"} = 1; 19897 $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet 19898 19899 $UsedDump{$LibVersion}{"DWARF"} = 1; 19900 19901 $TargetComponent = "module"; 19902 } 19903 19904 if(not checkDump($LibVersion, "2.11")) 19905 { # old ABI dumps 19906 $UsedDump{$LibVersion}{"BinOnly"} = 1; 19907 } 19908 elsif($ABI->{"BinOnly"}) 19909 { # ABI dump created with --binary option 19910 $UsedDump{$LibVersion}{"BinOnly"} = 1; 19911 } 19912 else 19913 { # default 19914 $UsedDump{$LibVersion}{"SrcBin"} = 1; 19915 } 19916 19917 if(defined $ABI->{"Mode"} 19918 and $ABI->{"Mode"} eq "Extended") 19919 { # --ext option 19920 $ExtendedCheck = 1; 19921 } 19922 if($ABI->{"Extra"}) { 19923 $ExtraDump = 1; 19924 } 19925 19926 if(my $Lang = $ABI->{"Language"}) 19927 { 19928 $UsedDump{$LibVersion}{"L"} = $Lang; 19929 setLanguage($LibVersion, $Lang); 19930 } 19931 if(checkDump($LibVersion, "2.15")) { 19932 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"}; 19933 } 19934 else 19935 { # support for old ABI dumps 19936 my $TInfo = $ABI->{"TypeInfo"}; 19937 if(not $TInfo) 19938 { # support for older ABI dumps 19939 $TInfo = $ABI->{"TypeDescr"}; 19940 } 19941 my %Tid_TDid = (); 19942 foreach my $TDid (keys(%{$TInfo})) 19943 { 19944 foreach my $Tid (keys(%{$TInfo->{$TDid}})) 19945 { 19946 $MAX_ID = $Tid if($Tid>$MAX_ID); 19947 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID); 19948 $Tid_TDid{$Tid}{$TDid} = 1; 19949 } 19950 } 19951 my %NewID = (); 19952 foreach my $Tid (keys(%Tid_TDid)) 19953 { 19954 my @TDids = keys(%{$Tid_TDid{$Tid}}); 19955 if($#TDids>=1) 19956 { 19957 foreach my $TDid (@TDids) 19958 { 19959 if($TDid) { 19960 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 19961 } 19962 else 19963 { 19964 my $ID = ++$MAX_ID; 19965 19966 $NewID{$TDid}{$Tid} = $ID; 19967 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; 19968 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; 19969 } 19970 } 19971 } 19972 else 19973 { 19974 my $TDid = $TDids[0]; 19975 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 19976 } 19977 } 19978 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 19979 { 19980 my %Info = %{$TypeInfo{$LibVersion}{$Tid}}; 19981 if(defined $Info{"BaseType"}) 19982 { 19983 my $Bid = $Info{"BaseType"}{"Tid"}; 19984 my $BDid = $Info{"BaseType"}{"TDid"}; 19985 $BDid="" if(not defined $BDid); 19986 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"}); 19987 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) { 19988 $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID; 19989 } 19990 } 19991 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"}); 19992 } 19993 } 19994 read_Machine_DumpInfo($ABI, $LibVersion); 19995 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"}; 19996 if(not $SymbolInfo{$LibVersion}) 19997 { # support for old dumps 19998 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"}; 19999 } 20000 if(not keys(%{$SymbolInfo{$LibVersion}})) 20001 { # validation of old-version dumps 20002 if(not $ExtendedCheck) { 20003 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid"); 20004 } 20005 } 20006 if(checkDump($LibVersion, "2.15")) { 20007 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"}; 20008 } 20009 else 20010 { # support for old ABI dumps 20011 my $DepSymbols = $ABI->{"DepSymbols"}; 20012 if(not $DepSymbols) { 20013 $DepSymbols = $ABI->{"DepInterfaces"}; 20014 } 20015 if(not $DepSymbols) 20016 { # Cannot reconstruct DepSymbols. This may result in false 20017 # positives if the old dump is for library 2. Not a problem if 20018 # old dumps are only from old libraries. 20019 $DepSymbols = {}; 20020 } 20021 foreach my $Symbol (keys(%{$DepSymbols})) { 20022 $DepSymbol_Library{$LibVersion}{$Symbol} = 1; 20023 } 20024 } 20025 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"}; 20026 20027 if(my $V = $TargetVersion{$LibVersion}) { 20028 $Descriptor{$LibVersion}{"Version"} = $V; 20029 } 20030 else { 20031 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"}; 20032 } 20033 20034 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"}; 20035 if(not $SkipTypes{$LibVersion}) 20036 { # support for old dumps 20037 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"}; 20038 } 20039 20040 if(not $SkipSymbols{$LibVersion}) 20041 { # if not defined by -skip-symbols option 20042 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; 20043 if(not $SkipSymbols{$LibVersion}) 20044 { # support for old dumps 20045 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"}; 20046 } 20047 if(not $SkipSymbols{$LibVersion}) 20048 { # support for old dumps 20049 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"}; 20050 } 20051 } 20052 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"}; 20053 20054 if(not $TargetHeaders{$LibVersion}) 20055 { # if not defined by -headers-list option 20056 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"}; 20057 } 20058 20059 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}})) 20060 { 20061 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path}; 20062 my ($CPath, $Type) = classifyPath($Path); 20063 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path}; 20064 } 20065 read_Source_DumpInfo($ABI, $LibVersion); 20066 read_Libs_DumpInfo($ABI, $LibVersion); 20067 if(not checkDump($LibVersion, "2.10.1") 20068 or not $TargetHeaders{$LibVersion}) 20069 { # support for old ABI dumps: added target headers 20070 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20071 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20072 } 20073 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20074 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20075 } 20076 } 20077 $Constants{$LibVersion} = $ABI->{"Constants"}; 20078 if(defined $ABI->{"GccConstants"}) 20079 { # 3.0 20080 foreach my $Name (keys(%{$ABI->{"GccConstants"}})) { 20081 $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name}; 20082 } 20083 } 20084 20085 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"}; 20086 if(not $NestedNameSpaces{$LibVersion}) 20087 { # support for old dumps 20088 # Cannot reconstruct NameSpaces. This may affect design 20089 # of the compatibility report. 20090 $NestedNameSpaces{$LibVersion} = {}; 20091 } 20092 # target system type 20093 # needed to adopt HTML report 20094 if(not $DumpSystem) 20095 { # to use in createSymbolsList(...) 20096 $OStarget = $ABI->{"Target"}; 20097 } 20098 # recreate environment 20099 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}})) 20100 { 20101 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 20102 { 20103 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20104 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1) 20105 { # data marked as -size in the dump 20106 $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}; 20107 } 20108 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 20109 { 20110 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 20111 setLanguage($LibVersion, "C++"); 20112 } 20113 } 20114 } 20115 } 20116 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}})) 20117 { 20118 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) { 20119 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20120 } 20121 } 20122 20123 my @VFunc = (); 20124 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20125 { 20126 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20127 { 20128 if(not $Symbol_Library{$LibVersion}{$MnglName} 20129 and not $DepSymbol_Library{$LibVersion}{$MnglName}) { 20130 push(@VFunc, $MnglName); 20131 } 20132 } 20133 } 20134 translateSymbols(@VFunc, $LibVersion); 20135 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 20136 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 20137 20138 if(not checkDump($LibVersion, "3.0")) 20139 { # support for old ABI dumps 20140 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20141 { 20142 if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20143 { 20144 if(ref($BaseType) eq "HASH") { 20145 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"}; 20146 } 20147 } 20148 } 20149 } 20150 20151 if(not checkDump($LibVersion, "3.2")) 20152 { # support for old ABI dumps 20153 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20154 { 20155 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) 20156 { 20157 foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) { 20158 $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset}); 20159 } 20160 } 20161 } 20162 20163 # repair target headers list 20164 delete($TargetHeaders{$LibVersion}); 20165 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20166 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20167 } 20168 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20169 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20170 } 20171 20172 # non-target constants from anon enums 20173 foreach my $Name (keys(%{$Constants{$LibVersion}})) 20174 { 20175 if(not $ExtraDump 20176 and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion)) 20177 { 20178 delete($Constants{$LibVersion}{$Name}); 20179 } 20180 } 20181 } 20182 20183 if(not checkDump($LibVersion, "2.20")) 20184 { # support for old ABI dumps 20185 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20186 { 20187 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20188 20189 if($TType=~/Struct|Union|Enum|Typedef/) 20190 { # repair complex types first 20191 next; 20192 } 20193 20194 if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20195 { 20196 my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"}); 20197 if($BType=~/Struct|Union|Enum/i) 20198 { 20199 my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}; 20200 $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g; 20201 } 20202 } 20203 } 20204 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20205 { 20206 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20207 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 20208 if($TType=~/Struct|Union|Enum/) { 20209 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName; 20210 } 20211 } 20212 } 20213 20214 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20215 { # order is important 20216 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}) 20217 { # support for old ABI dumps < 2.0 (ACC 1.22) 20218 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}})) 20219 { 20220 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId}) 20221 { 20222 if($Access ne "public") { 20223 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access; 20224 } 20225 } 20226 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {}; 20227 } 20228 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}); 20229 } 20230 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"}) 20231 { # support for old ABI dumps 20232 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup); 20233 } 20234 elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"}) 20235 { # DWARF ABI Dumps 20236 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source; 20237 } 20238 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) { 20239 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId; 20240 } 20241 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}}; 20242 if(defined $TInfo{"Base"}) 20243 { 20244 foreach (keys(%{$TInfo{"Base"}})) { 20245 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1; 20246 } 20247 } 20248 if($TInfo{"Type"} eq "MethodPtr") 20249 { 20250 if(defined $TInfo{"Param"}) 20251 { # support for old ABI dumps <= 1.17 20252 if(not defined $TInfo{"Param"}{"0"}) 20253 { 20254 my $Max = keys(%{$TInfo{"Param"}}); 20255 foreach my $Pos (1 .. $Max) { 20256 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos}; 20257 } 20258 delete($TInfo{"Param"}{$Max}); 20259 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo; 20260 } 20261 } 20262 } 20263 if($TInfo{"BaseType"} eq $TypeId) 20264 { # fix ABI dump 20265 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"}); 20266 } 20267 if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"}) 20268 { 20269 if(my $BTid = $TInfo{"BaseType"}) 20270 { 20271 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"}; 20272 if(not $BName) 20273 { # broken type 20274 next; 20275 } 20276 if($TInfo{"Name"} eq $BName) 20277 { # typedef to "class Class" 20278 # should not be registered in TName_Tid 20279 next; 20280 } 20281 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) { 20282 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName; 20283 } 20284 } 20285 } 20286 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}}) 20287 { # classes: class (id1), typedef (artificial, id2 > id1) 20288 $TName_Tid{$LibVersion}{formatName($TInfo{"Name"}, "T")} = $TypeId; 20289 } 20290 } 20291 20292 if(not checkDump($LibVersion, "2.15")) 20293 { # support for old ABI dumps 20294 my %Dups = (); 20295 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20296 { 20297 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20298 { 20299 if(not defined $TypeInfo{$LibVersion}{$ClassId}) 20300 { # remove template decls 20301 delete($SymbolInfo{$LibVersion}{$InfoId}); 20302 next; 20303 } 20304 } 20305 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 20306 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20307 { # templates 20308 delete($SymbolInfo{$LibVersion}{$InfoId}); 20309 } 20310 } 20311 } 20312 20313 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20314 { 20315 if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 20316 and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"} 20317 and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 20318 { # support for old ABI dumps (< 3.1) 20319 if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 20320 or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 20321 { # add "this" first parameter 20322 my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion); 20323 my %PInfo = ("name"=>"this", "type"=>"$ThisTid"); 20324 20325 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 20326 { 20327 my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 20328 foreach my $Pos (reverse(0 .. $#Pos)) { 20329 %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}}; 20330 } 20331 } 20332 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo; 20333 } 20334 } 20335 20336 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20337 { # ABI dumps have no mangled names for C-functions 20338 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 20339 } 20340 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"}) 20341 { # support for old ABI dumps 20342 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup); 20343 } 20344 elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"}) 20345 { # DWARF ABI Dumps 20346 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source; 20347 } 20348 } 20349 20350 $Descriptor{$LibVersion}{"Dump"} = 1; 20351} 20352 20353sub read_Machine_DumpInfo($$) 20354{ 20355 my ($ABI, $LibVersion) = @_; 20356 if($ABI->{"Arch"}) { 20357 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"}; 20358 } 20359 if($ABI->{"WordSize"}) { 20360 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"}; 20361 } 20362 else 20363 { # support for old dumps 20364 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"}; 20365 } 20366 if(not $WORD_SIZE{$LibVersion}) 20367 { # support for old dumps (<1.23) 20368 if(my $Tid = getTypeIdByName("char*", $LibVersion)) 20369 { # size of char* 20370 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20371 } 20372 else 20373 { 20374 my $PSize = 0; 20375 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 20376 { 20377 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer") 20378 { # any "pointer"-type 20379 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20380 last; 20381 } 20382 } 20383 if($PSize) 20384 { # a pointer type size 20385 $WORD_SIZE{$LibVersion} = $PSize; 20386 } 20387 else { 20388 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)"); 20389 } 20390 } 20391 } 20392 if($ABI->{"GccVersion"}) { 20393 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"}; 20394 } 20395} 20396 20397sub read_Libs_DumpInfo($$) 20398{ 20399 my ($ABI, $LibVersion) = @_; 20400 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"}; 20401 if(not $Library_Symbol{$LibVersion}) 20402 { # support for old dumps 20403 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"}; 20404 } 20405 if(keys(%{$Library_Symbol{$LibVersion}}) 20406 and not $DumpAPI) { 20407 $Descriptor{$LibVersion}{"Libs"} = "OK"; 20408 } 20409} 20410 20411sub read_Source_DumpInfo($$) 20412{ 20413 my ($ABI, $LibVersion) = @_; 20414 20415 if(keys(%{$ABI->{"Headers"}}) 20416 and not $DumpAPI) { 20417 $Descriptor{$LibVersion}{"Headers"} = "OK"; 20418 } 20419 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}})) 20420 { 20421 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity; 20422 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity}; 20423 } 20424 20425 if(keys(%{$ABI->{"Sources"}}) 20426 and not $DumpAPI) { 20427 $Descriptor{$LibVersion}{"Sources"} = "OK"; 20428 } 20429 foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}})) 20430 { 20431 $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name; 20432 $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name}; 20433 } 20434} 20435 20436sub find_libs($$$) 20437{ 20438 my ($Path, $Type, $MaxDepth) = @_; 20439 # FIXME: correct the search pattern 20440 return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1); 20441} 20442 20443sub createDescriptor($$) 20444{ 20445 my ($LibVersion, $Path) = @_; 20446 if(not $LibVersion or not $Path 20447 or not -e $Path) { 20448 return ""; 20449 } 20450 if(-d $Path) 20451 { # directory with headers files and shared objects 20452 return " 20453 <version> 20454 ".$TargetVersion{$LibVersion}." 20455 </version> 20456 20457 <headers> 20458 $Path 20459 </headers> 20460 20461 <libs> 20462 $Path 20463 </libs>"; 20464 } 20465 else 20466 { # files 20467 if($Path=~/\.(xml|desc)\Z/i) 20468 { # standard XML-descriptor 20469 return readFile($Path); 20470 } 20471 elsif(is_header($Path, 2, $LibVersion)) 20472 { # header file 20473 return " 20474 <version> 20475 ".$TargetVersion{$LibVersion}." 20476 </version> 20477 20478 <headers> 20479 $Path 20480 </headers> 20481 20482 <libs> 20483 none 20484 </libs>"; 20485 } 20486 elsif(parse_libname($Path, "name", $OStarget)) 20487 { # shared object 20488 return " 20489 <version> 20490 ".$TargetVersion{$LibVersion}." 20491 </version> 20492 20493 <headers> 20494 none 20495 </headers> 20496 20497 <libs> 20498 $Path 20499 </libs>"; 20500 } 20501 else 20502 { # standard XML-descriptor 20503 return readFile($Path); 20504 } 20505 } 20506} 20507 20508sub detect_lib_default_paths() 20509{ 20510 my %LPaths = (); 20511 if($OSgroup eq "bsd") 20512 { 20513 if(my $LdConfig = get_CmdPath("ldconfig")) 20514 { 20515 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`)) 20516 { 20517 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) 20518 { 20519 my $Name = "lib".$1; 20520 if(not defined $LPaths{$Name}) { 20521 $LPaths{$Name} = $2; 20522 } 20523 } 20524 } 20525 } 20526 else { 20527 printMsg("WARNING", "can't find ldconfig"); 20528 } 20529 } 20530 else 20531 { 20532 if(my $LdConfig = get_CmdPath("ldconfig")) 20533 { 20534 if($SystemRoot and $OSgroup eq "linux") 20535 { # use host (x86) ldconfig with the target (arm) ld.so.conf 20536 if(-e $SystemRoot."/etc/ld.so.conf") { 20537 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf"; 20538 } 20539 } 20540 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`)) 20541 { 20542 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/) 20543 { 20544 my ($Name, $Path) = ($1, $2); 20545 $Path=~s/[\/]{2,}/\//; 20546 if(not defined $LPaths{$Name}) 20547 { # get first element from the list of available paths 20548 20549 # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 20550 # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6 20551 # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6 20552 20553 $LPaths{$Name} = $Path; 20554 } 20555 } 20556 } 20557 } 20558 elsif($OSgroup eq "linux") { 20559 printMsg("WARNING", "can't find ldconfig"); 20560 } 20561 } 20562 return \%LPaths; 20563} 20564 20565sub detect_bin_default_paths() 20566{ 20567 my $EnvPaths = $ENV{"PATH"}; 20568 if($OSgroup eq "beos") { 20569 $EnvPaths.=":".$ENV{"BETOOLS"}; 20570 } 20571 my $Sep = ($OSgroup eq "windows")?";":":|;"; 20572 foreach my $Path (split(/$Sep/, $EnvPaths)) 20573 { 20574 $Path = path_format($Path, $OSgroup); 20575 next if(not $Path); 20576 if($SystemRoot 20577 and $Path=~/\A\Q$SystemRoot\E\//) 20578 { # do NOT use binaries from target system 20579 next; 20580 } 20581 push_U(\@DefaultBinPaths, $Path); 20582 } 20583} 20584 20585sub detect_inc_default_paths() 20586{ 20587 return () if(not $GCC_PATH); 20588 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]); 20589 writeFile("$TMP_DIR/empty.h", ""); 20590 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`)) 20591 { # detecting GCC default include paths 20592 next if(index($Line, "/cc1plus ")!=-1); 20593 20594 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) 20595 { 20596 my $Path = realpath($1); 20597 $Path = path_format($Path, $OSgroup); 20598 if(index($Path, "c++")!=-1 20599 or index($Path, "/g++/")!=-1) 20600 { 20601 push_U($DPaths{"Cpp"}, $Path); 20602 if(not defined $MAIN_CPP_DIR 20603 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) { 20604 $MAIN_CPP_DIR = $Path; 20605 } 20606 } 20607 elsif(index($Path, "gcc")!=-1) { 20608 push_U($DPaths{"Gcc"}, $Path); 20609 } 20610 else 20611 { 20612 if($Path=~/local[\/\\]+include/) 20613 { # local paths 20614 next; 20615 } 20616 if($SystemRoot 20617 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/) 20618 { # The GCC include path for user headers is not a part of the system root 20619 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler 20620 # or it is the internal cross-GCC path like arm-linux-gnueabi/include 20621 next; 20622 } 20623 push_U($DPaths{"Inc"}, $Path); 20624 } 20625 } 20626 } 20627 unlink("$TMP_DIR/empty.h"); 20628 return %DPaths; 20629} 20630 20631sub detect_default_paths($) 20632{ 20633 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1); 20634 my $Search = $_[0]; 20635 if($Search!~/inc/) { 20636 $HSearch = 0; 20637 } 20638 if($Search!~/lib/) { 20639 $LSearch = 0; 20640 } 20641 if($Search!~/bin/) { 20642 $BSearch = 0; 20643 } 20644 if($Search!~/gcc/) { 20645 $GSearch = 0; 20646 } 20647 if(@{$SystemPaths{"include"}}) 20648 { # <search_headers> section of the XML descriptor 20649 # do NOT search for systems headers 20650 $HSearch = 0; 20651 } 20652 if(@{$SystemPaths{"lib"}}) 20653 { # <search_headers> section of the XML descriptor 20654 # do NOT search for systems headers 20655 $LSearch = 0; 20656 } 20657 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}})) 20658 { # additional search paths 20659 next if($Type eq "include" and not $HSearch); 20660 next if($Type eq "lib" and not $LSearch); 20661 next if($Type eq "bin" and not $BSearch); 20662 push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}}); 20663 } 20664 if($OSgroup ne "windows") 20665 { # unix-like 20666 foreach my $Type ("include", "lib", "bin") 20667 { # automatic detection of system "devel" directories 20668 next if($Type eq "include" and not $HSearch); 20669 next if($Type eq "lib" and not $LSearch); 20670 next if($Type eq "bin" and not $BSearch); 20671 my ($UsrDir, $RootDir) = ("/usr", "/"); 20672 if($SystemRoot and $Type ne "bin") 20673 { # 1. search for target headers and libraries 20674 # 2. use host commands: ldconfig, readelf, etc. 20675 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot); 20676 } 20677 push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1)); 20678 if(-d $RootDir."/".$Type) 20679 { # if "/lib" is symbolic link 20680 if($RootDir eq "/") { 20681 push_U($SystemPaths{$Type}, "/".$Type); 20682 } 20683 else { 20684 push_U($SystemPaths{$Type}, $RootDir."/".$Type); 20685 } 20686 } 20687 if(-d $UsrDir) 20688 { 20689 push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1)); 20690 if(-d $UsrDir."/".$Type) 20691 { # if "/usr/lib" is symbolic link 20692 push_U($SystemPaths{$Type}, $UsrDir."/".$Type); 20693 } 20694 } 20695 } 20696 } 20697 if($BSearch) 20698 { 20699 detect_bin_default_paths(); 20700 push_U($SystemPaths{"bin"}, @DefaultBinPaths); 20701 } 20702 # check environment variables 20703 if($OSgroup eq "beos") 20704 { 20705 foreach (my @Paths = @{$SystemPaths{"bin"}}) 20706 { 20707 if($_ eq ".") { 20708 next; 20709 } 20710 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/ 20711 if(my @Dirs = sort cmd_find($_, "d", "bin")) { 20712 push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs); 20713 } 20714 } 20715 if($HSearch) 20716 { 20717 push_U(\@DefaultIncPaths, grep { is_abs($_) } ( 20718 split(/:|;/, $ENV{"BEINCLUDES"}) 20719 )); 20720 } 20721 if($LSearch) 20722 { 20723 push_U(\@DefaultLibPaths, grep { is_abs($_) } ( 20724 split(/:|;/, $ENV{"BELIBRARIES"}), 20725 split(/:|;/, $ENV{"LIBRARY_PATH"}) 20726 )); 20727 } 20728 } 20729 if($LSearch) 20730 { # using linker to get system paths 20731 if(my $LPaths = detect_lib_default_paths()) 20732 { # unix-like 20733 my %Dirs = (); 20734 foreach my $Name (keys(%{$LPaths})) 20735 { 20736 if($SystemRoot 20737 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//) 20738 { # wrong ldconfig configuration 20739 # check your <sysroot>/etc/ld.so.conf 20740 next; 20741 } 20742 $DyLib_DefaultPath{$Name} = $LPaths->{$Name}; 20743 if(my $Dir = get_dirname($LPaths->{$Name})) { 20744 $Dirs{$Dir} = 1; 20745 } 20746 } 20747 push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs)); 20748 } 20749 push_U($SystemPaths{"lib"}, @DefaultLibPaths); 20750 } 20751 if($BSearch) 20752 { 20753 if($CrossGcc) 20754 { # --cross-gcc=arm-linux-gcc 20755 if(-e $CrossGcc) 20756 { # absolute or relative path 20757 $GCC_PATH = get_abs_path($CrossGcc); 20758 } 20759 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc)) 20760 { # command name 20761 $GCC_PATH = $CrossGcc; 20762 } 20763 else { 20764 exitStatus("Access_Error", "can't access \'$CrossGcc\'"); 20765 } 20766 if($GCC_PATH=~/\s/) { 20767 $GCC_PATH = "\"".$GCC_PATH."\""; 20768 } 20769 } 20770 } 20771 if($GSearch) 20772 { # GCC path and default include dirs 20773 if(not $CrossGcc) 20774 { # try default gcc 20775 $GCC_PATH = get_CmdPath("gcc"); 20776 } 20777 if(not $GCC_PATH) 20778 { # try to find gcc-X.Y 20779 foreach my $Path (@{$SystemPaths{"bin"}}) 20780 { 20781 if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1)) 20782 { # select the latest version 20783 @GCCs = sort {$b cmp $a} @GCCs; 20784 if(check_gcc($GCCs[0], "3")) 20785 { 20786 $GCC_PATH = $GCCs[0]; 20787 last; 20788 } 20789 } 20790 } 20791 } 20792 if(not $GCC_PATH) { 20793 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); 20794 } 20795 20796 if(not $CheckObjectsOnly_Opt) 20797 { 20798 if(my $GCC_Ver = get_dumpversion($GCC_PATH)) 20799 { 20800 my $GccTarget = get_dumpmachine($GCC_PATH); 20801 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget, target: ".getArch_GCC(1).")"); 20802 if($GccTarget=~/symbian/) 20803 { 20804 $OStarget = "symbian"; 20805 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; 20806 } 20807 20808 # check GCC version 20809 if($GCC_Ver=~/\A4\.8(|\.[012])\Z/) 20810 { # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 20811 # introduced in 4.8 20812 # fixed in 4.8.3 20813 printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update or downgrade GCC or use a local installation by --gcc-path=PATH option."); 20814 $EMERGENCY_MODE_48 = 1; 20815 } 20816 } 20817 else { 20818 exitStatus("Error", "something is going wrong with the GCC compiler"); 20819 } 20820 } 20821 if($HSearch) 20822 { 20823 if(not $NoStdInc) 20824 { # do NOT search in GCC standard paths 20825 my %DPaths = detect_inc_default_paths(); 20826 @DefaultCppPaths = @{$DPaths{"Cpp"}}; 20827 @DefaultGccPaths = @{$DPaths{"Gcc"}}; 20828 @DefaultIncPaths = @{$DPaths{"Inc"}}; 20829 push_U($SystemPaths{"include"}, @DefaultIncPaths); 20830 } 20831 } 20832 } 20833 if($HSearch) 20834 { # users include paths 20835 my $IncPath = "/usr/include"; 20836 if($SystemRoot) { 20837 $IncPath = $SystemRoot.$IncPath; 20838 } 20839 if(-d $IncPath) { 20840 push_U(\@UsersIncPath, $IncPath); 20841 } 20842 } 20843 20844 if($ExtraInfo) 20845 { 20846 writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths)); 20847 writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths))); 20848 } 20849} 20850 20851sub getLIB_EXT($) 20852{ 20853 my $Target = $_[0]; 20854 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) { 20855 return $Ext; 20856 } 20857 return $OS_LibExt{$LIB_TYPE}{"default"}; 20858} 20859 20860sub getAR_EXT($) 20861{ 20862 my $Target = $_[0]; 20863 if(my $Ext = $OS_Archive{$Target}) { 20864 return $Ext; 20865 } 20866 return $OS_Archive{"default"}; 20867} 20868 20869sub get_dumpversion($) 20870{ 20871 my $Cmd = $_[0]; 20872 return "" if(not $Cmd); 20873 if($Cache{"get_dumpversion"}{$Cmd}) { 20874 return $Cache{"get_dumpversion"}{$Cmd}; 20875 } 20876 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`; 20877 chomp($V); 20878 return ($Cache{"get_dumpversion"}{$Cmd} = $V); 20879} 20880 20881sub get_dumpmachine($) 20882{ 20883 my $Cmd = $_[0]; 20884 return "" if(not $Cmd); 20885 if($Cache{"get_dumpmachine"}{$Cmd}) { 20886 return $Cache{"get_dumpmachine"}{$Cmd}; 20887 } 20888 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`; 20889 chomp($Machine); 20890 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine); 20891} 20892 20893sub checkCmd($) 20894{ 20895 my $Cmd = $_[0]; 20896 return "" if(not $Cmd); 20897 my @Options = ( 20898 "--version", 20899 "-help" 20900 ); 20901 foreach my $Opt (@Options) 20902 { 20903 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`; 20904 if($Info) { 20905 return 1; 20906 } 20907 } 20908 return 0; 20909} 20910 20911sub check_gcc($$) 20912{ 20913 my ($Cmd, $ReqVer) = @_; 20914 return 0 if(not $Cmd or not $ReqVer); 20915 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) { 20916 return $Cache{"check_gcc"}{$Cmd}{$ReqVer}; 20917 } 20918 if(my $GccVer = get_dumpversion($Cmd)) 20919 { 20920 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818") 20921 if(cmpVersions($GccVer, $ReqVer)>=0) { 20922 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd); 20923 } 20924 } 20925 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = ""); 20926} 20927 20928sub get_depth($) 20929{ 20930 if(defined $Cache{"get_depth"}{$_[0]}) { 20931 return $Cache{"get_depth"}{$_[0]}; 20932 } 20933 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!)); 20934} 20935 20936sub registerGccHeaders() 20937{ 20938 return if($Cache{"registerGccHeaders"}); # this function should be called once 20939 20940 foreach my $Path (@DefaultGccPaths) 20941 { 20942 my @Headers = cmd_find($Path,"f"); 20943 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 20944 foreach my $HPath (@Headers) 20945 { 20946 my $FileName = get_filename($HPath); 20947 if(not defined $DefaultGccHeader{$FileName}) 20948 { # skip duplicated 20949 $DefaultGccHeader{$FileName} = $HPath; 20950 } 20951 } 20952 } 20953 $Cache{"registerGccHeaders"} = 1; 20954} 20955 20956sub registerCppHeaders() 20957{ 20958 return if($Cache{"registerCppHeaders"}); # this function should be called once 20959 20960 foreach my $CppDir (@DefaultCppPaths) 20961 { 20962 my @Headers = cmd_find($CppDir,"f"); 20963 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 20964 foreach my $Path (@Headers) 20965 { 20966 my $FileName = get_filename($Path); 20967 if(not defined $DefaultCppHeader{$FileName}) 20968 { # skip duplicated 20969 $DefaultCppHeader{$FileName} = $Path; 20970 } 20971 } 20972 } 20973 $Cache{"registerCppHeaders"} = 1; 20974} 20975 20976sub parse_libname($$$) 20977{ 20978 return "" if(not $_[0]); 20979 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) { 20980 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}; 20981 } 20982 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_)); 20983} 20984 20985sub parse_libname_I($$$) 20986{ 20987 my ($Name, $Type, $Target) = @_; 20988 20989 if($Target eq "symbian") { 20990 return parse_libname_symbian($Name, $Type); 20991 } 20992 elsif($Target eq "windows") { 20993 return parse_libname_windows($Name, $Type); 20994 } 20995 20996 # unix 20997 my $Ext = getLIB_EXT($Target); 20998 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/) 20999 { # libSDL-1.2.so.0.7.1 21000 # libwbxml2.so.0.0.18 21001 # libopcodes-2.21.53-system.20110810.so 21002 if($Type eq "name") 21003 { # libSDL-1.2 21004 # libwbxml2 21005 return $2; 21006 } 21007 elsif($Type eq "name+ext") 21008 { # libSDL-1.2.so 21009 # libwbxml2.so 21010 return $1; 21011 } 21012 elsif($Type eq "version") 21013 { 21014 if(defined $7 21015 and $7 ne "") 21016 { # 0.7.1 21017 return $7; 21018 } 21019 else 21020 { # libc-2.5.so (=>2.5 version) 21021 my $MV = $5; 21022 $MV=~s/\A[\-\_]+//g; 21023 return $MV; 21024 } 21025 } 21026 elsif($Type eq "short") 21027 { # libSDL 21028 # libwbxml2 21029 return $3; 21030 } 21031 elsif($Type eq "shortest") 21032 { # SDL 21033 # wbxml 21034 return shortest_name($3); 21035 } 21036 } 21037 return "";# error 21038} 21039 21040sub parse_libname_symbian($$) 21041{ 21042 my ($Name, $Type) = @_; 21043 my $Ext = getLIB_EXT("symbian"); 21044 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/) 21045 { # libpthread{00010001}.dso 21046 if($Type eq "name") 21047 { # libpthread{00010001} 21048 return $2; 21049 } 21050 elsif($Type eq "name+ext") 21051 { # libpthread{00010001}.dso 21052 return $1; 21053 } 21054 elsif($Type eq "version") 21055 { # 00010001 21056 my $V = $4; 21057 $V=~s/\{(.+)\}/$1/; 21058 return $V; 21059 } 21060 elsif($Type eq "short") 21061 { # libpthread 21062 return $3; 21063 } 21064 elsif($Type eq "shortest") 21065 { # pthread 21066 return shortest_name($3); 21067 } 21068 } 21069 return "";# error 21070} 21071 21072sub parse_libname_windows($$) 21073{ 21074 my ($Name, $Type) = @_; 21075 my $Ext = getLIB_EXT("windows"); 21076 if($Name=~/((.+?)\.$Ext)\Z/) 21077 { # netapi32.dll 21078 if($Type eq "name") 21079 { # netapi32 21080 return $2; 21081 } 21082 elsif($Type eq "name+ext") 21083 { # netapi32.dll 21084 return $1; 21085 } 21086 elsif($Type eq "version") 21087 { # DLL version embedded 21088 # at binary-level 21089 return ""; 21090 } 21091 elsif($Type eq "short") 21092 { # netapi32 21093 return $2; 21094 } 21095 elsif($Type eq "shortest") 21096 { # netapi 21097 return shortest_name($2); 21098 } 21099 } 21100 return "";# error 21101} 21102 21103sub shortest_name($) 21104{ 21105 my $Name = $_[0]; 21106 # remove prefix 21107 $Name=~s/\A(lib|open)//; 21108 # remove suffix 21109 $Name=~s/[\W\d_]+\Z//i; 21110 $Name=~s/([a-z]{2,})(lib)\Z/$1/i; 21111 return $Name; 21112} 21113 21114sub createSymbolsList($$$$$) 21115{ 21116 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_; 21117 read_ABI_Dump(1, $DPath); 21118 if(not $CheckObjectsOnly) { 21119 prepareSymbols(1); 21120 } 21121 my %SymbolHeaderLib = (); 21122 my $Total = 0; 21123 # Get List 21124 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 21125 { 21126 if(not link_symbol($Symbol, 1, "-Deps")) 21127 { # skip src only and all external functions 21128 next; 21129 } 21130 if(not symbolFilter($Symbol, 1, "Public", "Binary")) 21131 { # skip other symbols 21132 next; 21133 } 21134 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 21135 if(not $HeaderName) 21136 { # skip src only and all external functions 21137 next; 21138 } 21139 my $DyLib = $Symbol_Library{1}{$Symbol}; 21140 if(not $DyLib) 21141 { # skip src only and all external functions 21142 next; 21143 } 21144 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1; 21145 $Total+=1; 21146 } 21147 # Draw List 21148 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)"; 21149 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>"; 21150 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib)) 21151 { 21152 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}})) 21153 { 21154 my %NS_Symbol = (); 21155 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) { 21156 $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 21157 } 21158 foreach my $NameSpace (sort keys(%NS_Symbol)) 21159 { 21160 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace); 21161 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}}); 21162 foreach my $Symbol (@SortedInterfaces) 21163 { 21164 my $SubReport = ""; 21165 my $Signature = get_Signature($Symbol, 1); 21166 if($NameSpace) { 21167 $Signature=~s/\b\Q$NameSpace\E::\b//g; 21168 } 21169 if($Symbol=~/\A(_Z|\?)/) 21170 { 21171 if($Signature) { 21172 $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n"); 21173 } 21174 else { 21175 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21176 } 21177 } 21178 else 21179 { 21180 if($Signature) { 21181 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 21182 } 21183 else { 21184 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21185 } 21186 } 21187 $SYMBOLS_LIST .= $SubReport; 21188 } 21189 } 21190 $SYMBOLS_LIST .= "<br/>\n"; 21191 } 21192 } 21193 # clear info 21194 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library, 21195 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols, 21196 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames, 21197 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = (); 21198 ($Content_Counter, $ContentID) = (0, 0); 21199 # print report 21200 my $CssStyles = readModule("Styles", "SymbolsList.css"); 21201 my $JScripts = readModule("Scripts", "Sections.js"); 21202 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n"; 21203 my $Title = "$LName: public symbols"; 21204 my $Keywords = "$LName, API, symbols"; 21205 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName); 21206 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)." 21207 <body><div>\n$SYMBOLS_LIST</div> 21208 <br/><br/><hr/>\n".getReportFooter($LName, 1)." 21209 </body></html>"; 21210 writeFile($SaveTo, $SYMBOLS_LIST); 21211} 21212 21213sub add_target_libs($) 21214{ 21215 foreach (@{$_[0]}) { 21216 $TargetLibs{$_} = 1; 21217 } 21218} 21219 21220sub is_target_lib($) 21221{ 21222 my $LName = $_[0]; 21223 if(not $LName) { 21224 return 0; 21225 } 21226 if($TargetLibraryName 21227 and $LName!~/\Q$TargetLibraryName\E/) { 21228 return 0; 21229 } 21230 if(keys(%TargetLibs) 21231 and not $TargetLibs{$LName} 21232 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) { 21233 return 0; 21234 } 21235 return 1; 21236} 21237 21238sub is_target_header($$) 21239{ # --header, --headers-list 21240 my ($H, $V) = @_; 21241 if(keys(%{$TargetHeaders{$V}})) 21242 { 21243 if($TargetHeaders{$V}{$H}) { 21244 return 1; 21245 } 21246 } 21247 return 0; 21248} 21249 21250sub checkVersionNum($$) 21251{ 21252 my ($LibVersion, $Path) = @_; 21253 if(my $VerNum = $TargetVersion{$LibVersion}) { 21254 return $VerNum; 21255 } 21256 my $UsedAltDescr = 0; 21257 foreach my $Part (split(/\s*,\s*/, $Path)) 21258 { # try to get version string from file path 21259 next if(isDump($Part)); # ABI dump 21260 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor 21261 my $VerNum = ""; 21262 if(parse_libname($Part, "name", $OStarget)) 21263 { 21264 $UsedAltDescr = 1; 21265 $VerNum = parse_libname($Part, "version", $OStarget); 21266 if(not $VerNum) { 21267 $VerNum = readStrVer($Part); 21268 } 21269 } 21270 elsif(is_header($Part, 2, $LibVersion) or -d $Part) 21271 { 21272 $UsedAltDescr = 1; 21273 $VerNum = readStrVer($Part); 21274 } 21275 if($VerNum ne "") 21276 { 21277 $TargetVersion{$LibVersion} = $VerNum; 21278 if($DumpAPI) { 21279 printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)"); 21280 } 21281 else { 21282 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)"); 21283 } 21284 return $TargetVersion{$LibVersion}; 21285 } 21286 } 21287 if($UsedAltDescr) 21288 { 21289 if($DumpAPI) { 21290 exitStatus("Error", "version number is not set (use -vnum option)"); 21291 } 21292 else { 21293 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)"); 21294 } 21295 } 21296} 21297 21298sub readStrVer($) 21299{ 21300 my $Str = $_[0]; 21301 return "" if(not $Str); 21302 $Str=~s/\Q$TargetLibraryName\E//g; 21303 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/) 21304 { # .../libssh-0.4.0/... 21305 return $2; 21306 } 21307 elsif(my $V = parse_libname($Str, "version", $OStarget)) { 21308 return $V; 21309 } 21310 return ""; 21311} 21312 21313sub readLibs($) 21314{ 21315 my $LibVersion = $_[0]; 21316 if($OStarget eq "windows") 21317 { # dumpbin.exe will crash 21318 # without VS Environment 21319 check_win32_env(); 21320 } 21321 readSymbols($LibVersion); 21322 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 21323 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 21324} 21325 21326sub dump_sorting($) 21327{ 21328 my $Hash = $_[0]; 21329 return [] if(not $Hash); 21330 my @Keys = keys(%{$Hash}); 21331 return [] if($#Keys<0); 21332 if($Keys[0]=~/\A\d+\Z/) 21333 { # numbers 21334 return [sort {int($a)<=>int($b)} @Keys]; 21335 } 21336 else 21337 { # strings 21338 return [sort {$a cmp $b} @Keys]; 21339 } 21340} 21341 21342sub printMsg($$) 21343{ 21344 my ($Type, $Msg) = @_; 21345 if($Type!~/\AINFO/) { 21346 $Msg = $Type.": ".$Msg; 21347 } 21348 if($Type!~/_C\Z/) { 21349 $Msg .= "\n"; 21350 } 21351 if($Quiet) 21352 { # --quiet option 21353 appendFile($COMMON_LOG_PATH, $Msg); 21354 } 21355 else 21356 { 21357 if($Type eq "ERROR") { 21358 print STDERR $Msg; 21359 } 21360 else { 21361 print $Msg; 21362 } 21363 } 21364} 21365 21366sub exitStatus($$) 21367{ 21368 my ($Code, $Msg) = @_; 21369 printMsg("ERROR", $Msg); 21370 exit($ERROR_CODE{$Code}); 21371} 21372 21373sub exitReport() 21374{ # the tool has run without any errors 21375 printReport(); 21376 if($COMPILE_ERRORS) 21377 { # errors in headers may add false positives/negatives 21378 exit($ERROR_CODE{"Compile_Error"}); 21379 } 21380 if($BinaryOnly and $RESULT{"Binary"}{"Problems"}) 21381 { # --binary 21382 exit($ERROR_CODE{"Incompatible"}); 21383 } 21384 elsif($SourceOnly and $RESULT{"Source"}{"Problems"}) 21385 { # --source 21386 exit($ERROR_CODE{"Incompatible"}); 21387 } 21388 elsif($RESULT{"Source"}{"Problems"} 21389 or $RESULT{"Binary"}{"Problems"}) 21390 { # default 21391 exit($ERROR_CODE{"Incompatible"}); 21392 } 21393 else { 21394 exit($ERROR_CODE{"Compatible"}); 21395 } 21396} 21397 21398sub readRules($) 21399{ 21400 my $Kind = $_[0]; 21401 if(not -f $RULES_PATH{$Kind}) { 21402 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'"); 21403 } 21404 my $Content = readFile($RULES_PATH{$Kind}); 21405 while(my $Rule = parseTag(\$Content, "rule")) 21406 { 21407 my $RId = parseTag(\$Rule, "id"); 21408 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind"); 21409 foreach my $Prop (@Properties) { 21410 if(my $Value = parseTag(\$Rule, lc($Prop))) 21411 { 21412 $Value=~s/\n[ ]*//; 21413 $CompatRules{$Kind}{$RId}{$Prop} = $Value; 21414 } 21415 } 21416 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) { 21417 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols"; 21418 } 21419 else { 21420 $CompatRules{$Kind}{$RId}{"Kind"} = "Types"; 21421 } 21422 } 21423} 21424 21425sub getReportPath($) 21426{ 21427 my $Level = $_[0]; 21428 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"}; 21429 if($Level eq "Binary") 21430 { 21431 if($BinaryReportPath) 21432 { # --bin-report-path 21433 return $BinaryReportPath; 21434 } 21435 elsif($OutputReportPath) 21436 { # --report-path 21437 return $OutputReportPath; 21438 } 21439 else 21440 { # default 21441 return $Dir."/abi_compat_report.$ReportFormat"; 21442 } 21443 } 21444 elsif($Level eq "Source") 21445 { 21446 if($SourceReportPath) 21447 { # --src-report-path 21448 return $SourceReportPath; 21449 } 21450 elsif($OutputReportPath) 21451 { # --report-path 21452 return $OutputReportPath; 21453 } 21454 else 21455 { # default 21456 return $Dir."/src_compat_report.$ReportFormat"; 21457 } 21458 } 21459 else 21460 { 21461 if($OutputReportPath) 21462 { # --report-path 21463 return $OutputReportPath; 21464 } 21465 else 21466 { # default 21467 return $Dir."/compat_report.$ReportFormat"; 21468 } 21469 } 21470} 21471 21472sub printStatMsg($) 21473{ 21474 my $Level = $_[0]; 21475 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"}); 21476} 21477 21478sub listAffected($) 21479{ 21480 my $Level = $_[0]; 21481 my $List = ""; 21482 foreach (keys(%{$TotalAffected{$Level}})) 21483 { 21484 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low") 21485 { # skip "Low"-severity problems 21486 next; 21487 } 21488 $List .= "$_\n"; 21489 } 21490 my $Dir = get_dirname(getReportPath($Level)); 21491 if($Level eq "Binary") { 21492 writeFile($Dir."/abi_affected.txt", $List); 21493 } 21494 elsif($Level eq "Source") { 21495 writeFile($Dir."/src_affected.txt", $List); 21496 } 21497} 21498 21499sub printReport() 21500{ 21501 printMsg("INFO", "creating compatibility report ..."); 21502 createReport(); 21503 if($JoinReport or $DoubleReport) 21504 { 21505 if($RESULT{"Binary"}{"Problems"} 21506 or $RESULT{"Source"}{"Problems"}) { 21507 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)"); 21508 } 21509 else { 21510 printMsg("INFO", "result: COMPATIBLE"); 21511 } 21512 printStatMsg("Binary"); 21513 printStatMsg("Source"); 21514 if($ListAffected) 21515 { # --list-affected 21516 listAffected("Binary"); 21517 listAffected("Source"); 21518 } 21519 } 21520 elsif($BinaryOnly) 21521 { 21522 if($RESULT{"Binary"}{"Problems"}) { 21523 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)"); 21524 } 21525 else { 21526 printMsg("INFO", "result: COMPATIBLE"); 21527 } 21528 printStatMsg("Binary"); 21529 if($ListAffected) 21530 { # --list-affected 21531 listAffected("Binary"); 21532 } 21533 } 21534 elsif($SourceOnly) 21535 { 21536 if($RESULT{"Source"}{"Problems"}) { 21537 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)"); 21538 } 21539 else { 21540 printMsg("INFO", "result: COMPATIBLE"); 21541 } 21542 printStatMsg("Source"); 21543 if($ListAffected) 21544 { # --list-affected 21545 listAffected("Source"); 21546 } 21547 } 21548 if($StdOut) 21549 { 21550 if($JoinReport or not $DoubleReport) 21551 { # --binary or --source 21552 printMsg("INFO", "compatibility report has been generated to stdout"); 21553 } 21554 else 21555 { # default 21556 printMsg("INFO", "compatibility reports have been generated to stdout"); 21557 } 21558 } 21559 else 21560 { 21561 if($JoinReport) 21562 { 21563 printMsg("INFO", "see detailed report:\n ".getReportPath("Join")); 21564 } 21565 elsif($DoubleReport) 21566 { # default 21567 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source")); 21568 } 21569 elsif($BinaryOnly) 21570 { # --binary 21571 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary")); 21572 } 21573 elsif($SourceOnly) 21574 { # --source 21575 printMsg("INFO", "see detailed report:\n ".getReportPath("Source")); 21576 } 21577 } 21578} 21579 21580sub check_win32_env() 21581{ 21582 if(not $ENV{"DevEnvDir"} 21583 or not $ENV{"LIB"}) { 21584 exitStatus("Error", "can't start without VS environment (vsvars32.bat)"); 21585 } 21586} 21587 21588sub diffSets($$) 21589{ 21590 my ($S1, $S2) = @_; 21591 my @SK1 = keys(%{$S1}); 21592 my @SK2 = keys(%{$S2}); 21593 if($#SK1!=$#SK2) { 21594 return 1; 21595 } 21596 foreach my $K1 (@SK1) 21597 { 21598 if(not defined $S2->{$K1}) { 21599 return 1; 21600 } 21601 } 21602 return 0; 21603} 21604 21605sub defaultDumpPath($$) 21606{ 21607 my ($N, $V) = @_; 21608 return "abi_dumps/".$N."/".$N."_".$V.".abi.".$AR_EXT; # gzipped by default 21609} 21610 21611sub create_ABI_Dump() 21612{ 21613 if(not -e $DumpAPI) { 21614 exitStatus("Access_Error", "can't access \'$DumpAPI\'"); 21615 } 21616 21617 my @DParts = split(/\s*,\s*/, $DumpAPI); 21618 foreach my $Part (@DParts) 21619 { 21620 if(not -e $Part) { 21621 exitStatus("Access_Error", "can't access \'$Part\'"); 21622 } 21623 } 21624 checkVersionNum(1, $DumpAPI); 21625 foreach my $Part (@DParts) 21626 { 21627 if(isDump($Part)) { 21628 read_ABI_Dump(1, $Part); 21629 } 21630 else { 21631 readDescriptor(1, createDescriptor(1, $Part)); 21632 } 21633 } 21634 21635 if(not $Descriptor{1}{"Version"}) 21636 { # set to default: X 21637 $Descriptor{1}{"Version"} = "X"; 21638 } 21639 21640 initLogging(1); 21641 detect_default_paths("inc|lib|bin|gcc"); # complete analysis 21642 21643 my $DumpPath = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 21644 if($OutputDumpPath) 21645 { # user defined path 21646 $DumpPath = $OutputDumpPath; 21647 } 21648 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g); 21649 21650 if(not $Archive and not $StdOut) 21651 { # check archive utilities 21652 if($OSgroup eq "windows") 21653 { # using zip 21654 my $ZipCmd = get_CmdPath("zip"); 21655 if(not $ZipCmd) { 21656 exitStatus("Not_Found", "can't find \"zip\""); 21657 } 21658 } 21659 else 21660 { # using tar and gzip 21661 my $TarCmd = get_CmdPath("tar"); 21662 if(not $TarCmd) { 21663 exitStatus("Not_Found", "can't find \"tar\""); 21664 } 21665 my $GzipCmd = get_CmdPath("gzip"); 21666 if(not $GzipCmd) { 21667 exitStatus("Not_Found", "can't find \"gzip\""); 21668 } 21669 } 21670 } 21671 21672 if(not $Descriptor{1}{"Dump"}) 21673 { 21674 if(not $CheckHeadersOnly) { 21675 readLibs(1); 21676 } 21677 if($CheckHeadersOnly) { 21678 setLanguage(1, "C++"); 21679 } 21680 if(not $CheckObjectsOnly) { 21681 searchForHeaders(1); 21682 } 21683 $WORD_SIZE{1} = detectWordSize(1); 21684 } 21685 if(not $Descriptor{1}{"Dump"}) 21686 { 21687 if($Descriptor{1}{"Headers"}) { 21688 readHeaders(1); 21689 } 21690 } 21691 cleanDump(1); 21692 if(not keys(%{$SymbolInfo{1}})) 21693 { # check if created dump is valid 21694 if(not $ExtendedCheck and not $CheckObjectsOnly) 21695 { 21696 if($CheckHeadersOnly) { 21697 exitStatus("Empty_Set", "the set of public symbols is empty"); 21698 } 21699 else { 21700 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection"); 21701 } 21702 } 21703 } 21704 my %HeadersInfo = (); 21705 foreach my $HPath (keys(%{$Registered_Headers{1}})) { 21706 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"}; 21707 } 21708 if($ExtraDump) 21709 { # add unmangled names to the ABI dump 21710 my @Names = (); 21711 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 21712 { 21713 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) { 21714 push(@Names, $MnglName); 21715 } 21716 } 21717 translateSymbols(@Names, 1); 21718 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 21719 { 21720 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) 21721 { 21722 if(my $Unmangled = $tr_name{$MnglName}) 21723 { 21724 if($MnglName ne $Unmangled) { 21725 $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled; 21726 } 21727 } 21728 } 21729 } 21730 } 21731 21732 my %GccConstants = (); # built-in GCC constants 21733 foreach my $Name (keys(%{$Constants{1}})) 21734 { 21735 if(not defined $Constants{1}{$Name}{"Header"}) 21736 { 21737 $GccConstants{$Name} = $Constants{1}{$Name}{"Value"}; 21738 delete($Constants{1}{$Name}); 21739 } 21740 } 21741 21742 printMsg("INFO", "creating library ABI dump ..."); 21743 my %ABI = ( 21744 "TypeInfo" => $TypeInfo{1}, 21745 "SymbolInfo" => $SymbolInfo{1}, 21746 "Symbols" => $Library_Symbol{1}, 21747 "DepSymbols" => $DepLibrary_Symbol{1}, 21748 "SymbolVersion" => $SymVer{1}, 21749 "LibraryVersion" => $Descriptor{1}{"Version"}, 21750 "LibraryName" => $TargetLibraryName, 21751 "Language" => $COMMON_LANGUAGE{1}, 21752 "SkipTypes" => $SkipTypes{1}, 21753 "SkipSymbols" => $SkipSymbols{1}, 21754 "SkipNameSpaces" => $SkipNameSpaces{1}, 21755 "SkipHeaders" => $SkipHeadersList{1}, 21756 "Headers" => \%HeadersInfo, 21757 "Constants" => $Constants{1}, 21758 "GccConstants" => \%GccConstants, 21759 "NameSpaces" => $NestedNameSpaces{1}, 21760 "Target" => $OStarget, 21761 "Arch" => getArch(1), 21762 "WordSize" => $WORD_SIZE{1}, 21763 "GccVersion" => get_dumpversion($GCC_PATH), 21764 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION, 21765 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION 21766 ); 21767 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) { 21768 $ABI{"TargetHeaders"} = $TargetHeaders{1}; 21769 } 21770 if($UseXML) { 21771 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION; 21772 } 21773 if($ExtendedCheck) 21774 { # --ext option 21775 $ABI{"Mode"} = "Extended"; 21776 } 21777 if($BinaryOnly) 21778 { # --binary 21779 $ABI{"BinOnly"} = 1; 21780 } 21781 if($ExtraDump) 21782 { # --extra-dump 21783 $ABI{"Extra"} = 1; 21784 $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1}; 21785 $ABI{"Needed"} = $Library_Needed{1}; 21786 } 21787 21788 my $ABI_DUMP = ""; 21789 if($UseXML) 21790 { 21791 loadModule("XmlDump"); 21792 $ABI_DUMP = createXmlDump(\%ABI); 21793 } 21794 else 21795 { # default 21796 $ABI_DUMP = Dumper(\%ABI); 21797 } 21798 if($StdOut) 21799 { # --stdout option 21800 print STDOUT $ABI_DUMP; 21801 printMsg("INFO", "ABI dump has been generated to stdout"); 21802 return; 21803 } 21804 else 21805 { # write to gzipped file 21806 my ($DDir, $DName) = separate_path($DumpPath); 21807 my $DPath = $TMP_DIR."/".$DName; 21808 if(not $Archive) { 21809 $DPath = $DumpPath; 21810 } 21811 21812 mkpath($DDir); 21813 21814 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n"); 21815 print DUMP $ABI_DUMP; 21816 close(DUMP); 21817 21818 if(not -s $DPath) { 21819 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module"); 21820 } 21821 if($Archive) { 21822 $DumpPath = createArchive($DPath, $DDir); 21823 } 21824 21825 if($OutputDumpPath) { 21826 printMsg("INFO", "library ABI has been dumped to:\n $OutputDumpPath"); 21827 } 21828 else { 21829 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath"); 21830 } 21831 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor"); 21832 } 21833} 21834 21835sub quickEmptyReports() 21836{ # Quick "empty" reports 21837 # 4 times faster than merging equal dumps 21838 # NOTE: the dump contains the "LibraryVersion" attribute 21839 # if you change the version, then your dump will be different 21840 # OVERCOME: use -v1 and v2 options for comparing dumps 21841 # and don't change version in the XML descriptor (and dumps) 21842 # OVERCOME 2: separate meta info from the dumps in ACC 2.0 21843 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) 21844 { 21845 my $FilePath1 = unpackDump($Descriptor{1}{"Path"}); 21846 my $FilePath2 = unpackDump($Descriptor{2}{"Path"}); 21847 if($FilePath1 and $FilePath2) 21848 { 21849 my $Line = readLineNum($FilePath1, 0); 21850 if($Line=~/xml/) 21851 { # XML format 21852 # is not supported yet 21853 return; 21854 } 21855 21856 local $/ = undef; 21857 21858 open(DUMP1, $FilePath1); 21859 my $Content1 = <DUMP1>; 21860 close(DUMP1); 21861 21862 open(DUMP2, $FilePath2); 21863 my $Content2 = <DUMP2>; 21864 close(DUMP2); 21865 21866 if($Content1 eq $Content2) 21867 { 21868 # clean memory 21869 undef $Content2; 21870 21871 # read a number of headers, libs, symbols and types 21872 my $ABIdump = eval($Content1); 21873 21874 # clean memory 21875 undef $Content1; 21876 21877 if(not $ABIdump) { 21878 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 21879 } 21880 if(not $ABIdump->{"TypeInfo"}) 21881 { # support for old dumps 21882 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"}; 21883 } 21884 if(not $ABIdump->{"SymbolInfo"}) 21885 { # support for old dumps 21886 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"}; 21887 } 21888 read_Source_DumpInfo($ABIdump, 1); 21889 read_Libs_DumpInfo($ABIdump, 1); 21890 read_Machine_DumpInfo($ABIdump, 1); 21891 read_Machine_DumpInfo($ABIdump, 2); 21892 21893 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}}; 21894 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}}; 21895 21896 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}}; 21897 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}}; 21898 21899 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"}; 21900 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"}; 21901 exitReport(); 21902 } 21903 } 21904 } 21905} 21906 21907sub initLogging($) 21908{ 21909 my $LibVersion = $_[0]; 21910 # create log directory 21911 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt"); 21912 if($OutputLogPath{$LibVersion}) 21913 { # user-defined by -log-path option 21914 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion}); 21915 } 21916 if($LogMode ne "n") { 21917 mkpath($LOG_DIR); 21918 } 21919 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE; 21920 if($Debug) 21921 { # debug directory 21922 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}; 21923 21924 if(not $ExtraInfo) 21925 { # enable --extra-info 21926 $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info"; 21927 } 21928 } 21929 resetLogging($LibVersion); 21930} 21931 21932sub writeLog($$) 21933{ 21934 my ($LibVersion, $Msg) = @_; 21935 if($LogMode ne "n") { 21936 appendFile($LOG_PATH{$LibVersion}, $Msg); 21937 } 21938} 21939 21940sub resetLogging($) 21941{ 21942 my $LibVersion = $_[0]; 21943 if($LogMode!~/a|n/) 21944 { # remove old log 21945 unlink($LOG_PATH{$LibVersion}); 21946 if($Debug) { 21947 rmtree($DEBUG_PATH{$LibVersion}); 21948 } 21949 } 21950} 21951 21952sub printErrorLog($) 21953{ 21954 my $LibVersion = $_[0]; 21955 if($LogMode ne "n") { 21956 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n"); 21957 } 21958} 21959 21960sub isDump($) 21961{ 21962 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz(\.\w+|)|\.zip|\.xml|)\Z/) 21963 { # NOTE: name.abi.tar.gz.amd64 (dh & cdbs) 21964 return $1; 21965 } 21966 return 0; 21967} 21968 21969sub isDump_U($) 21970{ 21971 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.xml|)\Z/) { 21972 return $1; 21973 } 21974 return 0; 21975} 21976 21977sub compareInit() 21978{ 21979 # read input XML descriptors or ABI dumps 21980 if(not $Descriptor{1}{"Path"}) { 21981 exitStatus("Error", "-old option is not specified"); 21982 } 21983 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"}); 21984 foreach my $Part (@DParts1) 21985 { 21986 if(not -e $Part) { 21987 exitStatus("Access_Error", "can't access \'$Part\'"); 21988 } 21989 } 21990 if(not $Descriptor{2}{"Path"}) { 21991 exitStatus("Error", "-new option is not specified"); 21992 } 21993 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"}); 21994 foreach my $Part (@DParts2) 21995 { 21996 if(not -e $Part) { 21997 exitStatus("Access_Error", "can't access \'$Part\'"); 21998 } 21999 } 22000 detect_default_paths("bin"); # to extract dumps 22001 if($#DParts1==0 and $#DParts2==0 22002 and isDump($Descriptor{1}{"Path"}) 22003 and isDump($Descriptor{2}{"Path"})) 22004 { # optimization: equal ABI dumps 22005 quickEmptyReports(); 22006 } 22007 checkVersionNum(1, $Descriptor{1}{"Path"}); 22008 checkVersionNum(2, $Descriptor{2}{"Path"}); 22009 printMsg("INFO", "preparation, please wait ..."); 22010 foreach my $Part (@DParts1) 22011 { 22012 if(isDump($Part)) { 22013 read_ABI_Dump(1, $Part); 22014 } 22015 else { 22016 readDescriptor(1, createDescriptor(1, $Part)); 22017 } 22018 } 22019 foreach my $Part (@DParts2) 22020 { 22021 if(isDump($Part)) { 22022 read_ABI_Dump(2, $Part); 22023 } 22024 else { 22025 readDescriptor(2, createDescriptor(2, $Part)); 22026 } 22027 } 22028 22029 if(not $Descriptor{1}{"Version"}) 22030 { # set to default: X 22031 $Descriptor{1}{"Version"} = "X"; 22032 } 22033 22034 if(not $Descriptor{2}{"Version"}) 22035 { # set to default: Y 22036 $Descriptor{2}{"Version"} = "Y"; 22037 } 22038 22039 initLogging(1); 22040 initLogging(2); 22041 # check consistency 22042 if(not $Descriptor{1}{"Headers"} 22043 and not $Descriptor{1}{"Libs"}) { 22044 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info"); 22045 } 22046 if(not $Descriptor{2}{"Headers"} 22047 and not $Descriptor{2}{"Libs"}) { 22048 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info"); 22049 } 22050 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"} 22051 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) { 22052 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries"); 22053 } 22054 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"} 22055 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) { 22056 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers"); 22057 } 22058 if(not $Descriptor{1}{"Headers"}) 22059 { 22060 if($CheckHeadersOnly_Opt) { 22061 exitStatus("Error", "can't find header files info in descriptor d1"); 22062 } 22063 } 22064 if(not $Descriptor{2}{"Headers"}) 22065 { 22066 if($CheckHeadersOnly_Opt) { 22067 exitStatus("Error", "can't find header files info in descriptor d2"); 22068 } 22069 } 22070 if(not $Descriptor{1}{"Headers"} 22071 or not $Descriptor{2}{"Headers"}) 22072 { 22073 if(not $CheckObjectsOnly_Opt) 22074 { 22075 printMsg("WARNING", "comparing $SLIB_TYPE libraries only"); 22076 $CheckObjectsOnly = 1; 22077 } 22078 } 22079 if(not $Descriptor{1}{"Libs"}) 22080 { 22081 if($CheckObjectsOnly_Opt) { 22082 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1"); 22083 } 22084 } 22085 if(not $Descriptor{2}{"Libs"}) 22086 { 22087 if($CheckObjectsOnly_Opt) { 22088 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2"); 22089 } 22090 } 22091 if(not $Descriptor{1}{"Libs"} 22092 or not $Descriptor{2}{"Libs"}) 22093 { # comparing standalone header files 22094 # comparing ABI dumps created with --headers-only 22095 if(not $CheckHeadersOnly_Opt) 22096 { 22097 printMsg("WARNING", "checking headers only"); 22098 $CheckHeadersOnly = 1; 22099 } 22100 } 22101 if($UseDumps) 22102 { # --use-dumps 22103 # parallel processing 22104 my $DumpPath1 = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 22105 my $DumpPath2 = defaultDumpPath($TargetLibraryName, $Descriptor{2}{"Version"}); 22106 22107 unlink($DumpPath1); 22108 unlink($DumpPath2); 22109 22110 my $pid = fork(); 22111 if($pid) 22112 { # dump on two CPU cores 22113 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName); 22114 if($RelativeDirectory{1}) { 22115 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1}); 22116 } 22117 if($OutputLogPath{1}) { 22118 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1}); 22119 } 22120 if($CrossGcc) { 22121 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22122 } 22123 if($Quiet) 22124 { 22125 @PARAMS = (@PARAMS, "-quiet"); 22126 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22127 } 22128 elsif($LogMode and $LogMode ne "w") 22129 { # "w" is default 22130 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22131 } 22132 if($ExtendedCheck) { 22133 @PARAMS = (@PARAMS, "-extended"); 22134 } 22135 if($UserLang) { 22136 @PARAMS = (@PARAMS, "-lang", $UserLang); 22137 } 22138 if($TargetVersion{1}) { 22139 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1}); 22140 } 22141 if($BinaryOnly) { 22142 @PARAMS = (@PARAMS, "-binary"); 22143 } 22144 if($SourceOnly) { 22145 @PARAMS = (@PARAMS, "-source"); 22146 } 22147 if($SortDump) { 22148 @PARAMS = (@PARAMS, "-sort"); 22149 } 22150 if($DumpFormat and $DumpFormat ne "perl") { 22151 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22152 } 22153 if($CheckHeadersOnly) { 22154 @PARAMS = (@PARAMS, "-headers-only"); 22155 } 22156 if($CheckObjectsOnly) { 22157 @PARAMS = (@PARAMS, "-objects-only"); 22158 } 22159 if($Debug) 22160 { 22161 @PARAMS = (@PARAMS, "-debug"); 22162 printMsg("INFO", "running perl $0 @PARAMS"); 22163 } 22164 system("perl", $0, @PARAMS); 22165 if(not -f $DumpPath1) { 22166 exit(1); 22167 } 22168 } 22169 else 22170 { # child 22171 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName); 22172 if($RelativeDirectory{2}) { 22173 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2}); 22174 } 22175 if($OutputLogPath{2}) { 22176 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2}); 22177 } 22178 if($CrossGcc) { 22179 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22180 } 22181 if($Quiet) 22182 { 22183 @PARAMS = (@PARAMS, "-quiet"); 22184 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22185 } 22186 elsif($LogMode and $LogMode ne "w") 22187 { # "w" is default 22188 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22189 } 22190 if($ExtendedCheck) { 22191 @PARAMS = (@PARAMS, "-extended"); 22192 } 22193 if($UserLang) { 22194 @PARAMS = (@PARAMS, "-lang", $UserLang); 22195 } 22196 if($TargetVersion{2}) { 22197 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2}); 22198 } 22199 if($BinaryOnly) { 22200 @PARAMS = (@PARAMS, "-binary"); 22201 } 22202 if($SourceOnly) { 22203 @PARAMS = (@PARAMS, "-source"); 22204 } 22205 if($SortDump) { 22206 @PARAMS = (@PARAMS, "-sort"); 22207 } 22208 if($DumpFormat and $DumpFormat ne "perl") { 22209 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22210 } 22211 if($CheckHeadersOnly) { 22212 @PARAMS = (@PARAMS, "-headers-only"); 22213 } 22214 if($CheckObjectsOnly) { 22215 @PARAMS = (@PARAMS, "-objects-only"); 22216 } 22217 if($Debug) 22218 { 22219 @PARAMS = (@PARAMS, "-debug"); 22220 printMsg("INFO", "running perl $0 @PARAMS"); 22221 } 22222 system("perl", $0, @PARAMS); 22223 if(not -f $DumpPath2) { 22224 exit(1); 22225 } 22226 else { 22227 exit(0); 22228 } 22229 } 22230 waitpid($pid, 0); 22231 22232 my @CMP_PARAMS = ("-l", $TargetLibraryName); 22233 @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1); 22234 @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2); 22235 if($TargetTitle ne $TargetLibraryName) { 22236 @CMP_PARAMS = (@CMP_PARAMS, "-title", $TargetTitle); 22237 } 22238 if($ShowRetVal) { 22239 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval"); 22240 } 22241 if($CrossGcc) { 22242 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc); 22243 } 22244 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a"); 22245 if($Quiet) { 22246 @CMP_PARAMS = (@CMP_PARAMS, "-quiet"); 22247 } 22248 if($ReportFormat and $ReportFormat ne "html") 22249 { # HTML is default format 22250 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat); 22251 } 22252 if($OutputReportPath) { 22253 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath); 22254 } 22255 if($BinaryReportPath) { 22256 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath); 22257 } 22258 if($SourceReportPath) { 22259 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath); 22260 } 22261 if($LoggingPath) { 22262 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath); 22263 } 22264 if($CheckHeadersOnly) { 22265 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only"); 22266 } 22267 if($CheckObjectsOnly) { 22268 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only"); 22269 } 22270 if($BinaryOnly) { 22271 @CMP_PARAMS = (@CMP_PARAMS, "-binary"); 22272 } 22273 if($SourceOnly) { 22274 @CMP_PARAMS = (@CMP_PARAMS, "-source"); 22275 } 22276 if($Debug) 22277 { 22278 @CMP_PARAMS = (@CMP_PARAMS, "-debug"); 22279 printMsg("INFO", "running perl $0 @CMP_PARAMS"); 22280 } 22281 system("perl", $0, @CMP_PARAMS); 22282 exit($?>>8); 22283 } 22284 if(not $Descriptor{1}{"Dump"} 22285 or not $Descriptor{2}{"Dump"}) 22286 { # need GCC toolchain to analyze 22287 # header files and libraries 22288 detect_default_paths("inc|lib|gcc"); 22289 } 22290 if(not $Descriptor{1}{"Dump"}) 22291 { 22292 if(not $CheckHeadersOnly) { 22293 readLibs(1); 22294 } 22295 if($CheckHeadersOnly) { 22296 setLanguage(1, "C++"); 22297 } 22298 if(not $CheckObjectsOnly) { 22299 searchForHeaders(1); 22300 } 22301 $WORD_SIZE{1} = detectWordSize(1); 22302 } 22303 if(not $Descriptor{2}{"Dump"}) 22304 { 22305 if(not $CheckHeadersOnly) { 22306 readLibs(2); 22307 } 22308 if($CheckHeadersOnly) { 22309 setLanguage(2, "C++"); 22310 } 22311 if(not $CheckObjectsOnly) { 22312 searchForHeaders(2); 22313 } 22314 $WORD_SIZE{2} = detectWordSize(2); 22315 } 22316 if($WORD_SIZE{1} ne $WORD_SIZE{2}) 22317 { # support for old ABI dumps 22318 # try to synch different WORD sizes 22319 if(not checkDump(1, "2.1")) 22320 { 22321 $WORD_SIZE{1} = $WORD_SIZE{2}; 22322 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes"); 22323 } 22324 elsif(not checkDump(2, "2.1")) 22325 { 22326 $WORD_SIZE{2} = $WORD_SIZE{1}; 22327 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes"); 22328 } 22329 } 22330 elsif(not $WORD_SIZE{1} 22331 and not $WORD_SIZE{2}) 22332 { # support for old ABI dumps 22333 $WORD_SIZE{1} = "4"; 22334 $WORD_SIZE{2} = "4"; 22335 } 22336 if($Descriptor{1}{"Dump"}) 22337 { # support for old ABI dumps 22338 prepareTypes(1); 22339 } 22340 if($Descriptor{2}{"Dump"}) 22341 { # support for old ABI dumps 22342 prepareTypes(2); 22343 } 22344 if($AppPath and not keys(%{$Symbol_Library{1}})) { 22345 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries"); 22346 } 22347 # started to process input data 22348 if(not $CheckObjectsOnly) 22349 { 22350 if($Descriptor{1}{"Headers"} 22351 and not $Descriptor{1}{"Dump"}) { 22352 readHeaders(1); 22353 } 22354 if($Descriptor{2}{"Headers"} 22355 and not $Descriptor{2}{"Dump"}) { 22356 readHeaders(2); 22357 } 22358 } 22359 22360 # clean memory 22361 %SystemHeaders = (); 22362 %mangled_name_gcc = (); 22363 22364 prepareSymbols(1); 22365 prepareSymbols(2); 22366 22367 # clean memory 22368 %SymbolInfo = (); 22369 22370 # Virtual Tables 22371 registerVTable(1); 22372 registerVTable(2); 22373 22374 if(not checkDump(1, "1.22") 22375 and checkDump(2, "1.22")) 22376 { # support for old ABI dumps 22377 foreach my $ClassName (keys(%{$VirtualTable{2}})) 22378 { 22379 if($ClassName=~/</) 22380 { # templates 22381 if(not defined $VirtualTable{1}{$ClassName}) 22382 { # synchronize 22383 delete($VirtualTable{2}{$ClassName}); 22384 } 22385 } 22386 } 22387 } 22388 22389 registerOverriding(1); 22390 registerOverriding(2); 22391 22392 setVirtFuncPositions(1); 22393 setVirtFuncPositions(2); 22394 22395 # Other 22396 addParamNames(1); 22397 addParamNames(2); 22398 22399 detectChangedTypedefs(); 22400} 22401 22402sub compareAPIs($) 22403{ 22404 my $Level = $_[0]; 22405 readRules($Level); 22406 loadModule("CallConv"); 22407 if($Level eq "Binary") { 22408 printMsg("INFO", "comparing ABIs ..."); 22409 } 22410 else { 22411 printMsg("INFO", "comparing APIs ..."); 22412 } 22413 if($CheckHeadersOnly 22414 or $Level eq "Source") 22415 { # added/removed in headers 22416 detectAdded_H($Level); 22417 detectRemoved_H($Level); 22418 } 22419 else 22420 { # added/removed in libs 22421 detectAdded($Level); 22422 detectRemoved($Level); 22423 } 22424 if(not $CheckObjectsOnly) 22425 { 22426 mergeSymbols($Level); 22427 if(keys(%{$CheckedSymbols{$Level}})) { 22428 mergeConstants($Level); 22429 } 22430 } 22431 22432 $Cache{"mergeTypes"} = (); # free memory 22433 22434 if($CheckHeadersOnly 22435 or $Level eq "Source") 22436 { # added/removed in headers 22437 mergeHeaders($Level); 22438 } 22439 else 22440 { # added/removed in libs 22441 mergeLibs($Level); 22442 } 22443} 22444 22445sub getSysOpts() 22446{ 22447 my %Opts = ( 22448 "OStarget"=>$OStarget, 22449 "Debug"=>$Debug, 22450 "Quiet"=>$Quiet, 22451 "LogMode"=>$LogMode, 22452 "CheckHeadersOnly"=>$CheckHeadersOnly, 22453 22454 "SystemRoot"=>$SystemRoot, 22455 "GCC_PATH"=>$GCC_PATH, 22456 "TargetSysInfo"=>$TargetSysInfo, 22457 "CrossPrefix"=>$CrossPrefix, 22458 "TargetLibraryName"=>$TargetLibraryName, 22459 "CrossGcc"=>$CrossGcc, 22460 "UseStaticLibs"=>$UseStaticLibs, 22461 "NoStdInc"=>$NoStdInc, 22462 22463 "BinaryOnly" => $BinaryOnly, 22464 "SourceOnly" => $SourceOnly 22465 ); 22466 return \%Opts; 22467} 22468 22469sub get_CodeError($) 22470{ 22471 my %CODE_ERROR = reverse(%ERROR_CODE); 22472 return $CODE_ERROR{$_[0]}; 22473} 22474 22475sub scenario() 22476{ 22477 if($StdOut) 22478 { # enable quiet mode 22479 $Quiet = 1; 22480 $JoinReport = 1; 22481 } 22482 if(not $LogMode) 22483 { # default 22484 $LogMode = "w"; 22485 } 22486 if($UserLang) 22487 { # --lang=C++ 22488 $UserLang = uc($UserLang); 22489 $COMMON_LANGUAGE{1}=$UserLang; 22490 $COMMON_LANGUAGE{2}=$UserLang; 22491 } 22492 if($LoggingPath) 22493 { 22494 $OutputLogPath{1} = $LoggingPath; 22495 $OutputLogPath{2} = $LoggingPath; 22496 if($Quiet) { 22497 $COMMON_LOG_PATH = $LoggingPath; 22498 } 22499 } 22500 if($Quick) { 22501 $ADD_TMPL_INSTANCES = 0; 22502 } 22503 if($OutputDumpPath) 22504 { # validate 22505 if(not isDump($OutputDumpPath)) { 22506 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file"); 22507 } 22508 } 22509 if($BinaryOnly and $SourceOnly) 22510 { # both --binary and --source 22511 # is the default mode 22512 $DoubleReport = 1; 22513 $JoinReport = 0; 22514 $BinaryOnly = 0; 22515 $SourceOnly = 0; 22516 if($OutputReportPath) 22517 { # --report-path 22518 $DoubleReport = 0; 22519 $JoinReport = 1; 22520 } 22521 } 22522 elsif($BinaryOnly or $SourceOnly) 22523 { # --binary or --source 22524 $DoubleReport = 0; 22525 $JoinReport = 0; 22526 } 22527 if($UseXML) 22528 { # --xml option 22529 $ReportFormat = "xml"; 22530 $DumpFormat = "xml"; 22531 } 22532 if($ReportFormat) 22533 { # validate 22534 $ReportFormat = lc($ReportFormat); 22535 if($ReportFormat!~/\A(xml|html|htm)\Z/) { 22536 exitStatus("Error", "unknown report format \'$ReportFormat\'"); 22537 } 22538 if($ReportFormat eq "htm") 22539 { # HTM == HTML 22540 $ReportFormat = "html"; 22541 } 22542 elsif($ReportFormat eq "xml") 22543 { # --report-format=XML equal to --xml 22544 $UseXML = 1; 22545 } 22546 } 22547 else 22548 { # default: HTML 22549 $ReportFormat = "html"; 22550 } 22551 if($DumpFormat) 22552 { # validate 22553 $DumpFormat = lc($DumpFormat); 22554 if($DumpFormat!~/\A(xml|perl)\Z/) { 22555 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'"); 22556 } 22557 if($DumpFormat eq "xml") 22558 { # --dump-format=XML equal to --xml 22559 $UseXML = 1; 22560 } 22561 } 22562 else 22563 { # default: Perl Data::Dumper 22564 $DumpFormat = "perl"; 22565 } 22566 if($Quiet and $LogMode!~/a|n/) 22567 { # --quiet log 22568 if(-f $COMMON_LOG_PATH) { 22569 unlink($COMMON_LOG_PATH); 22570 } 22571 } 22572 if($ExtraInfo) { 22573 $CheckUndefined = 1; 22574 } 22575 if($TestTool and $UseDumps) 22576 { # --test && --use-dumps == --test-dump 22577 $TestDump = 1; 22578 } 22579 if($Tolerant) 22580 { # enable all 22581 $Tolerance = 1234; 22582 } 22583 if($Help) 22584 { 22585 HELP_MESSAGE(); 22586 exit(0); 22587 } 22588 if($InfoMsg) 22589 { 22590 INFO_MESSAGE(); 22591 exit(0); 22592 } 22593 if($ShowVersion) 22594 { 22595 printMsg("INFO", "ABI Compliance Checker (ABICC) $TOOL_VERSION\nCopyright (C) 2015 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."); 22596 exit(0); 22597 } 22598 if($DumpVersion) 22599 { 22600 printMsg("INFO", $TOOL_VERSION); 22601 exit(0); 22602 } 22603 if($ExtendedCheck) { 22604 $CheckHeadersOnly = 1; 22605 } 22606 if($SystemRoot_Opt) 22607 { # user defined root 22608 if(not -e $SystemRoot_Opt) { 22609 exitStatus("Access_Error", "can't access \'$SystemRoot\'"); 22610 } 22611 $SystemRoot = $SystemRoot_Opt; 22612 $SystemRoot=~s/[\/]+\Z//g; 22613 if($SystemRoot) { 22614 $SystemRoot = get_abs_path($SystemRoot); 22615 } 22616 } 22617 $Data::Dumper::Sortkeys = 1; 22618 22619 if($SortDump) 22620 { 22621 $Data::Dumper::Useperl = 1; 22622 $Data::Dumper::Sortkeys = \&dump_sorting; 22623 } 22624 22625 if($TargetLibsPath) 22626 { 22627 if(not -f $TargetLibsPath) { 22628 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'"); 22629 } 22630 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) { 22631 $TargetLibs{$Lib} = 1; 22632 } 22633 } 22634 if($TargetHeadersPath) 22635 { # --headers-list 22636 if(not -f $TargetHeadersPath) { 22637 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'"); 22638 } 22639 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath))) 22640 { 22641 $TargetHeaders{1}{$Header} = 1; 22642 $TargetHeaders{2}{$Header} = 1; 22643 } 22644 } 22645 if($TargetHeader) 22646 { # --header 22647 $TargetHeaders{1}{$TargetHeader} = 1; 22648 $TargetHeaders{2}{$TargetHeader} = 1; 22649 } 22650 if($TestTool 22651 or $TestDump) 22652 { # --test, --test-dump 22653 detect_default_paths("bin|gcc"); # to compile libs 22654 loadModule("RegTests"); 22655 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, 22656 $LIB_EXT, $GCC_PATH, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly); 22657 exit(0); 22658 } 22659 if($DumpSystem) 22660 { # --dump-system 22661 22662 if(not $TargetSysInfo) { 22663 exitStatus("Error", "-sysinfo option should be specified to dump system ABI"); 22664 } 22665 22666 if(not -d $TargetSysInfo) { 22667 exitStatus("Access_Error", "can't access \'$TargetSysInfo\'"); 22668 } 22669 22670 loadModule("SysCheck"); 22671 if($DumpSystem=~/\.(xml|desc)\Z/) 22672 { # system XML descriptor 22673 if(not -f $DumpSystem) { 22674 exitStatus("Access_Error", "can't access file \'$DumpSystem\'"); 22675 } 22676 my $Ret = readSystemDescriptor(readFile($DumpSystem)); 22677 foreach (@{$Ret->{"Tools"}}) 22678 { 22679 push_U($SystemPaths{"bin"}, $_); 22680 $TargetTools{$_} = 1; 22681 } 22682 if($Ret->{"CrossPrefix"}) { 22683 $CrossPrefix = $Ret->{"CrossPrefix"}; 22684 } 22685 } 22686 elsif($SystemRoot_Opt) 22687 { # -sysroot "/" option 22688 # default target: /usr/lib, /usr/include 22689 # search libs: /usr/lib and /lib 22690 if(not -e $SystemRoot."/usr/lib") { 22691 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'"); 22692 } 22693 if(not -e $SystemRoot."/lib") { 22694 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'"); 22695 } 22696 if(not -e $SystemRoot."/usr/include") { 22697 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'"); 22698 } 22699 readSystemDescriptor(" 22700 <name> 22701 $DumpSystem 22702 </name> 22703 <headers> 22704 $SystemRoot/usr/include 22705 </headers> 22706 <libs> 22707 $SystemRoot/usr/lib 22708 </libs> 22709 <search_libs> 22710 $SystemRoot/lib 22711 </search_libs>"); 22712 } 22713 else { 22714 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\""); 22715 } 22716 detect_default_paths("bin|gcc"); # to check symbols 22717 if($OStarget eq "windows") 22718 { # to run dumpbin.exe 22719 # and undname.exe 22720 check_win32_env(); 22721 } 22722 dumpSystem(getSysOpts()); 22723 exit(0); 22724 } 22725 if($CmpSystems) 22726 { # --cmp-systems 22727 detect_default_paths("bin"); # to extract dumps 22728 loadModule("SysCheck"); 22729 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts()); 22730 exit(0); 22731 } 22732 if(not $TargetLibraryName) { 22733 exitStatus("Error", "library name is not selected (-l option)"); 22734 } 22735 else 22736 { # validate library name 22737 if($TargetLibraryName=~/[\*\/\\]/) { 22738 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name"); 22739 } 22740 } 22741 if(not $TargetTitle) { 22742 $TargetTitle = $TargetLibraryName; 22743 } 22744 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) { 22745 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time"); 22746 } 22747 if($SymbolsListPath) 22748 { 22749 if(not -f $SymbolsListPath) { 22750 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'"); 22751 } 22752 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) { 22753 $SymbolsList{$Interface} = 1; 22754 } 22755 } 22756 if($TypesListPath) 22757 { 22758 if(not -f $TypesListPath) { 22759 exitStatus("Access_Error", "can't access file \'$TypesListPath\'"); 22760 } 22761 foreach my $Type (split(/\s*\n\s*/, readFile($TypesListPath))) { 22762 $TypesList{$Type} = 1; 22763 } 22764 } 22765 if($SkipSymbolsListPath) 22766 { 22767 if(not -f $SkipSymbolsListPath) { 22768 exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'"); 22769 } 22770 foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) { 22771 $SkipSymbols{$Interface} = 1; 22772 } 22773 } 22774 if($SkipHeadersPath) 22775 { 22776 if(not -f $SkipHeadersPath) { 22777 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'"); 22778 } 22779 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath))) 22780 { # register for both versions 22781 $SkipHeadersList{1}{$Path} = 1; 22782 $SkipHeadersList{2}{$Path} = 1; 22783 my ($CPath, $Type) = classifyPath($Path); 22784 $SkipHeaders{1}{$Type}{$CPath} = 1; 22785 $SkipHeaders{2}{$Type}{$CPath} = 1; 22786 } 22787 } 22788 if($ParamNamesPath) 22789 { 22790 if(not -f $ParamNamesPath) { 22791 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'"); 22792 } 22793 foreach my $Line (split(/\n/, readFile($ParamNamesPath))) 22794 { 22795 if($Line=~s/\A(\w+)\;//) 22796 { 22797 my $Interface = $1; 22798 if($Line=~/;(\d+);/) 22799 { 22800 while($Line=~s/(\d+);(\w+)//) { 22801 $AddIntParams{$Interface}{$1}=$2; 22802 } 22803 } 22804 else 22805 { 22806 my $Num = 0; 22807 foreach my $Name (split(/;/, $Line)) { 22808 $AddIntParams{$Interface}{$Num++}=$Name; 22809 } 22810 } 22811 } 22812 } 22813 } 22814 if($AppPath) 22815 { 22816 if(not -f $AppPath) { 22817 exitStatus("Access_Error", "can't access file \'$AppPath\'"); 22818 } 22819 foreach my $Interface (readSymbols_App($AppPath)) { 22820 $SymbolsList_App{$Interface} = 1; 22821 } 22822 } 22823 if($DumpAPI) 22824 { # --dump-abi 22825 # make an API dump 22826 create_ABI_Dump(); 22827 exit($COMPILE_ERRORS); 22828 } 22829 # default: compare APIs 22830 # -d1 <path> 22831 # -d2 <path> 22832 compareInit(); 22833 if($JoinReport or $DoubleReport) 22834 { 22835 compareAPIs("Binary"); 22836 compareAPIs("Source"); 22837 } 22838 elsif($BinaryOnly) { 22839 compareAPIs("Binary"); 22840 } 22841 elsif($SourceOnly) { 22842 compareAPIs("Source"); 22843 } 22844 exitReport(); 22845} 22846 22847scenario(); 22848