abi-compliance-checker.pl revision ba8922775121372b6e35f925f3938282ef03019e
1#!/usr/bin/perl 2########################################################################### 3# ABI Compliance Checker (ABICC) 1.99.17 4# A tool for checking backward compatibility of a C/C++ library API 5# 6# Copyright (C) 2009-2011 Institute for System Programming, RAS 7# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) 8# Copyright (C) 2011-2012 ROSA Laboratory 9# Copyright (C) 2012-2016 Andrey Ponomarenko's ABI Laboratory 10# 11# Written by Andrey Ponomarenko 12# 13# PLATFORMS 14# ========= 15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian 16# 17# REQUIREMENTS 18# ============ 19# Linux 20# - G++ (3.0-4.7, 4.8.3, 4.9 or newer) 21# - GNU Binutils (readelf, c++filt, objdump) 22# - Perl 5 (5.8 or newer) 23# - Ctags (5.8 or newer) 24# - ABI Dumper (0.99.15 or newer) 25# 26# Mac OS X 27# - Xcode (g++, c++filt, otool, nm) 28# - Ctags (5.8 or newer) 29# 30# MS Windows 31# - MinGW (3.0-4.7, 4.8.3, 4.9 or newer) 32# - MS Visual C++ (dumpbin, undname, cl) 33# - Active Perl 5 (5.8 or newer) 34# - Sigcheck v1.71 or newer 35# - Info-ZIP 3.0 (zip, unzip) 36# - Ctags (5.8 or newer) 37# - Add tool locations to the PATH environment variable 38# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\) 39# 40# This program is free software: you can redistribute it and/or modify 41# it under the terms of the GNU General Public License or the GNU Lesser 42# General Public License as published by the Free Software Foundation. 43# 44# This program is distributed in the hope that it will be useful, 45# but WITHOUT ANY WARRANTY; without even the implied warranty of 46# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47# GNU General Public License for more details. 48# 49# You should have received a copy of the GNU General Public License 50# and the GNU Lesser General Public License along with this program. 51# If not, see <http://www.gnu.org/licenses/>. 52########################################################################### 53use Getopt::Long; 54Getopt::Long::Configure ("posix_default", "no_ignore_case"); 55use File::Path qw(mkpath rmtree); 56use File::Temp qw(tempdir); 57use File::Copy qw(copy move); 58use Cwd qw(abs_path cwd realpath); 59use Storable qw(dclone); 60use Data::Dumper; 61use Config; 62 63my $TOOL_VERSION = "1.99.17"; 64my $ABI_DUMP_VERSION = "3.2"; 65my $XML_REPORT_VERSION = "1.2"; 66my $XML_ABI_DUMP_VERSION = "1.2"; 67my $OSgroup = get_OSgroup(); 68my $ORIG_DIR = cwd(); 69my $TMP_DIR = tempdir(CLEANUP=>1); 70my $LOCALE = "C.UTF-8"; 71 72# Internal modules 73my $MODULES_DIR = get_Modules(); 74push(@INC, get_dirname($MODULES_DIR)); 75# Rules DB 76my %RULES_PATH = ( 77 "Binary" => $MODULES_DIR."/RulesBin.xml", 78 "Source" => $MODULES_DIR."/RulesSrc.xml"); 79 80my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, 81$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps, 82$AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath, 83%RelativeDirectory, $TargetTitle, $TestDump, $LoggingPath, 84%TargetVersion, $InfoMsg, $CrossGcc, %OutputLogPath, 85$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem, 86$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc, 87$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet, 88$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, 89$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, 90$SourceReportPath, $UseXML, $SortDump, $DumpFormat, 91$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, 92$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat, 93$SkipInternalSymbols, $SkipInternalTypes, $TargetArch, $GccOptions, 94$TypesListPath, $SkipTypesListPath, $CheckPrivateABI); 95 96my $CmdName = get_filename($0); 97my %OS_LibExt = ( 98 "dynamic" => { 99 "linux"=>"so", 100 "macos"=>"dylib", 101 "windows"=>"dll", 102 "symbian"=>"dso", 103 "default"=>"so" 104 }, 105 "static" => { 106 "linux"=>"a", 107 "windows"=>"lib", 108 "symbian"=>"lib", 109 "default"=>"a" 110 } 111); 112 113my %OS_Archive = ( 114 "windows"=>"zip", 115 "default"=>"tar.gz" 116); 117 118my %ERROR_CODE = ( 119 # Compatible verdict 120 "Compatible"=>0, 121 "Success"=>0, 122 # Incompatible verdict 123 "Incompatible"=>1, 124 # Undifferentiated error code 125 "Error"=>2, 126 # System command is not found 127 "Not_Found"=>3, 128 # Cannot access input files 129 "Access_Error"=>4, 130 # Cannot compile header files 131 "Cannot_Compile"=>5, 132 # Header compiled with errors 133 "Compile_Error"=>6, 134 # Invalid input ABI dump 135 "Invalid_Dump"=>7, 136 # Incompatible version of ABI dump 137 "Dump_Version"=>8, 138 # Cannot find a module 139 "Module_Error"=>9, 140 # Empty intersection between 141 # headers and shared objects 142 "Empty_Intersection"=>10, 143 # Empty set of symbols in headers 144 "Empty_Set"=>11 145); 146 147my $HomePage = "http://lvc.github.io/abi-compliance-checker/"; 148 149my $ShortUsage = "ABI Compliance Checker (ABICC) $TOOL_VERSION 150A tool for checking backward compatibility of a C/C++ library API 151Copyright (C) 2015 Andrey Ponomarenko's ABI Laboratory 152License: GNU LGPL or GNU GPL 153 154Usage: $CmdName [options] 155Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml 156 157OLD.xml and NEW.xml are XML-descriptors: 158 159 <version> 160 1.0 161 </version> 162 163 <headers> 164 /path/to/headers/ 165 </headers> 166 167 <libs> 168 /path/to/libraries/ 169 </libs> 170 171More info: $CmdName --help\n"; 172 173if($#ARGV==-1) 174{ 175 printMsg("INFO", $ShortUsage); 176 exit(0); 177} 178 179GetOptions("h|help!" => \$Help, 180 "i|info!" => \$InfoMsg, 181 "v|version!" => \$ShowVersion, 182 "dumpversion!" => \$DumpVersion, 183# general options 184 "l|lib|library=s" => \$TargetLibraryName, 185 "d1|old|o=s" => \$Descriptor{1}{"Path"}, 186 "d2|new|n=s" => \$Descriptor{2}{"Path"}, 187 "dump|dump-abi|dump_abi=s" => \$DumpAPI, 188# extra options 189 "app|application=s" => \$AppPath, 190 "static-libs!" => \$UseStaticLibs, 191 "gcc-path|cross-gcc=s" => \$CrossGcc, 192 "gcc-prefix|cross-prefix=s" => \$CrossPrefix, 193 "gcc-options=s" => \$GccOptions, 194 "sysroot=s" => \$SystemRoot_Opt, 195 "v1|vnum1|version1|vnum=s" => \$TargetVersion{1}, 196 "v2|vnum2|version2=s" => \$TargetVersion{2}, 197 "s|strict!" => \$StrictCompat, 198 "symbols-list=s" => \$SymbolsListPath, 199 "types-list=s" => \$TypesListPath, 200 "skip-symbols=s" => \$SkipSymbolsListPath, 201 "skip-types=s" => \$SkipTypesListPath, 202 "headers-list=s" => \$TargetHeadersPath, 203 "skip-headers=s" => \$SkipHeadersPath, 204 "header=s" => \$TargetHeader, 205 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt, 206 "show-retval!" => \$ShowRetVal, 207 "use-dumps!" => \$UseDumps, 208 "nostdinc!" => \$NoStdInc, 209 "dump-system=s" => \$DumpSystem, 210 "sysinfo=s" => \$TargetSysInfo, 211 "cmp-systems!" => \$CmpSystems, 212 "libs-list=s" => \$TargetLibsPath, 213 "ext|extended!" => \$ExtendedCheck, 214 "q|quiet!" => \$Quiet, 215 "stdout!" => \$StdOut, 216 "report-format=s" => \$ReportFormat, 217 "dump-format=s" => \$DumpFormat, 218 "xml!" => \$UseXML, 219 "lang=s" => \$UserLang, 220 "arch=s" => \$TargetArch, 221 "binary|bin|abi!" => \$BinaryOnly, 222 "source|src|api!" => \$SourceOnly, 223 "limit-affected|affected-limit=s" => \$AffectLimit, 224# other options 225 "test!" => \$TestTool, 226 "test-dump!" => \$TestDump, 227 "debug!" => \$Debug, 228 "cpp-compatible!" => \$CppCompat, 229 "cpp-incompatible!" => \$CppIncompat, 230 "p|params=s" => \$ParamNamesPath, 231 "relpath1|relpath=s" => \$RelativeDirectory{1}, 232 "relpath2=s" => \$RelativeDirectory{2}, 233 "dump-path=s" => \$OutputDumpPath, 234 "sort!" => \$SortDump, 235 "report-path=s" => \$OutputReportPath, 236 "bin-report-path=s" => \$BinaryReportPath, 237 "src-report-path=s" => \$SourceReportPath, 238 "log-path=s" => \$LoggingPath, 239 "log1-path=s" => \$OutputLogPath{1}, 240 "log2-path=s" => \$OutputLogPath{2}, 241 "logging-mode=s" => \$LogMode, 242 "list-affected!" => \$ListAffected, 243 "title|l-full|lib-full=s" => \$TargetTitle, 244 "component=s" => \$TargetComponent_Opt, 245 "extra-info=s" => \$ExtraInfo, 246 "extra-dump!" => \$ExtraDump, 247 "force!" => \$Force, 248 "tolerance=s" => \$Tolerance, 249 "tolerant!" => \$Tolerant, 250 "check!" => \$CheckInfo, 251 "quick!" => \$Quick, 252 "all-affected!" => \$AllAffected, 253 "skip-internal-symbols|skip-internal=s" => \$SkipInternalSymbols, 254 "skip-internal-types=s" => \$SkipInternalTypes, 255 "check-private-abi!" => \$CheckPrivateABI 256) or ERR_MESSAGE(); 257 258sub ERR_MESSAGE() 259{ 260 printMsg("INFO", "\n".$ShortUsage); 261 exit($ERROR_CODE{"Error"}); 262} 263 264my $LIB_TYPE = $UseStaticLibs?"static":"dynamic"; 265my $SLIB_TYPE = $LIB_TYPE; 266if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic") 267{ # show as "shared" library 268 $SLIB_TYPE = "shared"; 269} 270my $LIB_EXT = getLIB_EXT($OSgroup); 271my $AR_EXT = getAR_EXT($OSgroup); 272my $BYTE_SIZE = 8; 273my $COMMON_LOG_PATH = "logs/run.log"; 274 275my $HelpMessage=" 276NAME: 277 ABI Compliance Checker ($CmdName) 278 Check backward compatibility of a C/C++ library API 279 280DESCRIPTION: 281 ABI Compliance Checker (ABICC) is a tool for checking backward binary and 282 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks 283 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and 284 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary 285 and/or source-level compatibility: changes in calling stack, v-table changes, 286 removed symbols, renamed fields, etc. Binary incompatibility may result in 287 crashing or incorrect behavior of applications built with an old version of 288 a library if they run on a new one. Source incompatibility may result in 289 recompilation errors with a new library version. 290 291 The tool is intended for developers of software libraries and maintainers 292 of operating systems who are interested in ensuring backward compatibility, 293 i.e. allow old applications to run or to be recompiled with newer library 294 versions. 295 296 Also the tool can be used by ISVs for checking applications portability to 297 new library versions. Found issues can be taken into account when adapting 298 the application to a new library version. 299 300 This tool is free software: you can redistribute it and/or modify it 301 under the terms of the GNU LGPL or GNU GPL. 302 303USAGE: 304 $CmdName [options] 305 306EXAMPLE: 307 $CmdName -lib NAME -old OLD.xml -new NEW.xml 308 309 OLD.xml and NEW.xml are XML-descriptors: 310 311 <version> 312 1.0 313 </version> 314 315 <headers> 316 /path1/to/header(s)/ 317 /path2/to/header(s)/ 318 ... 319 </headers> 320 321 <libs> 322 /path1/to/library(ies)/ 323 /path2/to/library(ies)/ 324 ... 325 </libs> 326 327INFORMATION OPTIONS: 328 -h|-help 329 Print this help. 330 331 -i|-info 332 Print complete info. 333 334 -v|-version 335 Print version information. 336 337 -dumpversion 338 Print the tool version ($TOOL_VERSION) and don't do anything else. 339 340GENERAL OPTIONS: 341 -l|-lib|-library NAME 342 Library name (without version). 343 344 -d1|-old|-o PATH 345 Descriptor of 1st (old) library version. 346 It may be one of the following: 347 348 1. XML-descriptor (VERSION.xml file): 349 350 <version> 351 1.0 352 </version> 353 354 <headers> 355 /path1/to/header(s)/ 356 /path2/to/header(s)/ 357 ... 358 </headers> 359 360 <libs> 361 /path1/to/library(ies)/ 362 /path2/to/library(ies)/ 363 ... 364 </libs> 365 366 ... 367 368 2. ABI dump generated by -dump option 369 3. Directory with headers and/or $SLIB_TYPE libraries 370 4. Single header file 371 372 If you are using an 2-4 descriptor types then you should 373 specify version numbers with -v1 and -v2 options too. 374 375 For more information, please see: 376 http://ispras.linuxbase.org/index.php/Library_Descriptor 377 378 -d2|-new|-n PATH 379 Descriptor of 2nd (new) library version. 380 381 -dump|-dump-abi PATH 382 Create library ABI dump for the input XML descriptor. You can 383 transfer it anywhere and pass instead of the descriptor. Also 384 it can be used for debugging the tool. 385 386 Supported versions of ABI dump: 2.0<=V<=$ABI_DUMP_VERSION\n"; 387 388sub HELP_MESSAGE() { 389 printMsg("INFO", $HelpMessage." 390MORE INFO: 391 $CmdName --info\n"); 392} 393 394sub INFO_MESSAGE() 395{ 396 printMsg("INFO", "$HelpMessage 397EXTRA OPTIONS: 398 -app|-application PATH 399 This option allows to specify the application that should be checked 400 for portability to the new library version. 401 402 -static-libs 403 Check static libraries instead of the shared ones. The <libs> section 404 of the XML-descriptor should point to static libraries location. 405 406 -gcc-path PATH 407 Path to the cross GCC compiler to use instead of the usual (host) GCC. 408 409 -gcc-prefix PREFIX 410 GCC toolchain prefix. 411 412 -gcc-options OPTS 413 Additional compiler options. 414 415 -sysroot DIR 416 Specify the alternative root directory. The tool will search for include 417 paths in the DIR/usr/include and DIR/usr/lib directories. 418 419 -v1|-version1 NUM 420 Specify 1st library version outside the descriptor. This option is needed 421 if you have preferred an alternative descriptor type (see -d1 option). 422 423 In general case you should specify it in the XML-descriptor: 424 <version> 425 VERSION 426 </version> 427 428 -v2|-version2 NUM 429 Specify 2nd library version outside the descriptor. 430 431 -vnum NUM 432 Specify the library version in the generated ABI dump. The <version> section 433 of the input XML descriptor will be overwritten in this case. 434 435 -s|-strict 436 Treat all compatibility warnings as problems. Add a number of \"Low\" 437 severity problems to the return value of the tool. 438 439 -headers-only 440 Check header files without $SLIB_TYPE libraries. It is easy to run, but may 441 provide a low quality compatibility report with false positives and 442 without detecting of added/removed symbols. 443 444 Alternatively you can write \"none\" word to the <libs> section 445 in the XML-descriptor: 446 <libs> 447 none 448 </libs> 449 450 -show-retval 451 Show the symbol's return type in the report. 452 453 -symbols-list PATH 454 This option allows to specify a file with a list of symbols (mangled 455 names in C++) that should be checked. Other symbols will not be checked. 456 457 -types-list PATH 458 This option allows to specify a file with a list of types that should 459 be checked. Other types will not be checked. 460 461 -skip-symbols PATH 462 The list of symbols that should not be checked. 463 464 -skip-types PATH 465 The list of types that should not be checked. 466 467 -headers-list PATH 468 The file with a list of headers, that should be checked/dumped. 469 470 -skip-headers PATH 471 The file with the list of header files, that should not be checked. 472 473 -header NAME 474 Check/Dump ABI of this header only. 475 476 -use-dumps 477 Make dumps for two versions of a library and compare dumps. This should 478 increase the performance of the tool and decrease the system memory usage. 479 480 -nostdinc 481 Do not search in GCC standard system directories for header files. 482 483 -dump-system NAME -sysroot DIR 484 Find all the shared libraries and header files in DIR directory, 485 create XML descriptors and make ABI dumps for each library. The result 486 set of ABI dumps can be compared (--cmp-systems) with the other one 487 created for other version of operating system in order to check them for 488 compatibility. Do not forget to specify -cross-gcc option if your target 489 system requires some specific version of GCC compiler (different from 490 the host GCC). The system ABI dump will be generated to: 491 sys_dumps/NAME/ARCH 492 493 -dump-system DESCRIPTOR.xml 494 The same as the previous option but takes an XML descriptor of the target 495 system as input, where you should describe it: 496 497 /* Primary sections */ 498 499 <name> 500 /* Name of the system */ 501 </name> 502 503 <headers> 504 /* The list of paths to header files and/or 505 directories with header files, one per line */ 506 </headers> 507 508 <libs> 509 /* The list of paths to shared libraries and/or 510 directories with shared libraries, one per line */ 511 </libs> 512 513 /* Optional sections */ 514 515 <search_headers> 516 /* List of directories to be searched 517 for header files to automatically 518 generate include paths, one per line */ 519 </search_headers> 520 521 <search_libs> 522 /* List of directories to be searched 523 for shared libraries to resolve 524 dependencies, one per line */ 525 </search_libs> 526 527 <tools> 528 /* List of directories with tools used 529 for analysis (GCC toolchain), one per line */ 530 </tools> 531 532 <cross_prefix> 533 /* GCC toolchain prefix. 534 Examples: 535 arm-linux-gnueabi 536 arm-none-symbianelf */ 537 </cross_prefix> 538 539 <gcc_options> 540 /* Additional GCC options, one per line */ 541 </gcc_options> 542 543 -sysinfo DIR 544 This option should be used with -dump-system option to dump 545 ABI of operating systems and configure the dumping process. 546 You can find a sample in the package: 547 modules/Targets/{unix, symbian, windows} 548 549 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH 550 Compare two system ABI dumps. Create compatibility reports for each 551 library and the common HTML report including the summary of test 552 results for all checked libraries. Report will be generated to: 553 sys_compat_reports/NAME1_to_NAME2/ARCH 554 555 -libs-list PATH 556 The file with a list of libraries, that should be dumped by 557 the -dump-system option or should be checked by the -cmp-systems option. 558 559 -ext|-extended 560 If your library A is supposed to be used by other library B and you 561 want to control the ABI of B, then you should enable this option. The 562 tool will check for changes in all data types, even if they are not 563 used by any function in the library A. Such data types are not part 564 of the A library ABI, but may be a part of the ABI of the B library. 565 566 The short scheme is: 567 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI) 568 569 -q|-quiet 570 Print all messages to the file instead of stdout and stderr. 571 Default path (can be changed by -log-path option): 572 $COMMON_LOG_PATH 573 574 -stdout 575 Print analysis results (compatibility reports and ABI dumps) to stdout 576 instead of creating a file. This would allow piping data to other programs. 577 578 -report-format FMT 579 Change format of compatibility report. 580 Formats: 581 htm - HTML format (default) 582 xml - XML format 583 584 -dump-format FMT 585 Change format of ABI dump. 586 Formats: 587 perl - Data::Dumper format (default) 588 xml - XML format 589 590 -xml 591 Alias for: --report-format=xml or --dump-format=xml 592 593 -lang LANG 594 Set library language (C or C++). You can use this option if the tool 595 cannot auto-detect a language. This option may be useful for checking 596 C-library headers (--lang=C) in --headers-only or --extended modes. 597 598 -arch ARCH 599 Set library architecture (x86, x86_64, ia64, arm, ppc32, ppc64, s390, 600 ect.). The option is useful if the tool cannot detect correct architecture 601 of the input objects. 602 603 -binary|-bin|-abi 604 Show \"Binary\" compatibility problems only. 605 Generate report to: 606 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 607 608 -source|-src|-api 609 Show \"Source\" compatibility problems only. 610 Generate report to: 611 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 612 613 -limit-affected LIMIT 614 The maximum number of affected symbols listed under the description 615 of the changed type in the report. 616 617OTHER OPTIONS: 618 -test 619 Run internal tests. Create two binary incompatible versions of a sample 620 library and run the tool to check them for compatibility. This option 621 allows to check if the tool works correctly in the current environment. 622 623 -test-dump 624 Test ability to create, read and compare ABI dumps. 625 626 -debug 627 Debugging mode. Print debug info on the screen. Save intermediate 628 analysis stages in the debug directory: 629 debug/LIB_NAME/VERSION/ 630 631 Also consider using --dump option for debugging the tool. 632 633 -cpp-compatible 634 If your header files are written in C language and can be compiled 635 by the G++ compiler (i.e. don't use C++ keywords), then you can tell 636 the tool about this and speedup the analysis. 637 638 -cpp-incompatible 639 Set this option if input C header files use C++ keywords. 640 641 -p|-params PATH 642 Path to file with the function parameter names. It can be used 643 for improving report view if the library header files have no 644 parameter names. File format: 645 646 func1;param1;param2;param3 ... 647 func2;param1;param2;param3 ... 648 ... 649 650 -relpath PATH 651 Replace {RELPATH} macros to PATH in the XML-descriptor used 652 for dumping the library ABI (see -dump option). 653 654 -relpath1 PATH 655 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1). 656 657 -relpath2 PATH 658 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2). 659 660 -dump-path PATH 661 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump. 662 Default: 663 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT 664 665 -sort 666 Enable sorting of data in ABI dumps. 667 668 -report-path PATH 669 Path to compatibility report. 670 Default: 671 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 672 673 -bin-report-path PATH 674 Path to \"Binary\" compatibility report. 675 Default: 676 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html 677 678 -src-report-path PATH 679 Path to \"Source\" compatibility report. 680 Default: 681 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html 682 683 -log-path PATH 684 Log path for all messages. 685 Default: 686 logs/LIB_NAME/VERSION/log.txt 687 688 -log1-path PATH 689 Log path for 1st version of a library. 690 Default: 691 logs/LIB_NAME/V1/log.txt 692 693 -log2-path PATH 694 Log path for 2nd version of a library. 695 Default: 696 logs/LIB_NAME/V2/log.txt 697 698 -logging-mode MODE 699 Change logging mode. 700 Modes: 701 w - overwrite old logs (default) 702 a - append old logs 703 n - do not write any logs 704 705 -list-affected 706 Generate file with the list of incompatible 707 symbols beside the HTML compatibility report. 708 Use 'c++filt \@file' command from GNU binutils 709 to unmangle C++ symbols in the generated file. 710 Default names: 711 abi_affected.txt 712 src_affected.txt 713 714 -component NAME 715 The component name in the title and summary of the HTML report. 716 Default: 717 library 718 719 -title NAME 720 Change library name in the report title to NAME. By default 721 will be displayed a name specified by -l option. 722 723 -extra-info DIR 724 Dump extra info to DIR. 725 726 -extra-dump 727 Create extended ABI dump containing all symbols 728 from the translation unit. 729 730 -force 731 Try to use this option if the tool doesn't work. 732 733 -tolerance LEVEL 734 Apply a set of heuristics to successfully compile input 735 header files. You can enable several tolerance levels by 736 joining them into one string (e.g. 13, 124, etc.). 737 Levels: 738 1 - skip non-Linux headers (e.g. win32_*.h, etc.) 739 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.) 740 3 - skip headers that iclude non-Linux headers 741 4 - skip headers included by others 742 743 -tolerant 744 Enable highest tolerance level [1234]. 745 746 -check 747 Check completeness of the ABI dump. 748 749 -quick 750 Quick analysis. Disable check of some template instances. 751 752 -skip-internal-symbols PATTERN 753 Do not check symbols matched by the pattern. 754 755 -skip-internal-types PATTERN 756 Do not check types matched by the pattern. 757 758 -check-private-abi 759 Check data types from the private part of the ABI when 760 comparing ABI dumps created by the ABI Dumper tool with 761 use of the -public-headers option. 762 763 Requires ABI Dumper >= 0.99.14 764 765REPORT: 766 Compatibility report will be generated to: 767 compat_reports/LIB_NAME/V1_to_V2/compat_report.html 768 769 Log will be generated to: 770 logs/LIB_NAME/V1/log.txt 771 logs/LIB_NAME/V2/log.txt 772 773EXIT CODES: 774 0 - Compatible. The tool has run without any errors. 775 non-zero - Incompatible or the tool has run with errors. 776 777MORE INFORMATION: 778 ".$HomePage."\n"); 779} 780 781my %Operator_Indication = ( 782 "not" => "~", 783 "assign" => "=", 784 "andassign" => "&=", 785 "orassign" => "|=", 786 "xorassign" => "^=", 787 "or" => "|", 788 "xor" => "^", 789 "addr" => "&", 790 "and" => "&", 791 "lnot" => "!", 792 "eq" => "==", 793 "ne" => "!=", 794 "lt" => "<", 795 "lshift" => "<<", 796 "lshiftassign" => "<<=", 797 "rshiftassign" => ">>=", 798 "call" => "()", 799 "mod" => "%", 800 "modassign" => "%=", 801 "subs" => "[]", 802 "land" => "&&", 803 "lor" => "||", 804 "rshift" => ">>", 805 "ref" => "->", 806 "le" => "<=", 807 "deref" => "*", 808 "mult" => "*", 809 "preinc" => "++", 810 "delete" => " delete", 811 "vecnew" => " new[]", 812 "vecdelete" => " delete[]", 813 "predec" => "--", 814 "postinc" => "++", 815 "postdec" => "--", 816 "plusassign" => "+=", 817 "plus" => "+", 818 "minus" => "-", 819 "minusassign" => "-=", 820 "gt" => ">", 821 "ge" => ">=", 822 "new" => " new", 823 "multassign" => "*=", 824 "divassign" => "/=", 825 "div" => "/", 826 "neg" => "-", 827 "pos" => "+", 828 "memref" => "->*", 829 "compound" => "," ); 830 831my %UnknownOperator; 832 833my %NodeType= ( 834 "array_type" => "Array", 835 "binfo" => "Other", 836 "boolean_type" => "Intrinsic", 837 "complex_type" => "Intrinsic", 838 "const_decl" => "Other", 839 "enumeral_type" => "Enum", 840 "field_decl" => "Other", 841 "function_decl" => "Other", 842 "function_type" => "FunctionType", 843 "identifier_node" => "Other", 844 "integer_cst" => "Other", 845 "integer_type" => "Intrinsic", 846 "vector_type" => "Vector", 847 "method_type" => "MethodType", 848 "namespace_decl" => "Other", 849 "parm_decl" => "Other", 850 "pointer_type" => "Pointer", 851 "real_cst" => "Other", 852 "real_type" => "Intrinsic", 853 "record_type" => "Struct", 854 "reference_type" => "Ref", 855 "string_cst" => "Other", 856 "template_decl" => "Other", 857 "template_type_parm" => "TemplateParam", 858 "typename_type" => "TypeName", 859 "sizeof_expr" => "SizeOf", 860 "tree_list" => "Other", 861 "tree_vec" => "Other", 862 "type_decl" => "Other", 863 "union_type" => "Union", 864 "var_decl" => "Other", 865 "void_type" => "Intrinsic", 866 "nop_expr" => "Other", # 867 "addr_expr" => "Other", # 868 "offset_type" => "Other" ); 869 870my %CppKeywords_C = map {$_=>1} ( 871 # C++ 2003 keywords 872 "public", 873 "protected", 874 "private", 875 "default", 876 "template", 877 "new", 878 #"asm", 879 "dynamic_cast", 880 "auto", 881 "try", 882 "namespace", 883 "typename", 884 "using", 885 "reinterpret_cast", 886 "friend", 887 "class", 888 "virtual", 889 "const_cast", 890 "mutable", 891 "static_cast", 892 "export", 893 # C++0x keywords 894 "noexcept", 895 "nullptr", 896 "constexpr", 897 "static_assert", 898 "explicit", 899 # cannot be used as a macro name 900 # as it is an operator in C++ 901 "and", 902 #"and_eq", 903 "not", 904 #"not_eq", 905 "or" 906 #"or_eq", 907 #"bitand", 908 #"bitor", 909 #"xor", 910 #"xor_eq", 911 #"compl" 912); 913 914my %CppKeywords_F = map {$_=>1} ( 915 "delete", 916 "catch", 917 "alignof", 918 "thread_local", 919 "decltype", 920 "typeid" 921); 922 923my %CppKeywords_O = map {$_=>1} ( 924 "bool", 925 "register", 926 "inline", 927 "operator" 928); 929 930my %CppKeywords_A = map {$_=>1} ( 931 "this", 932 "throw", 933 "template" 934); 935 936foreach (keys(%CppKeywords_C), 937keys(%CppKeywords_F), 938keys(%CppKeywords_O)) { 939 $CppKeywords_A{$_}=1; 940} 941 942# Header file extensions as described by gcc 943my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+"; 944 945my %IntrinsicMangling = ( 946 "void" => "v", 947 "bool" => "b", 948 "wchar_t" => "w", 949 "char" => "c", 950 "signed char" => "a", 951 "unsigned char" => "h", 952 "short" => "s", 953 "unsigned short" => "t", 954 "int" => "i", 955 "unsigned int" => "j", 956 "long" => "l", 957 "unsigned long" => "m", 958 "long long" => "x", 959 "__int64" => "x", 960 "unsigned long long" => "y", 961 "__int128" => "n", 962 "unsigned __int128" => "o", 963 "float" => "f", 964 "double" => "d", 965 "long double" => "e", 966 "__float80" => "e", 967 "__float128" => "g", 968 "..." => "z" 969); 970 971my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); 972 973my %StdcxxMangling = ( 974 "3std"=>"St", 975 "3std9allocator"=>"Sa", 976 "3std12basic_string"=>"Sb", 977 "3std12basic_stringIcE"=>"Ss", 978 "3std13basic_istreamIcE"=>"Si", 979 "3std13basic_ostreamIcE"=>"So", 980 "3std14basic_iostreamIcE"=>"Sd" 981); 982 983my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; 984my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); 985 986my $ADD_TMPL_INSTANCES = 1; 987my $EMERGENCY_MODE_48 = 0; 988 989my %ConstantSuffix = ( 990 "unsigned int"=>"u", 991 "long"=>"l", 992 "unsigned long"=>"ul", 993 "long long"=>"ll", 994 "unsigned long long"=>"ull" 995); 996 997my %ConstantSuffixR = 998reverse(%ConstantSuffix); 999 1000my %OperatorMangling = ( 1001 "~" => "co", 1002 "=" => "aS", 1003 "|" => "or", 1004 "^" => "eo", 1005 "&" => "an",#ad (addr) 1006 "==" => "eq", 1007 "!" => "nt", 1008 "!=" => "ne", 1009 "<" => "lt", 1010 "<=" => "le", 1011 "<<" => "ls", 1012 "<<=" => "lS", 1013 ">" => "gt", 1014 ">=" => "ge", 1015 ">>" => "rs", 1016 ">>=" => "rS", 1017 "()" => "cl", 1018 "%" => "rm", 1019 "[]" => "ix", 1020 "&&" => "aa", 1021 "||" => "oo", 1022 "*" => "ml",#de (deref) 1023 "++" => "pp",# 1024 "--" => "mm",# 1025 "new" => "nw", 1026 "delete" => "dl", 1027 "new[]" => "na", 1028 "delete[]" => "da", 1029 "+=" => "pL", 1030 "+" => "pl",#ps (pos) 1031 "-" => "mi",#ng (neg) 1032 "-=" => "mI", 1033 "*=" => "mL", 1034 "/=" => "dV", 1035 "&=" => "aN", 1036 "|=" => "oR", 1037 "%=" => "rM", 1038 "^=" => "eO", 1039 "/" => "dv", 1040 "->*" => "pm", 1041 "->" => "pt",#rf (ref) 1042 "," => "cm", 1043 "?" => "qu", 1044 "." => "dt", 1045 "sizeof"=> "sz"#st 1046); 1047 1048my %Intrinsic_Keywords = map {$_=>1} ( 1049 "true", 1050 "false", 1051 "_Bool", 1052 "_Complex", 1053 "const", 1054 "int", 1055 "long", 1056 "void", 1057 "short", 1058 "float", 1059 "volatile", 1060 "restrict", 1061 "unsigned", 1062 "signed", 1063 "char", 1064 "double", 1065 "class", 1066 "struct", 1067 "union", 1068 "enum" 1069); 1070 1071my %GlibcHeader = map {$_=>1} ( 1072 "aliases.h", 1073 "argp.h", 1074 "argz.h", 1075 "assert.h", 1076 "cpio.h", 1077 "ctype.h", 1078 "dirent.h", 1079 "envz.h", 1080 "errno.h", 1081 "error.h", 1082 "execinfo.h", 1083 "fcntl.h", 1084 "fstab.h", 1085 "ftw.h", 1086 "glob.h", 1087 "grp.h", 1088 "iconv.h", 1089 "ifaddrs.h", 1090 "inttypes.h", 1091 "langinfo.h", 1092 "limits.h", 1093 "link.h", 1094 "locale.h", 1095 "malloc.h", 1096 "math.h", 1097 "mntent.h", 1098 "monetary.h", 1099 "nl_types.h", 1100 "obstack.h", 1101 "printf.h", 1102 "pwd.h", 1103 "regex.h", 1104 "sched.h", 1105 "search.h", 1106 "setjmp.h", 1107 "shadow.h", 1108 "signal.h", 1109 "spawn.h", 1110 "stdarg.h", 1111 "stdint.h", 1112 "stdio.h", 1113 "stdlib.h", 1114 "string.h", 1115 "strings.h", 1116 "tar.h", 1117 "termios.h", 1118 "time.h", 1119 "ulimit.h", 1120 "unistd.h", 1121 "utime.h", 1122 "wchar.h", 1123 "wctype.h", 1124 "wordexp.h" ); 1125 1126my %GlibcDir = map {$_=>1} ( 1127 "arpa", 1128 "bits", 1129 "gnu", 1130 "netinet", 1131 "net", 1132 "nfs", 1133 "rpc", 1134 "sys", 1135 "linux" ); 1136 1137my %WinHeaders = map {$_=>1} ( 1138 "dos.h", 1139 "process.h", 1140 "winsock.h", 1141 "config-win.h", 1142 "mem.h", 1143 "windows.h", 1144 "winsock2.h", 1145 "crtdbg.h", 1146 "ws2tcpip.h" 1147); 1148 1149my %ObsoleteHeaders = map {$_=>1} ( 1150 "iostream.h", 1151 "fstream.h" 1152); 1153 1154my %AlienHeaders = map {$_=>1} ( 1155 # Solaris 1156 "thread.h", 1157 "sys/atomic.h", 1158 # HPUX 1159 "sys/stream.h", 1160 # Symbian 1161 "AknDoc.h", 1162 # Atari ST 1163 "ext.h", 1164 "tos.h", 1165 # MS-DOS 1166 "alloc.h", 1167 # Sparc 1168 "sys/atomic.h" 1169); 1170 1171my %ConfHeaders = map {$_=>1} ( 1172 "atomic", 1173 "conf.h", 1174 "config.h", 1175 "configure.h", 1176 "build.h", 1177 "setup.h" 1178); 1179 1180my %LocalIncludes = map {$_=>1} ( 1181 "/usr/local/include", 1182 "/usr/local" ); 1183 1184my %OS_AddPath=( 1185# These paths are needed if the tool cannot detect them automatically 1186 "macos"=>{ 1187 "include"=>[ 1188 "/Library", 1189 "/Developer/usr/include" 1190 ], 1191 "lib"=>[ 1192 "/Library", 1193 "/Developer/usr/lib" 1194 ], 1195 "bin"=>[ 1196 "/Developer/usr/bin" 1197 ] 1198 }, 1199 "beos"=>{ 1200 # Haiku has GCC 2.95.3 by default 1201 # try to find GCC>=3.0 in /boot/develop/abi 1202 "include"=>[ 1203 "/boot/common", 1204 "/boot/develop" 1205 ], 1206 "lib"=>[ 1207 "/boot/common/lib", 1208 "/boot/system/lib", 1209 "/boot/apps" 1210 ], 1211 "bin"=>[ 1212 "/boot/common/bin", 1213 "/boot/system/bin", 1214 "/boot/develop/abi" 1215 ] 1216 } 1217); 1218 1219my %Slash_Type=( 1220 "default"=>"/", 1221 "windows"=>"\\" 1222); 1223 1224my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"}; 1225 1226# Global Variables 1227my %COMMON_LANGUAGE=( 1228 1 => "C", 1229 2 => "C" ); 1230 1231my $MAX_COMMAND_LINE_ARGUMENTS = 4096; 1232my $MAX_CPPFILT_FILE_SIZE = 50000; 1233my $CPPFILT_SUPPORT_FILE; 1234 1235my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION); 1236 1237my $STDCXX_TESTING = 0; 1238my $GLIBC_TESTING = 0; 1239my $CPP_HEADERS = 0; 1240 1241my $CheckHeadersOnly = $CheckHeadersOnly_Opt; 1242my $CheckUndefined = 0; 1243 1244my $TargetComponent = undef; 1245if($TargetComponent_Opt) { 1246 $TargetComponent = lc($TargetComponent_Opt); 1247} 1248else 1249{ # default: library 1250 # other components: header, system, ... 1251 $TargetComponent = "library"; 1252} 1253 1254my $TOP_REF = "<a class='top_ref' href='#Top'>to the top</a>"; 1255 1256my $SystemRoot; 1257 1258my $MAIN_CPP_DIR; 1259my %RESULT; 1260my %LOG_PATH; 1261my %DEBUG_PATH; 1262my %Cache; 1263my %LibInfo; 1264my $COMPILE_ERRORS = 0; 1265my %CompilerOptions; 1266my %CheckedDyLib; 1267my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup); 1268 1269# Constants (#defines) 1270my %Constants; 1271my %SkipConstants; 1272my %EnumConstants; 1273 1274# Extra Info 1275my %SymbolHeader; 1276my %KnownLibs; 1277 1278# Templates 1279my %TemplateInstance; 1280my %BasicTemplate; 1281my %TemplateArg; 1282my %TemplateDecl; 1283my %TemplateMap; 1284 1285# Types 1286my %TypeInfo; 1287my %SkipTypes = ( 1288 "1"=>{}, 1289 "2"=>{} ); 1290my %CheckedTypes; 1291my %TName_Tid; 1292my %EnumMembName_Id; 1293my %NestedNameSpaces = ( 1294 "1"=>{}, 1295 "2"=>{} ); 1296my %VirtualTable; 1297my %VirtualTable_Model; 1298my %ClassVTable; 1299my %ClassVTable_Content; 1300my %VTableClass; 1301my %AllocableClass; 1302my %ClassMethods; 1303my %ClassNames; 1304my %Class_SubClasses; 1305my %OverriddenMethods; 1306my %TypedefToAnon; 1307my $MAX_ID = 0; 1308 1309my %CheckedTypeInfo; 1310 1311# Typedefs 1312my %Typedef_BaseName; 1313my %Typedef_Tr; 1314my %Typedef_Eq; 1315my %StdCxxTypedef; 1316my %MissedTypedef; 1317my %MissedBase; 1318my %MissedBase_R; 1319my %TypeTypedef; 1320 1321# Symbols 1322my %SymbolInfo; 1323my %tr_name; 1324my %mangled_name_gcc; 1325my %mangled_name; 1326my %SkipSymbols = ( 1327 "1"=>{}, 1328 "2"=>{} ); 1329my %SkipNameSpaces = ( 1330 "1"=>{}, 1331 "2"=>{} ); 1332my %AddNameSpaces = ( 1333 "1"=>{}, 1334 "2"=>{} ); 1335my %SymbolsList; 1336my %TypesList; 1337my %SymbolsList_App; 1338my %CheckedSymbols; 1339my %Symbol_Library = ( 1340 "1"=>{}, 1341 "2"=>{} ); 1342my %Library_Symbol = ( 1343 "1"=>{}, 1344 "2"=>{} ); 1345my %DepSymbol_Library = ( 1346 "1"=>{}, 1347 "2"=>{} ); 1348my %DepLibrary_Symbol = ( 1349 "1"=>{}, 1350 "2"=>{} ); 1351my %MangledNames; 1352my %Func_ShortName; 1353my %AddIntParams; 1354my %GlobalDataObject; 1355my %WeakSymbols; 1356my %Library_Needed= ( 1357 "1"=>{}, 1358 "2"=>{} ); 1359 1360# Extra Info 1361my %UndefinedSymbols; 1362my %PreprocessedHeaders; 1363 1364# Headers 1365my %Include_Preamble = ( 1366 "1"=>[], 1367 "2"=>[] ); 1368my %Registered_Headers; 1369my %Registered_Sources; 1370my %HeaderName_Paths; 1371my %Header_Dependency; 1372my %Include_Neighbors; 1373my %Include_Paths = ( 1374 "1"=>[], 1375 "2"=>[] ); 1376my %INC_PATH_AUTODETECT = ( 1377 "1"=>1, 1378 "2"=>1 ); 1379my %Add_Include_Paths = ( 1380 "1"=>[], 1381 "2"=>[] ); 1382my %Skip_Include_Paths; 1383my %RegisteredDirs; 1384my %Header_ErrorRedirect; 1385my %Header_Includes; 1386my %Header_Includes_R; 1387my %Header_ShouldNotBeUsed; 1388my %RecursiveIncludes; 1389my %Header_Include_Prefix; 1390my %SkipHeaders; 1391my %SkipHeadersList=( 1392 "1"=>{}, 1393 "2"=>{} ); 1394my %SkipLibs; 1395my %Include_Order; 1396my %TUnit_NameSpaces; 1397my %TUnit_Classes; 1398my %TUnit_Funcs; 1399my %TUnit_Vars; 1400 1401my %CppMode = ( 1402 "1"=>0, 1403 "2"=>0 ); 1404my %AutoPreambleMode = ( 1405 "1"=>0, 1406 "2"=>0 ); 1407my %MinGWMode = ( 1408 "1"=>0, 1409 "2"=>0 ); 1410my %Cpp0xMode = ( 1411 "1"=>0, 1412 "2"=>0 ); 1413 1414# Shared Objects 1415my %RegisteredObjects; 1416my %RegisteredObjects_Short; 1417my %RegisteredSONAMEs; 1418my %RegisteredObject_Dirs; 1419 1420my %CheckedArch; 1421 1422# System Objects 1423my %SystemObjects; 1424my @DefaultLibPaths; 1425my %DyLib_DefaultPath; 1426 1427# System Headers 1428my %SystemHeaders; 1429my @DefaultCppPaths; 1430my @DefaultGccPaths; 1431my @DefaultIncPaths; 1432my %DefaultCppHeader; 1433my %DefaultGccHeader; 1434my @UsersIncPath; 1435 1436# Merging 1437my %CompleteSignature; 1438my $Version; 1439my %AddedInt; 1440my %RemovedInt; 1441my %AddedInt_Virt; 1442my %RemovedInt_Virt; 1443my %VirtualReplacement; 1444my %ChangedTypedef; 1445my %CompatRules; 1446my %IncompleteRules; 1447my %UnknownRules; 1448my %VTableChanged_M; 1449my %ExtendedSymbols; 1450my %ReturnedClass; 1451my %ParamClass; 1452my %SourceAlternative; 1453my %SourceAlternative_B; 1454my %SourceReplacement; 1455my $CurrentSymbol; # for debugging 1456 1457# Calling Conventions 1458my %UseConv_Real = ( 1459 1=>{ "R"=>0, "P"=>0 }, 1460 2=>{ "R"=>0, "P"=>0 } 1461); 1462 1463# ABI Dump 1464my %UsedDump; 1465 1466# Filters 1467my %TargetLibs; 1468my %TargetHeaders; 1469 1470# Format of objects 1471my $OStarget = $OSgroup; 1472my %TargetTools; 1473 1474# Compliance Report 1475my %Type_MaxSeverity; 1476 1477# Recursion locks 1478my @RecurLib; 1479my @RecurTypes; 1480my @RecurTypes_Diff; 1481my @RecurInclude; 1482my @RecurConstant; 1483 1484# System 1485my %SystemPaths = ( 1486 "include"=>[], 1487 "lib"=>[], 1488 "bin"=>[] 1489); 1490my @DefaultBinPaths; 1491my $GCC_PATH; 1492 1493# Symbols versioning 1494my %SymVer = ( 1495 "1"=>{}, 1496 "2"=>{} ); 1497 1498# Problem descriptions 1499my %CompatProblems; 1500my %CompatProblems_Constants; 1501my %TotalAffected; 1502 1503# Reports 1504my $ContentID = 1; 1505my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1506my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1507my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n"; 1508my $ContentSpanEnd = "</span>\n"; 1509my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n"; 1510my $ContentDivEnd = "</div>\n"; 1511my $Content_Counter = 0; 1512 1513# Modes 1514my $JoinReport = 1; 1515my $DoubleReport = 0; 1516 1517my %Severity_Val=( 1518 "High"=>3, 1519 "Medium"=>2, 1520 "Low"=>1, 1521 "Safe"=>-1 1522); 1523 1524sub get_Modules() 1525{ 1526 my $TOOL_DIR = get_dirname($0); 1527 if(not $TOOL_DIR) 1528 { # patch for MS Windows 1529 $TOOL_DIR = "."; 1530 } 1531 my @SEARCH_DIRS = ( 1532 # tool's directory 1533 abs_path($TOOL_DIR), 1534 # relative path to modules 1535 abs_path($TOOL_DIR)."/../share/abi-compliance-checker", 1536 # install path 1537 'MODULES_INSTALL_PATH' 1538 ); 1539 foreach my $DIR (@SEARCH_DIRS) 1540 { 1541 if(not is_abs($DIR)) 1542 { # relative path 1543 $DIR = abs_path($TOOL_DIR)."/".$DIR; 1544 } 1545 if(-d $DIR."/modules") { 1546 return $DIR."/modules"; 1547 } 1548 } 1549 exitStatus("Module_Error", "can't find modules"); 1550} 1551 1552my %LoadedModules = (); 1553 1554sub loadModule($) 1555{ 1556 my $Name = $_[0]; 1557 if(defined $LoadedModules{$Name}) { 1558 return; 1559 } 1560 my $Path = $MODULES_DIR."/Internals/$Name.pm"; 1561 if(not -f $Path) { 1562 exitStatus("Module_Error", "can't access \'$Path\'"); 1563 } 1564 require $Path; 1565 $LoadedModules{$Name} = 1; 1566} 1567 1568sub readModule($$) 1569{ 1570 my ($Module, $Name) = @_; 1571 my $Path = $MODULES_DIR."/Internals/$Module/".$Name; 1572 if(not -f $Path) { 1573 exitStatus("Module_Error", "can't access \'$Path\'"); 1574 } 1575 return readFile($Path); 1576} 1577 1578sub showPos($) 1579{ 1580 my $Number = $_[0]; 1581 if(not $Number) { 1582 $Number = 1; 1583 } 1584 else { 1585 $Number = int($Number)+1; 1586 } 1587 if($Number>3) { 1588 return $Number."th"; 1589 } 1590 elsif($Number==1) { 1591 return "1st"; 1592 } 1593 elsif($Number==2) { 1594 return "2nd"; 1595 } 1596 elsif($Number==3) { 1597 return "3rd"; 1598 } 1599 else { 1600 return $Number; 1601 } 1602} 1603 1604sub search_Tools($) 1605{ 1606 my $Name = $_[0]; 1607 return "" if(not $Name); 1608 if(my @Paths = keys(%TargetTools)) 1609 { 1610 foreach my $Path (@Paths) 1611 { 1612 if(-f join_P($Path, $Name)) { 1613 return join_P($Path, $Name); 1614 } 1615 if($CrossPrefix) 1616 { # user-defined prefix (arm-none-symbianelf, ...) 1617 my $Candidate = join_P($Path, $CrossPrefix."-".$Name); 1618 if(-f $Candidate) { 1619 return $Candidate; 1620 } 1621 } 1622 } 1623 } 1624 else { 1625 return ""; 1626 } 1627} 1628 1629sub synch_Cmd($) 1630{ 1631 my $Name = $_[0]; 1632 if(not $GCC_PATH) 1633 { # GCC was not found yet 1634 return ""; 1635 } 1636 my $Candidate = $GCC_PATH; 1637 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) { 1638 return $Candidate; 1639 } 1640 return ""; 1641} 1642 1643sub get_CmdPath($) 1644{ 1645 my $Name = $_[0]; 1646 return "" if(not $Name); 1647 if(defined $Cache{"get_CmdPath"}{$Name}) { 1648 return $Cache{"get_CmdPath"}{$Name}; 1649 } 1650 my %BinUtils = map {$_=>1} ( 1651 "c++filt", 1652 "objdump", 1653 "readelf" 1654 ); 1655 if($BinUtils{$Name} and $GCC_PATH) 1656 { 1657 if(my $Dir = get_dirname($GCC_PATH)) { 1658 $TargetTools{$Dir}=1; 1659 } 1660 } 1661 my $Path = search_Tools($Name); 1662 if(not $Path and $OSgroup eq "windows") { 1663 $Path = search_Tools($Name.".exe"); 1664 } 1665 if(not $Path and $BinUtils{$Name}) 1666 { 1667 if($CrossPrefix) 1668 { # user-defined prefix 1669 $Path = search_Cmd($CrossPrefix."-".$Name); 1670 } 1671 } 1672 if(not $Path and $BinUtils{$Name}) 1673 { 1674 if(my $Candidate = synch_Cmd($Name)) 1675 { # synch with GCC 1676 if($Candidate=~/[\/\\]/) 1677 { # command path 1678 if(-f $Candidate) { 1679 $Path = $Candidate; 1680 } 1681 } 1682 elsif($Candidate = search_Cmd($Candidate)) 1683 { # command name 1684 $Path = $Candidate; 1685 } 1686 } 1687 } 1688 if(not $Path) { 1689 $Path = search_Cmd($Name); 1690 } 1691 if(not $Path and $OSgroup eq "windows") 1692 { # search for *.exe file 1693 $Path=search_Cmd($Name.".exe"); 1694 } 1695 if($Path=~/\s/) { 1696 $Path = "\"".$Path."\""; 1697 } 1698 return ($Cache{"get_CmdPath"}{$Name}=$Path); 1699} 1700 1701sub search_Cmd($) 1702{ 1703 my $Name = $_[0]; 1704 return "" if(not $Name); 1705 if(defined $Cache{"search_Cmd"}{$Name}) { 1706 return $Cache{"search_Cmd"}{$Name}; 1707 } 1708 if(my $DefaultPath = get_CmdPath_Default($Name)) { 1709 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath); 1710 } 1711 foreach my $Path (@{$SystemPaths{"bin"}}) 1712 { 1713 my $CmdPath = join_P($Path,$Name); 1714 if(-f $CmdPath) 1715 { 1716 if($Name=~/gcc/) { 1717 next if(not check_gcc($CmdPath, "3")); 1718 } 1719 return ($Cache{"search_Cmd"}{$Name} = $CmdPath); 1720 } 1721 } 1722 return ($Cache{"search_Cmd"}{$Name} = ""); 1723} 1724 1725sub get_CmdPath_Default($) 1726{ # search in PATH 1727 return "" if(not $_[0]); 1728 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) { 1729 return $Cache{"get_CmdPath_Default"}{$_[0]}; 1730 } 1731 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0])); 1732} 1733 1734sub get_CmdPath_Default_I($) 1735{ # search in PATH 1736 my $Name = $_[0]; 1737 if($Name=~/find/) 1738 { # special case: search for "find" utility 1739 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) { 1740 return "find"; 1741 } 1742 } 1743 elsif($Name=~/gcc/) { 1744 return check_gcc($Name, "3"); 1745 } 1746 if(checkCmd($Name)) { 1747 return $Name; 1748 } 1749 if($OSgroup eq "windows") 1750 { 1751 if(`$Name /? 2>\"$TMP_DIR/null\"`) { 1752 return $Name; 1753 } 1754 } 1755 foreach my $Path (@DefaultBinPaths) 1756 { 1757 if(-f $Path."/".$Name) { 1758 return join_P($Path, $Name); 1759 } 1760 } 1761 return ""; 1762} 1763 1764sub classifyPath($) 1765{ 1766 my $Path = $_[0]; 1767 if($Path=~/[\*\[]/) 1768 { # wildcard 1769 $Path=~s/\*/.*/g; 1770 $Path=~s/\\/\\\\/g; 1771 return ($Path, "Pattern"); 1772 } 1773 elsif($Path=~/[\/\\]/) 1774 { # directory or relative path 1775 return (path_format($Path, $OSgroup), "Path"); 1776 } 1777 else { 1778 return ($Path, "Name"); 1779 } 1780} 1781 1782sub readDescriptor($$) 1783{ 1784 my ($LibVersion, $Content) = @_; 1785 return if(not $LibVersion); 1786 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\""; 1787 if(not $Content) { 1788 exitStatus("Error", "$DName is empty"); 1789 } 1790 if($Content!~/\</) { 1791 exitStatus("Error", "incorrect descriptor (see -d1 option)"); 1792 } 1793 $Content=~s/\/\*(.|\n)+?\*\///g; 1794 $Content=~s/<\!--(.|\n)+?-->//g; 1795 1796 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version"); 1797 if($TargetVersion{$LibVersion}) { 1798 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion}; 1799 } 1800 if(not $Descriptor{$LibVersion}{"Version"}) { 1801 exitStatus("Error", "version in the $DName is not specified (<version> section)"); 1802 } 1803 if($Content=~/{RELPATH}/) 1804 { 1805 if(my $RelDir = $RelativeDirectory{$LibVersion}) { 1806 $Content =~ s/{RELPATH}/$RelDir/g; 1807 } 1808 else 1809 { 1810 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion"; 1811 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro"); 1812 } 1813 } 1814 1815 my $DHeaders = parseTag(\$Content, "headers"); 1816 if(not $DHeaders) { 1817 exitStatus("Error", "header files in the $DName are not specified (<headers> section)"); 1818 } 1819 elsif(lc($DHeaders) ne "none") 1820 { # append the descriptor headers list 1821 if($Descriptor{$LibVersion}{"Headers"}) 1822 { # multiple descriptors 1823 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders; 1824 } 1825 else { 1826 $Descriptor{$LibVersion}{"Headers"} = $DHeaders; 1827 } 1828 foreach my $Path (split(/\s*\n\s*/, $DHeaders)) 1829 { 1830 if(not -e $Path) { 1831 exitStatus("Access_Error", "can't access \'$Path\'"); 1832 } 1833 } 1834 } 1835 1836 if(not $CheckHeadersOnly_Opt) 1837 { 1838 my $DObjects = parseTag(\$Content, "libs"); 1839 if(not $DObjects) { 1840 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)"); 1841 } 1842 elsif(lc($DObjects) ne "none") 1843 { # append the descriptor libraries list 1844 if($Descriptor{$LibVersion}{"Libs"}) 1845 { # multiple descriptors 1846 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects; 1847 } 1848 else { 1849 $Descriptor{$LibVersion}{"Libs"} .= $DObjects; 1850 } 1851 foreach my $Path (split(/\s*\n\s*/, $DObjects)) 1852 { 1853 if(not -e $Path) { 1854 exitStatus("Access_Error", "can't access \'$Path\'"); 1855 } 1856 } 1857 } 1858 } 1859 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) 1860 { 1861 if(not -d $Path) { 1862 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1863 } 1864 $Path = get_abs_path($Path); 1865 $Path = path_format($Path, $OSgroup); 1866 push_U($SystemPaths{"include"}, $Path); 1867 } 1868 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) 1869 { 1870 if(not -d $Path) { 1871 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1872 } 1873 $Path = get_abs_path($Path); 1874 $Path = path_format($Path, $OSgroup); 1875 push_U($SystemPaths{"lib"}, $Path); 1876 } 1877 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) 1878 { 1879 if(not -d $Path) { 1880 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1881 } 1882 $Path = get_abs_path($Path); 1883 $Path = path_format($Path, $OSgroup); 1884 push_U($SystemPaths{"bin"}, $Path); 1885 $TargetTools{$Path}=1; 1886 } 1887 if(my $Prefix = parseTag(\$Content, "cross_prefix")) { 1888 $CrossPrefix = $Prefix; 1889 } 1890 $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //= 1891 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) 1892 { 1893 if(not -d $Path) { 1894 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1895 } 1896 $Path = get_abs_path($Path); 1897 $Path = path_format($Path, $OSgroup); 1898 push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path); 1899 } 1900 $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"}); 1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) 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(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path); 1909 } 1910 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) 1911 { # skip some auto-generated include paths 1912 if(not is_abs($Path)) 1913 { 1914 if(my $P = abs_path($Path)) { 1915 $Path = $P; 1916 } 1917 } 1918 $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1; 1919 } 1920 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) 1921 { # skip direct including of some headers 1922 my ($CPath, $Type) = classifyPath($Path); 1923 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2; 1924 } 1925 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options"); 1926 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) 1927 { 1928 if($Option!~/\A\-(Wl|l|L)/) 1929 { # skip linker options 1930 $CompilerOptions{$LibVersion} .= " ".$Option; 1931 } 1932 } 1933 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers"); 1934 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"})) 1935 { 1936 $SkipHeadersList{$LibVersion}{$Path} = 1; 1937 my ($CPath, $Type) = classifyPath($Path); 1938 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1; 1939 } 1940 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs"); 1941 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"})) 1942 { 1943 my ($CPath, $Type) = classifyPath($Path); 1944 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1; 1945 } 1946 if(my $DDefines = parseTag(\$Content, "defines")) 1947 { 1948 if($Descriptor{$LibVersion}{"Defines"}) 1949 { # multiple descriptors 1950 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines; 1951 } 1952 else { 1953 $Descriptor{$LibVersion}{"Defines"} = $DDefines; 1954 } 1955 } 1956 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) 1957 { 1958 if($Order=~/\A(.+):(.+)\Z/) { 1959 $Include_Order{$LibVersion}{$1} = $2; 1960 } 1961 } 1962 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), 1963 split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) 1964 { # opaque_types renamed to skip_types (1.23.4) 1965 $SkipTypes{$LibVersion}{$Type_Name} = 1; 1966 } 1967 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), 1968 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) 1969 { # skip_interfaces renamed to skip_symbols (1.22.1) 1970 $SkipSymbols{$LibVersion}{$Symbol} = 1; 1971 } 1972 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { 1973 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1; 1974 } 1975 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { 1976 $AddNameSpaces{$LibVersion}{$NameSpace} = 1; 1977 } 1978 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { 1979 $SkipConstants{$LibVersion}{$Constant} = 1; 1980 } 1981 if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) 1982 { 1983 if($Descriptor{$LibVersion}{"IncludePreamble"}) 1984 { # multiple descriptors 1985 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble; 1986 } 1987 else { 1988 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble; 1989 } 1990 } 1991} 1992 1993sub parseTag(@) 1994{ 1995 my $CodeRef = shift(@_); 1996 my $Tag = shift(@_); 1997 if(not $Tag or not $CodeRef) { 1998 return undef; 1999 } 2000 my $Sp = 0; 2001 if(@_) { 2002 $Sp = shift(@_); 2003 } 2004 my $Start = index(${$CodeRef}, "<$Tag>"); 2005 if($Start!=-1) 2006 { 2007 my $End = index(${$CodeRef}, "</$Tag>"); 2008 if($End!=-1) 2009 { 2010 my $TS = length($Tag)+3; 2011 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, ""); 2012 substr($Content, 0, $TS-1, ""); # cut start tag 2013 substr($Content, -$TS, $TS, ""); # cut end tag 2014 if(not $Sp) 2015 { 2016 $Content=~s/\A\s+//g; 2017 $Content=~s/\s+\Z//g; 2018 } 2019 if(substr($Content, 0, 1) ne "<") { 2020 $Content = xmlSpecChars_R($Content); 2021 } 2022 return $Content; 2023 } 2024 } 2025 return undef; 2026} 2027 2028sub getInfo($) 2029{ 2030 my $DumpPath = $_[0]; 2031 return if(not $DumpPath or not -f $DumpPath); 2032 2033 readTUDump($DumpPath); 2034 2035 # processing info 2036 setTemplateParams_All(); 2037 2038 if($ExtraDump) { 2039 setAnonTypedef_All(); 2040 } 2041 2042 getTypeInfo_All(); 2043 simplifyNames(); 2044 simplifyConstants(); 2045 getVarInfo_All(); 2046 getSymbolInfo_All(); 2047 2048 # clean memory 2049 %LibInfo = (); 2050 %TemplateInstance = (); 2051 %BasicTemplate = (); 2052 %MangledNames = (); 2053 %TemplateDecl = (); 2054 %StdCxxTypedef = (); 2055 %MissedTypedef = (); 2056 %Typedef_Tr = (); 2057 %Typedef_Eq = (); 2058 %TypedefToAnon = (); 2059 2060 # clean cache 2061 delete($Cache{"getTypeAttr"}); 2062 delete($Cache{"getTypeDeclId"}); 2063 2064 if($ExtraDump) 2065 { 2066 remove_Unused($Version, "Extra"); 2067 } 2068 else 2069 { # remove unused types 2070 if($BinaryOnly and not $ExtendedCheck) 2071 { # --binary 2072 remove_Unused($Version, "All"); 2073 } 2074 else { 2075 remove_Unused($Version, "Extended"); 2076 } 2077 } 2078 2079 if($CheckInfo) 2080 { 2081 foreach my $Tid (keys(%{$TypeInfo{$Version}})) { 2082 check_Completeness($TypeInfo{$Version}{$Tid}, $Version); 2083 } 2084 2085 foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { 2086 check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); 2087 } 2088 } 2089 2090 if($Debug) { 2091 # debugMangling($Version); 2092 } 2093} 2094 2095sub readTUDump($) 2096{ 2097 my $DumpPath = $_[0]; 2098 2099 open(TU_DUMP, $DumpPath); 2100 local $/ = undef; 2101 my $Content = <TU_DUMP>; 2102 close(TU_DUMP); 2103 2104 unlink($DumpPath); 2105 2106 $Content=~s/\n[ ]+/ /g; 2107 my @Lines = split(/\n/, $Content); 2108 2109 # clean memory 2110 undef $Content; 2111 2112 $MAX_ID = $#Lines+1; # number of lines == number of nodes 2113 2114 foreach (0 .. $#Lines) 2115 { 2116 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i) 2117 { # get a number and attributes of a node 2118 next if(not $NodeType{$2}); 2119 $LibInfo{$Version}{"info_type"}{$1}=$2; 2120 $LibInfo{$Version}{"info"}{$1}=$3; 2121 } 2122 2123 # clean memory 2124 delete($Lines[$_]); 2125 } 2126 2127 # clean memory 2128 undef @Lines; 2129} 2130 2131sub simplifyConstants() 2132{ 2133 foreach my $Constant (keys(%{$Constants{$Version}})) 2134 { 2135 if(defined $Constants{$Version}{$Constant}{"Header"}) 2136 { 2137 my $Value = $Constants{$Version}{$Constant}{"Value"}; 2138 if(defined $EnumConstants{$Version}{$Value}) { 2139 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"}; 2140 } 2141 } 2142 } 2143} 2144 2145sub simplifyNames() 2146{ 2147 foreach my $Base (keys(%{$Typedef_Tr{$Version}})) 2148 { 2149 if($Typedef_Eq{$Version}{$Base}) { 2150 next; 2151 } 2152 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}}); 2153 if($#Translations==0) 2154 { 2155 if(length($Translations[0])<=length($Base)) { 2156 $Typedef_Eq{$Version}{$Base} = $Translations[0]; 2157 } 2158 } 2159 else 2160 { # select most appropriate 2161 foreach my $Tr (@Translations) 2162 { 2163 if($Base=~/\A\Q$Tr\E/) 2164 { 2165 $Typedef_Eq{$Version}{$Base} = $Tr; 2166 last; 2167 } 2168 } 2169 } 2170 } 2171 foreach my $TypeId (keys(%{$TypeInfo{$Version}})) 2172 { 2173 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2174 if(not $TypeName) { 2175 next; 2176 } 2177 next if(index($TypeName,"<")==-1);# template instances only 2178 if($TypeName=~/>(::\w+)+\Z/) 2179 { # skip unused types 2180 next; 2181 } 2182 foreach my $Base (sort {length($b)<=>length($a)} 2183 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}})) 2184 { 2185 next if(not $Base); 2186 next if(index($TypeName,$Base)==-1); 2187 next if(length($TypeName) - length($Base) <= 3); 2188 if(my $Typedef = $Typedef_Eq{$Version}{$Base}) 2189 { 2190 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g; 2191 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g; 2192 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"}) 2193 { 2194 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}})) 2195 { 2196 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"}) 2197 { 2198 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g; 2199 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g; 2200 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T"); 2201 } 2202 } 2203 } 2204 } 2205 } 2206 $TypeName = formatName($TypeName, "T"); 2207 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName; 2208 $TName_Tid{$Version}{$TypeName} = $TypeId; 2209 } 2210} 2211 2212sub setAnonTypedef_All() 2213{ 2214 foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}})) 2215 { 2216 if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl") 2217 { 2218 if(isAnon(getNameByInfo($InfoId))) { 2219 $TypedefToAnon{getTypeId($InfoId)} = 1; 2220 } 2221 } 2222 } 2223} 2224 2225sub setTemplateParams_All() 2226{ 2227 foreach (keys(%{$LibInfo{$Version}{"info"}})) 2228 { 2229 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") { 2230 setTemplateParams($_); 2231 } 2232 } 2233} 2234 2235sub setTemplateParams($) 2236{ 2237 my $Tid = getTypeId($_[0]); 2238 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2239 { 2240 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) 2241 { 2242 my $TmplInst_Id = $2; 2243 setTemplateInstParams($_[0], $TmplInst_Id); 2244 while($TmplInst_Id = getNextElem($TmplInst_Id)) { 2245 setTemplateInstParams($_[0], $TmplInst_Id); 2246 } 2247 } 2248 2249 $BasicTemplate{$Version}{$Tid} = $_[0]; 2250 2251 if(my $Prms = getTreeAttr_Prms($_[0])) 2252 { 2253 if(my $Valu = getTreeAttr_Valu($Prms)) 2254 { 2255 my $Vector = getTreeVec($Valu); 2256 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) 2257 { 2258 if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) 2259 { 2260 if(my $Name = getNameByInfo($Val)) 2261 { 2262 $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; 2263 if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { 2264 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; 2265 } 2266 else { 2267 $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); 2268 } 2269 } 2270 } 2271 } 2272 } 2273 } 2274 } 2275 if(my $TypeId = getTreeAttr_Type($_[0])) 2276 { 2277 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) 2278 { 2279 if($IType eq "record_type") { 2280 $TemplateDecl{$Version}{$TypeId} = 1; 2281 } 2282 } 2283 } 2284} 2285 2286sub setTemplateInstParams($$) 2287{ 2288 my ($Tmpl, $Inst) = @_; 2289 2290 if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) 2291 { 2292 my ($Params_InfoId, $ElemId) = (); 2293 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 2294 $Params_InfoId = $1; 2295 } 2296 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 2297 $ElemId = $1; 2298 } 2299 if($Params_InfoId and $ElemId) 2300 { 2301 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId}; 2302 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 2303 { 2304 my ($PPos, $PTypeId) = ($1, $2); 2305 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) 2306 { 2307 if($PType eq "template_type_parm") { 2308 $TemplateDecl{$Version}{$ElemId} = 1; 2309 } 2310 } 2311 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") 2312 { # functions 2313 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; 2314 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2315 } 2316 else 2317 { # types 2318 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; 2319 $BasicTemplate{$Version}{$ElemId} = $Tmpl; 2320 } 2321 } 2322 } 2323 } 2324} 2325 2326sub getTypeDeclId($) 2327{ 2328 if($_[0]) 2329 { 2330 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) { 2331 return $Cache{"getTypeDeclId"}{$Version}{$_[0]}; 2332 } 2333 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 2334 { 2335 if($Info=~/name[ ]*:[ ]*@(\d+)/) { 2336 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1); 2337 } 2338 } 2339 } 2340 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0); 2341} 2342 2343sub getTypeInfo_All() 2344{ 2345 if(not check_gcc($GCC_PATH, "4.5")) 2346 { # support for GCC < 4.5 2347 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag> 2348 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump 2349 # FIXME: check GCC versions 2350 addMissedTypes_Pre(); 2351 } 2352 2353 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2354 { # forward order only 2355 my $IType = $LibInfo{$Version}{"info_type"}{$_}; 2356 if($IType=~/_type\Z/ and $IType ne "function_type" 2357 and $IType ne "method_type") { 2358 getTypeInfo("$_"); 2359 } 2360 } 2361 2362 # add "..." type 2363 $TypeInfo{$Version}{"-1"} = { 2364 "Name" => "...", 2365 "Type" => "Intrinsic", 2366 "Tid" => "-1" 2367 }; 2368 $TName_Tid{$Version}{"..."} = "-1"; 2369 2370 if(not check_gcc($GCC_PATH, "4.5")) 2371 { # support for GCC < 4.5 2372 addMissedTypes_Post(); 2373 } 2374 2375 if($ADD_TMPL_INSTANCES) 2376 { 2377 # templates 2378 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) 2379 { 2380 if(defined $TemplateMap{$Version}{$Tid} 2381 and not defined $TypeInfo{$Version}{$Tid}{"Template"}) 2382 { 2383 if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) 2384 { 2385 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) 2386 { 2387 if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) 2388 { 2389 if(my %MAttr = getTypeAttr($MembTypeId)) 2390 { 2391 $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; 2392 $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); 2393 } 2394 } 2395 } 2396 } 2397 if(defined $TypeInfo{$Version}{$Tid}{"Base"}) 2398 { 2399 foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) 2400 { 2401 my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); 2402 2403 if($NBid ne $Bid 2404 and $NBid ne $Tid) 2405 { 2406 %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; 2407 delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); 2408 } 2409 } 2410 } 2411 } 2412 } 2413 } 2414} 2415 2416sub createType($$) 2417{ 2418 my ($Attr, $LibVersion) = @_; 2419 my $NewId = ++$MAX_ID; 2420 2421 $Attr->{"Tid"} = $NewId; 2422 $TypeInfo{$Version}{$NewId} = $Attr; 2423 $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; 2424 2425 return "$NewId"; 2426} 2427 2428sub instType($$$) 2429{ # create template instances 2430 my ($Map, $Tid, $LibVersion) = @_; 2431 2432 if(not $TypeInfo{$LibVersion}{$Tid}) { 2433 return undef; 2434 } 2435 my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); 2436 2437 foreach my $Key (sort keys(%{$Map})) 2438 { 2439 if(my $Val = $Map->{$Key}) 2440 { 2441 $Attr->{"Name"}=~s/\b$Key\b/$Val/g; 2442 2443 if(defined $Attr->{"NameSpace"}) { 2444 $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; 2445 } 2446 foreach (keys(%{$Attr->{"TParam"}})) { 2447 $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; 2448 } 2449 } 2450 else 2451 { # remove absent 2452 # _Traits, etc. 2453 $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; 2454 if(defined $Attr->{"NameSpace"}) { 2455 $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; 2456 } 2457 foreach (keys(%{$Attr->{"TParam"}})) 2458 { 2459 if($Attr->{"TParam"}{$_}{"name"} eq $Key) { 2460 delete($Attr->{"TParam"}{$_}); 2461 } 2462 else { 2463 $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; 2464 } 2465 } 2466 } 2467 } 2468 2469 my $Tmpl = 0; 2470 2471 if(defined $Attr->{"TParam"}) 2472 { 2473 foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) 2474 { 2475 my $PName = $Attr->{"TParam"}{$_}{"name"}; 2476 2477 if(my $PTid = $TName_Tid{$LibVersion}{$PName}) 2478 { 2479 my %Base = get_BaseType($PTid, $LibVersion); 2480 2481 if($Base{"Type"} eq "TemplateParam" 2482 or defined $Base{"Template"}) 2483 { 2484 $Tmpl = 1; 2485 last 2486 } 2487 } 2488 } 2489 } 2490 2491 if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { 2492 return "$Id"; 2493 } 2494 else 2495 { 2496 if(not $Tmpl) { 2497 delete($Attr->{"Template"}); 2498 } 2499 2500 my $New = createType($Attr, $LibVersion); 2501 2502 my %EMap = (); 2503 if(defined $TemplateMap{$LibVersion}{$Tid}) { 2504 %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; 2505 } 2506 foreach (keys(%{$Map})) { 2507 $EMap{$_} = $Map->{$_}; 2508 } 2509 2510 if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { 2511 $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); 2512 } 2513 if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) 2514 { 2515 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) 2516 { 2517 my $NBid = instType(\%EMap, $Bid, $LibVersion); 2518 2519 if($NBid ne $Bid 2520 and $NBid ne $New) 2521 { 2522 %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; 2523 delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); 2524 } 2525 } 2526 } 2527 2528 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) 2529 { 2530 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) 2531 { 2532 if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { 2533 $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); 2534 } 2535 } 2536 } 2537 2538 if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) 2539 { 2540 foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { 2541 $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); 2542 } 2543 } 2544 2545 if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { 2546 $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); 2547 } 2548 2549 return $New; 2550 } 2551} 2552 2553sub addMissedTypes_Pre() 2554{ 2555 my %MissedTypes = (); 2556 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) 2557 { # detecting missed typedefs 2558 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl") 2559 { 2560 my $TypeId = getTreeAttr_Type($MissedTDid); 2561 next if(not $TypeId); 2562 my $TypeType = getTypeType($TypeId); 2563 if($TypeType eq "Unknown") 2564 { # template_type_parm 2565 next; 2566 } 2567 my $TypeDeclId = getTypeDeclId($TypeId); 2568 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId 2569 my $TypedefName = getNameByInfo($MissedTDid); 2570 next if(not $TypedefName); 2571 next if($TypedefName eq "__float80"); 2572 next if(isAnon($TypedefName)); 2573 if(not $TypeDeclId 2574 or getNameByInfo($TypeDeclId) ne $TypedefName) { 2575 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1; 2576 } 2577 } 2578 } 2579 my %AddTypes = (); 2580 foreach my $Tid (keys(%{$MissedTypes{$Version}})) 2581 { # add missed typedefs 2582 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}}); 2583 if(not @Missed or $#Missed>=1) { 2584 next; 2585 } 2586 my $MissedTDid = $Missed[0]; 2587 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid); 2588 if(not $TypedefName) { 2589 next; 2590 } 2591 my $NewId = ++$MAX_ID; 2592 my %MissedInfo = ( # typedef info 2593 "Name" => $TypedefName, 2594 "NameSpace" => $TypedefNS, 2595 "BaseType" => $Tid, 2596 "Type" => "Typedef", 2597 "Tid" => "$NewId" ); 2598 my ($H, $L) = getLocation($MissedTDid); 2599 $MissedInfo{"Header"} = $H; 2600 $MissedInfo{"Line"} = $L; 2601 if($TypedefName=~/\*|\&|\s/) 2602 { # other types 2603 next; 2604 } 2605 if($TypedefName=~/>(::\w+)+\Z/) 2606 { # QFlags<Qt::DropAction>::enum_type 2607 next; 2608 } 2609 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) 2610 { # double-check for the name of typedef 2611 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info 2612 next if(not $TName); 2613 if(length($TypedefName)>=length($TName)) 2614 { # too long typedef 2615 next; 2616 } 2617 if($TName=~/\A\Q$TypedefName\E</) { 2618 next; 2619 } 2620 if($TypedefName=~/\A\Q$TName\E/) 2621 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type 2622 next; 2623 } 2624 if(get_depth($TypedefName)==0 and get_depth($TName)!=0) 2625 { # std::_Vector_base and std::vector::_Base 2626 next; 2627 } 2628 } 2629 2630 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo; 2631 2632 # register typedef 2633 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"}; 2634 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid; 2635 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"}; 2636 } 2637 2638 # add missed & remove other 2639 $TypeInfo{$Version} = \%AddTypes; 2640 delete($Cache{"getTypeAttr"}{$Version}); 2641} 2642 2643sub addMissedTypes_Post() 2644{ 2645 foreach my $BaseId (keys(%{$MissedTypedef{$Version}})) 2646 { 2647 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"}) 2648 { 2649 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"}; 2650 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) { 2651 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"}; 2652 } 2653 } 2654 } 2655} 2656 2657sub getTypeInfo($) 2658{ 2659 my $TypeId = $_[0]; 2660 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId); 2661 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"}; 2662 if(not $TName) { 2663 delete($TypeInfo{$Version}{$TypeId}); 2664 } 2665} 2666 2667sub getArraySize($$) 2668{ 2669 my ($TypeId, $BaseName) = @_; 2670 if(my $Size = getSize($TypeId)) 2671 { 2672 my $Elems = $Size/$BYTE_SIZE; 2673 while($BaseName=~s/\s*\[(\d+)\]//) { 2674 $Elems/=$1; 2675 } 2676 if(my $BasicId = $TName_Tid{$Version}{$BaseName}) 2677 { 2678 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) { 2679 $Elems/=$BasicSize; 2680 } 2681 } 2682 return $Elems; 2683 } 2684 return 0; 2685} 2686 2687sub getTParams($$) 2688{ 2689 my ($TypeId, $Kind) = @_; 2690 my @TmplParams = (); 2691 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}}); 2692 foreach my $Pos (@Positions) 2693 { 2694 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos}; 2695 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId}; 2696 if(not $NodeType) 2697 { # typename_type 2698 return (); 2699 } 2700 if($NodeType eq "tree_vec") 2701 { 2702 if($Pos!=$#Positions) 2703 { # select last vector of parameters ( ns<P1>::type<P2> ) 2704 next; 2705 } 2706 } 2707 my @Params = get_TemplateParam($Pos, $Param_TypeId); 2708 foreach my $P (@Params) 2709 { 2710 if($P eq "") { 2711 return (); 2712 } 2713 elsif($P ne "\@skip\@") { 2714 @TmplParams = (@TmplParams, $P); 2715 } 2716 } 2717 } 2718 return @TmplParams; 2719} 2720 2721sub getTypeAttr($) 2722{ 2723 my $TypeId = $_[0]; 2724 my %TypeAttr = (); 2725 if(defined $TypeInfo{$Version}{$TypeId} 2726 and $TypeInfo{$Version}{$TypeId}{"Name"}) 2727 { # already created 2728 return %{$TypeInfo{$Version}{$TypeId}}; 2729 } 2730 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId}) 2731 { # incomplete type 2732 return (); 2733 } 2734 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1; 2735 2736 my $TypeDeclId = getTypeDeclId($TypeId); 2737 $TypeAttr{"Tid"} = $TypeId; 2738 2739 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId)) 2740 { 2741 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 2742 { 2743 if($Info=~/qual[ ]*:/) 2744 { 2745 my $NewId = ++$MAX_ID; 2746 2747 $MissedBase{$Version}{$TypeId} = "$NewId"; 2748 $MissedBase_R{$Version}{$NewId} = $TypeId; 2749 $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; 2750 $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; 2751 } 2752 } 2753 $TypeAttr{"Type"} = "Typedef"; 2754 } 2755 else { 2756 $TypeAttr{"Type"} = getTypeType($TypeId); 2757 } 2758 2759 if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) 2760 { 2761 if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") 2762 { # local code 2763 return (); 2764 } 2765 } 2766 2767 if($TypeAttr{"Type"} eq "Unknown") { 2768 return (); 2769 } 2770 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/) 2771 { 2772 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"}); 2773 if(my $TName = $TypeAttr{"Name"}) 2774 { 2775 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2776 $TName_Tid{$Version}{$TName} = $TypeId; 2777 return %TypeAttr; 2778 } 2779 else { 2780 return (); 2781 } 2782 } 2783 elsif($TypeAttr{"Type"} eq "Array") 2784 { 2785 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2786 if(not $BTid) { 2787 return (); 2788 } 2789 if(my $Algn = getAlgn($TypeId)) { 2790 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 2791 } 2792 $TypeAttr{"BaseType"} = $BTid; 2793 if(my %BTAttr = getTypeAttr($BTid)) 2794 { 2795 if(not $BTAttr{"Name"}) { 2796 return (); 2797 } 2798 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"})) 2799 { 2800 if(my $Size = getSize($TypeId)) { 2801 $TypeAttr{"Size"} = $Size/$BYTE_SIZE; 2802 } 2803 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2804 $TypeAttr{"Name"} = $1."[$NElems]".$2; 2805 } 2806 else { 2807 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]"; 2808 } 2809 } 2810 else 2811 { 2812 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer 2813 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { 2814 $TypeAttr{"Name"} = $1."[]".$2; 2815 } 2816 else { 2817 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]"; 2818 } 2819 } 2820 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 2821 if($BTAttr{"Header"}) { 2822 $TypeAttr{"Header"} = $BTAttr{"Header"}; 2823 } 2824 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2825 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2826 return %TypeAttr; 2827 } 2828 return (); 2829 } 2830 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) 2831 { 2832 %TypeAttr = getTrivialTypeAttr($TypeId); 2833 if($TypeAttr{"Name"}) 2834 { 2835 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2836 2837 if(not defined $IntrinsicNames{$TypeAttr{"Name"}} 2838 or getTypeDeclId($TypeAttr{"Tid"})) 2839 { # NOTE: register only one int: with built-in decl 2840 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2841 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2842 } 2843 } 2844 return %TypeAttr; 2845 } 2846 else { 2847 return (); 2848 } 2849 } 2850 elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) 2851 { 2852 %TypeAttr = getTrivialTypeAttr($TypeId); 2853 if($TypeAttr{"Name"}) 2854 { 2855 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2856 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 2857 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 2858 } 2859 return %TypeAttr; 2860 } 2861 else { 2862 return (); 2863 } 2864 } 2865 elsif($TypeAttr{"Type"} eq "SizeOf") 2866 { 2867 $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); 2868 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2869 $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; 2870 if($TypeAttr{"Name"}) 2871 { 2872 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 2873 return %TypeAttr; 2874 } 2875 else { 2876 return (); 2877 } 2878 } 2879 else 2880 { # derived types 2881 my ($BTid, $BTSpec) = selectBaseType($TypeId); 2882 if(not $BTid) { 2883 return (); 2884 } 2885 $TypeAttr{"BaseType"} = $BTid; 2886 if(defined $MissedTypedef{$Version}{$BTid}) 2887 { 2888 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"}) 2889 { 2890 if($MissedTDid ne $TypeDeclId) { 2891 $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"}; 2892 } 2893 } 2894 } 2895 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); 2896 if(not $BTAttr{"Name"}) 2897 { # templates 2898 return (); 2899 } 2900 if($BTAttr{"Type"} eq "Typedef") 2901 { # relinking typedefs 2902 my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version); 2903 if($BTAttr{"Name"} eq $BaseBase{"Name"}) { 2904 $TypeAttr{"BaseType"} = $BaseBase{"Tid"}; 2905 } 2906 } 2907 if($BTSpec) 2908 { 2909 if($TypeAttr{"Type"} eq "Pointer" 2910 and $BTAttr{"Name"}=~/\([\*]+\)/) 2911 { 2912 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2913 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g; 2914 } 2915 else { 2916 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec; 2917 } 2918 } 2919 else { 2920 $TypeAttr{"Name"} = $BTAttr{"Name"}; 2921 } 2922 if($TypeAttr{"Type"} eq "Typedef") 2923 { 2924 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId); 2925 2926 if(index($TypeAttr{"Name"}, "tmp_add_type")==0) { 2927 return (); 2928 } 2929 2930 if(isAnon($TypeAttr{"Name"})) 2931 { # anon typedef to anon type: ._N 2932 return (); 2933 } 2934 2935 if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i) 2936 { # artificial typedef of "struct X" to "X" 2937 $TypeAttr{"Artificial"} = 1; 2938 } 2939 2940 if(my $NS = getNameSpace($TypeDeclId)) 2941 { 2942 my $TypeName = $TypeAttr{"Name"}; 2943 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/) 2944 { # "some_type" is the typedef to "struct some_type" in C++ 2945 if($3) { 2946 $TypeAttr{"Name"} = $3."::".$TypeName; 2947 } 2948 } 2949 else 2950 { 2951 $TypeAttr{"NameSpace"} = $NS; 2952 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 2953 2954 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ 2955 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/) 2956 { 2957 if($BTAttr{"NameSpace"} 2958 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</) 2959 { # types like "std::fpos<__mbstate_t>" are 2960 # not covered by typedefs in the TU dump 2961 # so trying to add such typedefs manually 2962 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 2963 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"})) 2964 { 2965 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) 2966 { # skip "other" in "std" and "type" in "boost" 2967 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"}; 2968 } 2969 } 2970 } 2971 } 2972 } 2973 } 2974 if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"} 2975 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/) 2976 { 2977 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}}) 2978 { # typedef int*const TYPEDEF; // first 2979 # int foo(TYPEDEF p); // const is optimized out 2980 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"}; 2981 if($BTAttr{"Name"}=~/</) 2982 { 2983 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) { 2984 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; 2985 } 2986 } 2987 } 2988 } 2989 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId); 2990 } 2991 if(not $TypeAttr{"Size"}) 2992 { 2993 if($TypeAttr{"Type"} eq "Pointer") { 2994 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; 2995 } 2996 elsif($BTAttr{"Size"}) { 2997 $TypeAttr{"Size"} = $BTAttr{"Size"}; 2998 } 2999 } 3000 if(my $Algn = getAlgn($TypeId)) { 3001 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3002 } 3003 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3004 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) { 3005 $TypeAttr{"Header"} = $BTAttr{"Header"}; 3006 } 3007 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; 3008 if($TypeAttr{"Name"} ne $BTAttr{"Name"}) 3009 { # typedef to "class Class" 3010 # should not be registered in TName_Tid 3011 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { 3012 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; 3013 } 3014 } 3015 return %TypeAttr; 3016 } 3017} 3018 3019sub getTreeVec($) 3020{ 3021 my %Vector = (); 3022 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3023 { 3024 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) 3025 { # string length is N-1 because of the null terminator 3026 $Vector{$1} = $2; 3027 } 3028 } 3029 return \%Vector; 3030} 3031 3032sub get_TemplateParam($$) 3033{ 3034 my ($Pos, $Type_Id) = @_; 3035 return () if(not $Type_Id); 3036 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id}; 3037 return () if(not $NodeType); 3038 if($NodeType eq "integer_cst") 3039 { # int (1), unsigned (2u), char ('c' as 99), ... 3040 my $CstTid = getTreeAttr_Type($Type_Id); 3041 my %CstType = getTypeAttr($CstTid); # without recursion 3042 my $Num = getNodeIntCst($Type_Id); 3043 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) { 3044 return ($Num.$CstSuffix); 3045 } 3046 else { 3047 return ("(".$CstType{"Name"}.")".$Num); 3048 } 3049 } 3050 elsif($NodeType eq "string_cst") { 3051 return (getNodeStrCst($Type_Id)); 3052 } 3053 elsif($NodeType eq "tree_vec") 3054 { 3055 my $Vector = getTreeVec($Type_Id); 3056 my @Params = (); 3057 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector})) 3058 { 3059 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) { 3060 push(@Params, $P2); 3061 } 3062 } 3063 return @Params; 3064 } 3065 elsif($NodeType eq "parm_decl") 3066 { 3067 (getNameByInfo($Type_Id)); 3068 } 3069 else 3070 { 3071 my %ParamAttr = getTypeAttr($Type_Id); 3072 my $PName = $ParamAttr{"Name"}; 3073 if(not $PName) { 3074 return (); 3075 } 3076 if($PName=~/\>/) 3077 { 3078 if(my $Cover = cover_stdcxx_typedef($PName)) { 3079 $PName = $Cover; 3080 } 3081 } 3082 if($Pos>=1 and 3083 $PName=~/\A$DEFAULT_STD_PARMS\</) 3084 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> > 3085 # template<typename _Key, typename _Compare = std::less<_Key> 3086 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> > 3087 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> > 3088 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> > 3089 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> > 3090 return ("\@skip\@"); 3091 } 3092 return ($PName); 3093 } 3094} 3095 3096sub cover_stdcxx_typedef($) 3097{ 3098 my $TypeName = $_[0]; 3099 if(my @Covers = sort {length($a)<=>length($b)} 3100 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3101 { # take the shortest typedef 3102 # FIXME: there may be more than 3103 # one typedefs to the same type 3104 return $Covers[0]; 3105 } 3106 my $Covered = $TypeName; 3107 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){}; 3108 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) 3109 { 3110 if(my $Cover = $Covers[0]) 3111 { 3112 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g; 3113 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g; 3114 } 3115 } 3116 return formatName($Covered, "T"); 3117} 3118 3119sub getNodeIntCst($) 3120{ 3121 my $CstId = $_[0]; 3122 my $CstTypeId = getTreeAttr_Type($CstId); 3123 if($EnumMembName_Id{$Version}{$CstId}) { 3124 return $EnumMembName_Id{$Version}{$CstId}; 3125 } 3126 elsif((my $Value = getTreeValue($CstId)) ne "") 3127 { 3128 if($Value eq "0") 3129 { 3130 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3131 return "false"; 3132 } 3133 else { 3134 return "0"; 3135 } 3136 } 3137 elsif($Value eq "1") 3138 { 3139 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { 3140 return "true"; 3141 } 3142 else { 3143 return "1"; 3144 } 3145 } 3146 else { 3147 return $Value; 3148 } 3149 } 3150 return ""; 3151} 3152 3153sub getNodeStrCst($) 3154{ 3155 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3156 { 3157 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/) 3158 { 3159 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst") 3160 { # string length is N-1 because of the null terminator 3161 return substr($1, 0, $2-1); 3162 } 3163 else 3164 { # identifier_node 3165 return substr($1, 0, $2); 3166 } 3167 } 3168 } 3169 return ""; 3170} 3171 3172sub getMemPtrAttr($$$) 3173{ # function, method and field pointers 3174 my ($PtrId, $TypeId, $Type) = @_; 3175 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId}; 3176 if($Type eq "FieldPtr") { 3177 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId}; 3178 } 3179 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId}; 3180 my $MemPtrName = ""; 3181 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId); 3182 if($Type eq "MethodPtr") 3183 { # size of "method pointer" may be greater than WORD size 3184 if(my $Size = getSize($TypeId)) 3185 { 3186 $Size/=$BYTE_SIZE; 3187 $TypeAttr{"Size"} = "$Size"; 3188 } 3189 } 3190 if(my $Algn = getAlgn($TypeId)) { 3191 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3192 } 3193 # Return 3194 if($Type eq "FieldPtr") 3195 { 3196 my %ReturnAttr = getTypeAttr($PtrId); 3197 if($ReturnAttr{"Name"}) { 3198 $MemPtrName .= $ReturnAttr{"Name"}; 3199 } 3200 $TypeAttr{"Return"} = $PtrId; 3201 } 3202 else 3203 { 3204 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /) 3205 { 3206 my $ReturnTypeId = $1; 3207 my %ReturnAttr = getTypeAttr($ReturnTypeId); 3208 if(not $ReturnAttr{"Name"}) 3209 { # templates 3210 return (); 3211 } 3212 $MemPtrName .= $ReturnAttr{"Name"}; 3213 $TypeAttr{"Return"} = $ReturnTypeId; 3214 } 3215 } 3216 # Class 3217 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /) 3218 { 3219 $TypeAttr{"Class"} = $2; 3220 my %Class = getTypeAttr($TypeAttr{"Class"}); 3221 if($Class{"Name"}) { 3222 $MemPtrName .= " (".$Class{"Name"}."\:\:*)"; 3223 } 3224 else { 3225 $MemPtrName .= " (*)"; 3226 } 3227 } 3228 else { 3229 $MemPtrName .= " (*)"; 3230 } 3231 # Parameters 3232 if($Type eq "FuncPtr" 3233 or $Type eq "MethodPtr") 3234 { 3235 my @ParamTypeName = (); 3236 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /) 3237 { 3238 my $PTypeInfoId = $1; 3239 my ($Pos, $PPos) = (0, 0); 3240 while($PTypeInfoId) 3241 { 3242 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId}; 3243 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /) 3244 { 3245 my $PTypeId = $1; 3246 my %ParamAttr = getTypeAttr($PTypeId); 3247 if(not $ParamAttr{"Name"}) 3248 { # templates (template_type_parm), etc. 3249 return (); 3250 } 3251 if($ParamAttr{"Name"} eq "void") { 3252 last; 3253 } 3254 if($Pos!=0 or $Type ne "MethodPtr") 3255 { 3256 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId; 3257 push(@ParamTypeName, $ParamAttr{"Name"}); 3258 } 3259 if($PTypeInfoId = getNextElem($PTypeInfoId)) { 3260 $Pos+=1; 3261 } 3262 else { 3263 last; 3264 } 3265 } 3266 else { 3267 last; 3268 } 3269 } 3270 } 3271 $MemPtrName .= " (".join(", ", @ParamTypeName).")"; 3272 } 3273 $TypeAttr{"Name"} = formatName($MemPtrName, "T"); 3274 return %TypeAttr; 3275} 3276 3277sub getTreeTypeName($) 3278{ 3279 my $TypeId = $_[0]; 3280 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3281 { 3282 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type") 3283 { 3284 if(my $Name = getNameByInfo($TypeId)) 3285 { # bit_size_type 3286 return $Name; 3287 } 3288 elsif($Info=~/unsigned/) { 3289 return "unsigned int"; 3290 } 3291 else { 3292 return "int"; 3293 } 3294 } 3295 elsif($Info=~/name[ ]*:[ ]*@(\d+) /) { 3296 return getNameByInfo($1); 3297 } 3298 } 3299 return ""; 3300} 3301 3302sub isFuncPtr($) 3303{ 3304 my $Ptd = pointTo($_[0]); 3305 return 0 if(not $Ptd); 3306 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3307 { 3308 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) { 3309 return 0; 3310 } 3311 } 3312 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]} 3313 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd}) 3314 { 3315 if($InfoT1 eq "pointer_type" 3316 and $InfoT2 eq "function_type") { 3317 return 1; 3318 } 3319 } 3320 return 0; 3321} 3322 3323sub isMethodPtr($) 3324{ 3325 my $Ptd = pointTo($_[0]); 3326 return 0 if(not $Ptd); 3327 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3328 { 3329 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type" 3330 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type" 3331 and $Info=~/ ptrmem /) { 3332 return 1; 3333 } 3334 } 3335 return 0; 3336} 3337 3338sub isFieldPtr($) 3339{ 3340 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3341 { 3342 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type" 3343 and $Info=~/ ptrmem /) { 3344 return 1; 3345 } 3346 } 3347 return 0; 3348} 3349 3350sub pointTo($) 3351{ 3352 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3353 { 3354 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) { 3355 return $1; 3356 } 3357 } 3358 return ""; 3359} 3360 3361sub getTypeTypeByTypeId($) 3362{ 3363 my $TypeId = $_[0]; 3364 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId}) 3365 { 3366 my $NType = $NodeType{$TType}; 3367 if($NType eq "Intrinsic") { 3368 return $NType; 3369 } 3370 elsif(isFuncPtr($TypeId)) { 3371 return "FuncPtr"; 3372 } 3373 elsif(isMethodPtr($TypeId)) { 3374 return "MethodPtr"; 3375 } 3376 elsif(isFieldPtr($TypeId)) { 3377 return "FieldPtr"; 3378 } 3379 elsif($NType ne "Other") { 3380 return $NType; 3381 } 3382 } 3383 return "Unknown"; 3384} 3385 3386my %UnQual = ( 3387 "r"=>"restrict", 3388 "v"=>"volatile", 3389 "c"=>"const", 3390 "cv"=>"const volatile" 3391); 3392 3393sub getQual($) 3394{ 3395 my $TypeId = $_[0]; 3396 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) 3397 { 3398 my ($Qual, $To) = (); 3399 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) { 3400 $Qual = $UnQual{$1}; 3401 } 3402 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { 3403 $To = $1; 3404 } 3405 if($Qual and $To) { 3406 return ($Qual, $To); 3407 } 3408 } 3409 return (); 3410} 3411 3412sub getQualType($) 3413{ 3414 if($_[0] eq "const volatile") { 3415 return "ConstVolatile"; 3416 } 3417 return ucfirst($_[0]); 3418} 3419 3420sub getTypeType($) 3421{ 3422 my $TypeId = $_[0]; 3423 my $TypeDeclId = getTypeDeclId($TypeId); 3424 if(defined $MissedTypedef{$Version}{$TypeId}) 3425 { # support for old GCC versions 3426 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) { 3427 return "Typedef"; 3428 } 3429 } 3430 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3431 my ($Qual, $To) = getQual($TypeId); 3432 if(($Qual or $To) and $TypeDeclId 3433 and (getTypeId($TypeDeclId) ne $TypeId)) 3434 { # qualified types (special) 3435 return getQualType($Qual); 3436 } 3437 elsif(not $MissedBase_R{$Version}{$TypeId} 3438 and isTypedef($TypeId)) { 3439 return "Typedef"; 3440 } 3441 elsif($Qual) 3442 { # qualified types 3443 return getQualType($Qual); 3444 } 3445 3446 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) 3447 { # typedef struct { ... } name 3448 $TypeTypedef{$Version}{$TypeId} = $1; 3449 } 3450 3451 my $TypeType = getTypeTypeByTypeId($TypeId); 3452 if($TypeType eq "Struct") 3453 { 3454 if($TypeDeclId 3455 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") { 3456 return "Template"; 3457 } 3458 } 3459 return $TypeType; 3460} 3461 3462sub isTypedef($) 3463{ 3464 if($_[0]) 3465 { 3466 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") 3467 { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); 3468 return 0; 3469 } 3470 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 3471 { 3472 if(my $TDid = getTypeDeclId($_[0])) 3473 { 3474 if(getTypeId($TDid) eq $_[0] 3475 and getNameByInfo($TDid)) 3476 { 3477 if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { 3478 return $1; 3479 } 3480 } 3481 } 3482 } 3483 } 3484 return 0; 3485} 3486 3487sub selectBaseType($) 3488{ 3489 my $TypeId = $_[0]; 3490 if(defined $MissedTypedef{$Version}{$TypeId}) 3491 { # add missed typedefs 3492 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) { 3493 return ($TypeId, ""); 3494 } 3495 } 3496 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 3497 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId}; 3498 3499 my $MB_R = $MissedBase_R{$Version}{$TypeId}; 3500 my $MB = $MissedBase{$Version}{$TypeId}; 3501 3502 my ($Qual, $To) = getQual($TypeId); 3503 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) / 3504 and (getTypeId($1) ne $TypeId) 3505 and (not $MB_R or getTypeId($1) ne $MB_R)) 3506 { # qualified types (special) 3507 return (getTypeId($1), $Qual); 3508 } 3509 elsif($MB) 3510 { # add base 3511 return ($MB, ""); 3512 } 3513 elsif(not $MB_R and my $Bid = isTypedef($TypeId)) 3514 { # typedefs 3515 return ($Bid, ""); 3516 } 3517 elsif($Qual or $To) 3518 { # qualified types 3519 return ($To, $Qual); 3520 } 3521 elsif($InfoType eq "reference_type") 3522 { 3523 if($Info=~/refd[ ]*:[ ]*@(\d+) /) { 3524 return ($1, "&"); 3525 } 3526 } 3527 elsif($InfoType eq "array_type") 3528 { 3529 if($Info=~/elts[ ]*:[ ]*@(\d+) /) { 3530 return ($1, ""); 3531 } 3532 } 3533 elsif($InfoType eq "pointer_type") 3534 { 3535 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { 3536 return ($1, "*"); 3537 } 3538 } 3539 3540 return (0, ""); 3541} 3542 3543sub getSymbolInfo_All() 3544{ 3545 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3546 { # reverse order 3547 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") { 3548 getSymbolInfo($_); 3549 } 3550 } 3551 3552 if($ADD_TMPL_INSTANCES) 3553 { 3554 # templates 3555 foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) 3556 { 3557 my %Map = (); 3558 3559 if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) 3560 { 3561 if(defined $TemplateMap{$Version}{$ClassId}) 3562 { 3563 foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { 3564 $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; 3565 } 3566 } 3567 } 3568 3569 if(defined $TemplateMap{$Version}{$Sid}) 3570 { 3571 foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { 3572 $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; 3573 } 3574 } 3575 3576 if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) 3577 { 3578 foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) 3579 { 3580 my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; 3581 $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); 3582 } 3583 } 3584 if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { 3585 $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); 3586 } 3587 } 3588 } 3589} 3590 3591sub getVarInfo_All() 3592{ 3593 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) 3594 { # reverse order 3595 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") { 3596 getVarInfo($_); 3597 } 3598 } 3599} 3600 3601sub isBuiltIn($) { 3602 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./); 3603} 3604 3605sub getVarInfo($) 3606{ 3607 my $InfoId = $_[0]; 3608 if(my $NSid = getTreeAttr_Scpe($InfoId)) 3609 { 3610 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid}; 3611 if($NSInfoType and $NSInfoType eq "function_decl") { 3612 return; 3613 } 3614 } 3615 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 3616 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 3617 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { 3618 delete($SymbolInfo{$Version}{$InfoId}); 3619 return; 3620 } 3621 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId)); 3622 if(not $ShortName) { 3623 delete($SymbolInfo{$Version}{$InfoId}); 3624 return; 3625 } 3626 if($ShortName=~/\Atmp_add_class_\d+\Z/) { 3627 delete($SymbolInfo{$Version}{$InfoId}); 3628 return; 3629 } 3630 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName; 3631 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 3632 { 3633 if($OSgroup eq "windows") 3634 { # cut the offset 3635 $MnglName=~s/\@\d+\Z//g; 3636 } 3637 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 3638 } 3639 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 3640 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 3641 { # validate mangled name 3642 delete($SymbolInfo{$Version}{$InfoId}); 3643 return; 3644 } 3645 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3646 and index($ShortName, "_Z")==0) 3647 { # _ZTS, etc. 3648 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3649 } 3650 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"})) 3651 { # non-public global data 3652 delete($SymbolInfo{$Version}{$InfoId}); 3653 return; 3654 } 3655 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; 3656 if(my $Rid = getTypeId($InfoId)) 3657 { 3658 if(not defined $TypeInfo{$Version}{$Rid} 3659 or not $TypeInfo{$Version}{$Rid}{"Name"}) 3660 { 3661 delete($SymbolInfo{$Version}{$InfoId}); 3662 return; 3663 } 3664 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid; 3665 my $Val = getDataVal($InfoId, $Rid); 3666 if(defined $Val) { 3667 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val; 3668 } 3669 } 3670 set_Class_And_Namespace($InfoId); 3671 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 3672 { 3673 if(not defined $TypeInfo{$Version}{$ClassId} 3674 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 3675 { 3676 delete($SymbolInfo{$Version}{$InfoId}); 3677 return; 3678 } 3679 } 3680 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 3681 { # extern "C" 3682 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 3683 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3684 } 3685 if($UserLang and $UserLang eq "C") 3686 { # --lang=C option 3687 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3688 } 3689 if(not $CheckHeadersOnly) 3690 { 3691 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}) 3692 { 3693 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} 3694 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 3695 { 3696 if(link_symbol($ShortName, $Version, "-Deps")) 3697 { # "const" global data is mangled as _ZL... in the TU dump 3698 # but not mangled when compiling a C shared library 3699 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3700 } 3701 } 3702 } 3703 } 3704 if($COMMON_LANGUAGE{$Version} eq "C++") 3705 { 3706 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3707 { # for some symbols (_ZTI) the short name is the mangled name 3708 if(index($ShortName, "_Z")==0) { 3709 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3710 } 3711 } 3712 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3713 { # try to mangle symbol (link with libraries) 3714 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId); 3715 } 3716 if($OStarget eq "windows") 3717 { 3718 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 3719 { # link MS C++ symbols from library with GCC symbols from headers 3720 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 3721 } 3722 } 3723 } 3724 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { 3725 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; 3726 } 3727 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 3728 { 3729 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 3730 { # non-target symbols 3731 delete($SymbolInfo{$Version}{$InfoId}); 3732 return; 3733 } 3734 } 3735 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 3736 { 3737 if(defined $MissedTypedef{$Version}{$Rid}) 3738 { 3739 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 3740 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 3741 } 3742 } 3743 } 3744 setFuncAccess($InfoId); 3745 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) { 3746 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 3747 } 3748 if($ShortName=~/\A(_Z|\?)/) { 3749 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"}); 3750 } 3751 3752 if($ExtraDump) { 3753 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 3754 } 3755} 3756 3757sub isConstType($$) 3758{ 3759 my ($TypeId, $LibVersion) = @_; 3760 my %Base = get_Type($TypeId, $LibVersion); 3761 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { 3762 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion}); 3763 } 3764 return ($Base{"Type"} eq "Const"); 3765} 3766 3767sub getTrivialName($$) 3768{ 3769 my ($TypeInfoId, $TypeId) = @_; 3770 my %TypeAttr = (); 3771 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId); 3772 if(not $TypeAttr{"Name"}) { 3773 $TypeAttr{"Name"} = getTreeTypeName($TypeId); 3774 } 3775 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3776 $TypeAttr{"Type"} = getTypeType($TypeId); 3777 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name 3778 if(isAnon($TypeAttr{"Name"})) 3779 { 3780 my $NameSpaceId = $TypeId; 3781 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId))) 3782 { # searching for a first not anon scope 3783 if($NSId eq $NameSpaceId) { 3784 last; 3785 } 3786 else 3787 { 3788 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId)); 3789 if(not $TypeAttr{"NameSpace"} 3790 or not isAnon($TypeAttr{"NameSpace"})) { 3791 last; 3792 } 3793 } 3794 $NameSpaceId = $NSId; 3795 } 3796 } 3797 else 3798 { 3799 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId)) 3800 { 3801 if($NameSpaceId ne $TypeId) { 3802 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId); 3803 } 3804 } 3805 } 3806 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) { 3807 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3808 } 3809 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); 3810 if(isAnon($TypeAttr{"Name"})) 3811 { # anon-struct-header.h-line 3812 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-"; 3813 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"}; 3814 if($TypeAttr{"NameSpace"}) { 3815 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; 3816 } 3817 } 3818 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId} 3819 and getTypeDeclId($TypeId) eq $TypeInfoId) 3820 { 3821 if(my @TParams = getTParams($TypeId, "Type")) { 3822 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); 3823 } 3824 else { 3825 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."<...>", "T"); 3826 } 3827 } 3828 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); 3829} 3830 3831sub getTrivialTypeAttr($) 3832{ 3833 my $TypeId = $_[0]; 3834 my $TypeInfoId = getTypeDeclId($_[0]); 3835 3836 my %TypeAttr = (); 3837 3838 if($TemplateDecl{$Version}{$TypeId}) 3839 { # template_decl 3840 $TypeAttr{"Template"} = 1; 3841 } 3842 3843 setTypeAccess($TypeId, \%TypeAttr); 3844 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); 3845 if(isBuiltIn($TypeAttr{"Header"})) 3846 { 3847 delete($TypeAttr{"Header"}); 3848 delete($TypeAttr{"Line"}); 3849 } 3850 3851 $TypeAttr{"Type"} = getTypeType($TypeId); 3852 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId); 3853 if(not $TypeAttr{"Name"}) { 3854 return (); 3855 } 3856 if(not $TypeAttr{"NameSpace"}) { 3857 delete($TypeAttr{"NameSpace"}); 3858 } 3859 3860 if($TypeAttr{"Type"} eq "Intrinsic") 3861 { 3862 if(defined $TypeAttr{"Header"}) 3863 { 3864 if($TypeAttr{"Header"}=~/\Adump[1-2]\.[ih]\Z/) 3865 { # support for SUSE 11.2 3866 # integer_type has srcp dump{1-2}.i 3867 delete($TypeAttr{"Header"}); 3868 } 3869 } 3870 } 3871 3872 my $Tmpl = undef; 3873 3874 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 3875 { 3876 $Tmpl = $BasicTemplate{$Version}{$TypeId}; 3877 3878 if(my @TParams = getTParams($TypeId, "Type")) 3879 { 3880 foreach my $Pos (0 .. $#TParams) 3881 { 3882 my $Val = $TParams[$Pos]; 3883 $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; 3884 3885 if(not defined $TypeAttr{"Template"}) 3886 { 3887 my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); 3888 3889 if($Base{"Type"} eq "TemplateParam" 3890 or defined $Base{"Template"}) { 3891 $TypeAttr{"Template"} = 1; 3892 } 3893 } 3894 3895 if($Tmpl) 3896 { 3897 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 3898 { 3899 $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; 3900 3901 if($Val eq $Arg) { 3902 $TypeAttr{"Template"} = 1; 3903 } 3904 } 3905 } 3906 } 3907 3908 if($Tmpl) 3909 { 3910 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 3911 { 3912 if($Pos>$#TParams) 3913 { 3914 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 3915 $TemplateMap{$Version}{$TypeId}{$Arg} = ""; 3916 } 3917 } 3918 } 3919 } 3920 3921 if($ADD_TMPL_INSTANCES) 3922 { 3923 if($Tmpl) 3924 { 3925 if(my $MainInst = getTreeAttr_Type($Tmpl)) 3926 { 3927 if(not getTreeAttr_Flds($TypeId)) 3928 { 3929 if(my $Flds = getTreeAttr_Flds($MainInst)) { 3930 $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; 3931 } 3932 } 3933 if(not getTreeAttr_Binf($TypeId)) 3934 { 3935 if(my $Binf = getTreeAttr_Binf($MainInst)) { 3936 $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; 3937 } 3938 } 3939 } 3940 } 3941 } 3942 } 3943 3944 my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); 3945 3946 if(my $Size = getSize($TypeId)) 3947 { 3948 $Size = $Size/$BYTE_SIZE; 3949 $TypeAttr{"Size"} = "$Size"; 3950 } 3951 else 3952 { 3953 if($ExtraDump) 3954 { 3955 if(not defined $TypeAttr{"Memb"} 3956 and not $Tmpl) 3957 { # declaration only 3958 $TypeAttr{"Forward"} = 1; 3959 } 3960 } 3961 } 3962 3963 if($TypeAttr{"Type"} eq "Struct" 3964 and ($StaticFields or detect_lang($TypeId))) 3965 { 3966 $TypeAttr{"Type"} = "Class"; 3967 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo() 3968 } 3969 if($TypeAttr{"Type"} eq "Struct" 3970 or $TypeAttr{"Type"} eq "Class") 3971 { 3972 my $Skip = setBaseClasses($TypeId, \%TypeAttr); 3973 if($Skip) { 3974 return (); 3975 } 3976 } 3977 if(my $Algn = getAlgn($TypeId)) { 3978 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; 3979 } 3980 setSpec($TypeId, \%TypeAttr); 3981 3982 if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) 3983 { 3984 if(not $TypedefToAnon{$TypeId} 3985 and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) 3986 { 3987 if(not isAnon($TypeAttr{"Name"})) { 3988 $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; 3989 } 3990 } 3991 } 3992 3993 $TypeAttr{"Tid"} = $TypeId; 3994 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}}) 3995 { 3996 my @Entries = split(/\n/, $VTable); 3997 foreach (1 .. $#Entries) 3998 { 3999 my $Entry = $Entries[$_]; 4000 if($Entry=~/\A(\d+)\s+(.+)\Z/) { 4001 $TypeAttr{"VTable"}{$1} = simplifyVTable($2); 4002 } 4003 } 4004 } 4005 4006 if($TypeAttr{"Type"} eq "Enum") 4007 { 4008 if(not $TypeAttr{"NameSpace"}) 4009 { 4010 foreach my $Pos (keys(%{$TypeAttr{"Memb"}})) 4011 { 4012 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"}; 4013 my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"}; 4014 $EnumConstants{$Version}{$MName} = { 4015 "Value"=>$MVal, 4016 "Header"=>$TypeAttr{"Header"} 4017 }; 4018 if(isAnon($TypeAttr{"Name"})) 4019 { 4020 if($ExtraDump 4021 or is_target_header($TypeAttr{"Header"}, $Version)) 4022 { 4023 %{$Constants{$Version}{$MName}} = ( 4024 "Value" => $MVal, 4025 "Header" => $TypeAttr{"Header"} 4026 ); 4027 } 4028 } 4029 } 4030 } 4031 } 4032 if($ExtraDump) 4033 { 4034 if(defined $TypedefToAnon{$TypeId}) { 4035 $TypeAttr{"AnonTypedef"} = 1; 4036 } 4037 } 4038 4039 return %TypeAttr; 4040} 4041 4042sub simplifyVTable($) 4043{ 4044 my $Content = $_[0]; 4045 if($Content=~s/ \[with (.+)]//) 4046 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>] 4047 if(my @Elems = separate_Params($1, 0, 0)) 4048 { 4049 foreach my $Elem (@Elems) 4050 { 4051 if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) 4052 { 4053 my ($Arg, $Val) = ($1, $2); 4054 4055 if(defined $DEFAULT_STD_ARGS{$Arg}) { 4056 $Content=~s/,\s*$Arg\b//g; 4057 } 4058 else { 4059 $Content=~s/\b$Arg\b/$Val/g; 4060 } 4061 } 4062 } 4063 } 4064 } 4065 4066 return $Content; 4067} 4068 4069sub detect_lang($) 4070{ 4071 my $TypeId = $_[0]; 4072 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4073 if(check_gcc($GCC_PATH, "4")) 4074 { # GCC 4 fncs-node points to only non-artificial methods 4075 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /); 4076 } 4077 else 4078 { # GCC 3 4079 my $Fncs = getTreeAttr_Fncs($TypeId); 4080 while($Fncs) 4081 { 4082 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) { 4083 return 1; 4084 } 4085 $Fncs = getTreeAttr_Chan($Fncs); 4086 } 4087 } 4088 return 0; 4089} 4090 4091sub setSpec($$) 4092{ 4093 my ($TypeId, $TypeAttr) = @_; 4094 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4095 if($Info=~/\s+spec\s+/) { 4096 $TypeAttr->{"Spec"} = 1; 4097 } 4098} 4099 4100sub setBaseClasses($$) 4101{ 4102 my ($TypeId, $TypeAttr) = @_; 4103 my $Info = $LibInfo{$Version}{"info"}{$TypeId}; 4104 if(my $Binf = getTreeAttr_Binf($TypeId)) 4105 { 4106 my $Info = $LibInfo{$Version}{"info"}{$Binf}; 4107 my $Pos = 0; 4108 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) 4109 { 4110 my ($Access, $BInfoId) = ($1, $2); 4111 my $ClassId = getBinfClassId($BInfoId); 4112 4113 if($ClassId eq $TypeId) 4114 { # class A<N>:public A<N-1> 4115 next; 4116 } 4117 4118 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId}; 4119 if(not $CType or $CType eq "template_type_parm" 4120 or $CType eq "typename_type") 4121 { # skip 4122 # return 1; 4123 } 4124 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; 4125 if($Access=~/prot/) { 4126 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected"; 4127 } 4128 elsif($Access=~/priv/) { 4129 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private"; 4130 } 4131 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos"; 4132 if($BaseInfo=~/virt/) 4133 { # virtual base 4134 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1; 4135 } 4136 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1; 4137 $Pos += 1; 4138 } 4139 } 4140 return 0; 4141} 4142 4143sub getBinfClassId($) 4144{ 4145 my $Info = $LibInfo{$Version}{"info"}{$_[0]}; 4146 $Info=~/type[ ]*:[ ]*@(\d+) /; 4147 return $1; 4148} 4149 4150sub unmangledFormat($$) 4151{ 4152 my ($Name, $LibVersion) = @_; 4153 $Name = uncover_typedefs($Name, $LibVersion); 4154 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){}; 4155 $Name=~s/\(\w+\)(\d)/$1/; 4156 return $Name; 4157} 4158 4159sub modelUnmangled($$) 4160{ 4161 my ($InfoId, $Compiler) = @_; 4162 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) { 4163 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}; 4164 } 4165 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 4166 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4167 $PureSignature = "~".$PureSignature; 4168 } 4169 if(not $SymbolInfo{$Version}{$InfoId}{"Data"}) 4170 { 4171 my (@Params, @ParamTypes) = (); 4172 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"} 4173 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 4174 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}}); 4175 } 4176 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4177 { # checking parameters 4178 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4179 my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; 4180 my %PType = get_PureType($PId, $TypeInfo{$Version}); 4181 my $PTName = unmangledFormat($PType{"Name"}, $Version); 4182 4183 if($PName eq "this" 4184 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") 4185 { 4186 next; 4187 } 4188 4189 $PTName=~s/\b(restrict|register)\b//g; 4190 if($Compiler eq "MSVC") { 4191 $PTName=~s/\blong long\b/__int64/; 4192 } 4193 @ParamTypes = (@ParamTypes, $PTName); 4194 } 4195 if(@ParamTypes) { 4196 $PureSignature .= "(".join(", ", @ParamTypes).")"; 4197 } 4198 else 4199 { 4200 if($Compiler eq "MSVC") 4201 { 4202 $PureSignature .= "(void)"; 4203 } 4204 else 4205 { # GCC 4206 $PureSignature .= "()"; 4207 } 4208 } 4209 $PureSignature = delete_keywords($PureSignature); 4210 } 4211 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 4212 { 4213 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version); 4214 $PureSignature = $ClassName."::".$PureSignature; 4215 } 4216 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { 4217 $PureSignature = $NS."::".$PureSignature; 4218 } 4219 if($SymbolInfo{$Version}{$InfoId}{"Const"}) { 4220 $PureSignature .= " const"; 4221 } 4222 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) { 4223 $PureSignature .= " volatile"; 4224 } 4225 my $ShowReturn = 0; 4226 if($Compiler eq "MSVC" 4227 and $SymbolInfo{$Version}{$InfoId}{"Data"}) 4228 { 4229 $ShowReturn=1; 4230 } 4231 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId} 4232 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}})) 4233 { 4234 $ShowReturn=1; 4235 } 4236 if($ShowReturn) 4237 { # mangled names for template function specializations include return value 4238 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"}) 4239 { 4240 my %RType = get_PureType($ReturnId, $TypeInfo{$Version}); 4241 my $ReturnName = unmangledFormat($RType{"Name"}, $Version); 4242 $PureSignature = $ReturnName." ".$PureSignature; 4243 } 4244 } 4245 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S")); 4246} 4247 4248sub mangle_symbol($$$) 4249{ # mangling for simple methods 4250 # see gcc-4.6.0/gcc/cp/mangle.c 4251 my ($InfoId, $LibVersion, $Compiler) = @_; 4252 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) { 4253 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}; 4254 } 4255 my $Mangled = ""; 4256 if($Compiler eq "GCC") { 4257 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion); 4258 } 4259 elsif($Compiler eq "MSVC") { 4260 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion); 4261 } 4262 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled); 4263} 4264 4265sub mangle_symbol_MSVC($$) 4266{ # TODO 4267 my ($InfoId, $LibVersion) = @_; 4268 return ""; 4269} 4270 4271sub mangle_symbol_GCC($$) 4272{ # see gcc-4.6.0/gcc/cp/mangle.c 4273 my ($InfoId, $LibVersion) = @_; 4274 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, ""); 4275 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 4276 my %Repl = ();# SN_ replacements 4277 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 4278 { 4279 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl); 4280 if($MangledClass!~/\AN/) { 4281 $MangledClass = "N".$MangledClass; 4282 } 4283 else { 4284 $MangledClass=~s/E\Z//; 4285 } 4286 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) { 4287 $MangledClass=~s/\AN/NV/; 4288 } 4289 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) { 4290 $MangledClass=~s/\AN/NK/; 4291 } 4292 $Mangled .= $MangledClass; 4293 } 4294 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"}) 4295 { # mangled by name due to the absence of structured info 4296 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl); 4297 if($MangledNS!~/\AN/) { 4298 $MangledNS = "N".$MangledNS; 4299 } 4300 else { 4301 $MangledNS=~s/E\Z//; 4302 } 4303 $Mangled .= $MangledNS; 4304 } 4305 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}); 4306 my @TParams = (); 4307 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) 4308 { # parsing mode 4309 foreach (@TPos) { 4310 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"}); 4311 } 4312 } 4313 elsif($TmplParams) 4314 { # remangling mode 4315 # support for old ABI dumps 4316 @TParams = separate_Params($TmplParams, 0, 0); 4317 } 4318 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { 4319 $Mangled .= "C1"; 4320 } 4321 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4322 $Mangled .= "D0"; 4323 } 4324 elsif($ShortName) 4325 { 4326 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4327 { 4328 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 4329 and isConstType($Return, $LibVersion)) 4330 { # "const" global data is mangled as _ZL... 4331 $Mangled .= "L"; 4332 } 4333 } 4334 if($ShortName=~/\Aoperator(\W.*)\Z/) 4335 { 4336 my $Op = $1; 4337 $Op=~s/\A[ ]+//g; 4338 if(my $OpMngl = $OperatorMangling{$Op}) { 4339 $Mangled .= $OpMngl; 4340 } 4341 else { # conversion operator 4342 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl); 4343 } 4344 } 4345 else { 4346 $Mangled .= length($ShortName).$ShortName; 4347 } 4348 if(@TParams) 4349 { # templates 4350 $Mangled .= "I"; 4351 foreach my $TParam (@TParams) { 4352 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl); 4353 } 4354 $Mangled .= "E"; 4355 } 4356 if(not $ClassId and @TParams) { 4357 add_substitution($ShortName, \%Repl, 0); 4358 } 4359 } 4360 if($ClassId or $NameSpace) { 4361 $Mangled .= "E"; 4362 } 4363 if(@TParams) 4364 { 4365 if($Return) { 4366 $Mangled .= mangle_param($Return, $LibVersion, \%Repl); 4367 } 4368 } 4369 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 4370 { 4371 my @Params = (); 4372 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 4373 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { 4374 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 4375 } 4376 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) 4377 { # checking parameters 4378 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"}; 4379 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl); 4380 } 4381 if(not @Params) { 4382 $Mangled .= "v"; 4383 } 4384 } 4385 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled); 4386 $Mangled = write_stdcxx_substitution($Mangled); 4387 if($Mangled eq "_Z") { 4388 return ""; 4389 } 4390 return $Mangled; 4391} 4392 4393sub correct_incharge($$$) 4394{ 4395 my ($InfoId, $LibVersion, $Mangled) = @_; 4396 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) 4397 { 4398 if($MangledNames{$LibVersion}{$Mangled}) { 4399 $Mangled=~s/C1([EI])/C2$1/; 4400 } 4401 } 4402 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 4403 { 4404 if($MangledNames{$LibVersion}{$Mangled}) { 4405 $Mangled=~s/D0([EI])/D1$1/; 4406 } 4407 if($MangledNames{$LibVersion}{$Mangled}) { 4408 $Mangled=~s/D1([EI])/D2$1/; 4409 } 4410 } 4411 return $Mangled; 4412} 4413 4414sub template_Base($) 4415{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl 4416 # NOTE: operators: >>, << 4417 my $Name = $_[0]; 4418 if($Name!~/>\Z/ or $Name!~/</) { 4419 return $Name; 4420 } 4421 my $TParams = $Name; 4422 while(my $CPos = find_center($TParams, "<")) 4423 { # search for the last <T> 4424 $TParams = substr($TParams, $CPos); 4425 } 4426 if($TParams=~s/\A<(.+)>\Z/$1/) { 4427 $Name=~s/<\Q$TParams\E>\Z//; 4428 } 4429 else 4430 { # error 4431 $TParams = ""; 4432 } 4433 return ($Name, $TParams); 4434} 4435 4436sub get_sub_ns($) 4437{ 4438 my $Name = $_[0]; 4439 my @NS = (); 4440 while(my $CPos = find_center($Name, ":")) 4441 { 4442 push(@NS, substr($Name, 0, $CPos)); 4443 $Name = substr($Name, $CPos); 4444 $Name=~s/\A:://; 4445 } 4446 return (join("::", @NS), $Name); 4447} 4448 4449sub mangle_ns($$$) 4450{ 4451 my ($Name, $LibVersion, $Repl) = @_; 4452 if(my $Tid = $TName_Tid{$LibVersion}{$Name}) 4453 { 4454 my $Mangled = mangle_param($Tid, $LibVersion, $Repl); 4455 $Mangled=~s/\AN(.+)E\Z/$1/; 4456 return $Mangled; 4457 4458 } 4459 else 4460 { 4461 my ($MangledNS, $SubNS) = ("", ""); 4462 ($SubNS, $Name) = get_sub_ns($Name); 4463 if($SubNS) { 4464 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4465 } 4466 $MangledNS .= length($Name).$Name; 4467 add_substitution($MangledNS, $Repl, 0); 4468 return $MangledNS; 4469 } 4470} 4471 4472sub mangle_param($$$) 4473{ 4474 my ($PTid, $LibVersion, $Repl) = @_; 4475 my ($MPrefix, $Mangled) = ("", ""); 4476 my %ReplCopy = %{$Repl}; 4477 my %BaseType = get_BaseType($PTid, $LibVersion); 4478 my $BaseType_Name = $BaseType{"Name"}; 4479 $BaseType_Name=~s/\A(struct|union|enum) //g; 4480 if(not $BaseType_Name) { 4481 return ""; 4482 } 4483 my ($ShortName, $TmplParams) = template_Base($BaseType_Name); 4484 my $Suffix = get_BaseTypeQual($PTid, $LibVersion); 4485 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){}; 4486 while($Suffix=~/(&|\*|const)\Z/) 4487 { 4488 if($Suffix=~s/[ ]*&\Z//) { 4489 $MPrefix .= "R"; 4490 } 4491 if($Suffix=~s/[ ]*\*\Z//) { 4492 $MPrefix .= "P"; 4493 } 4494 if($Suffix=~s/[ ]*const\Z//) 4495 { 4496 if($MPrefix=~/R|P/ 4497 or $Suffix=~/&|\*/) { 4498 $MPrefix .= "K"; 4499 } 4500 } 4501 if($Suffix=~s/[ ]*volatile\Z//) { 4502 $MPrefix .= "V"; 4503 } 4504 #if($Suffix=~s/[ ]*restrict\Z//) { 4505 #$MPrefix .= "r"; 4506 #} 4507 } 4508 if(my $Token = $IntrinsicMangling{$BaseType_Name}) { 4509 $Mangled .= $Token; 4510 } 4511 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/) 4512 { 4513 my @TParams = (); 4514 if(my @TPos = keys(%{$BaseType{"TParam"}})) 4515 { # parsing mode 4516 foreach (@TPos) { 4517 push(@TParams, $BaseType{"TParam"}{$_}{"name"}); 4518 } 4519 } 4520 elsif($TmplParams) 4521 { # remangling mode 4522 # support for old ABI dumps 4523 @TParams = separate_Params($TmplParams, 0, 0); 4524 } 4525 my $MangledNS = ""; 4526 my ($SubNS, $SName) = get_sub_ns($ShortName); 4527 if($SubNS) { 4528 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); 4529 } 4530 $MangledNS .= length($SName).$SName; 4531 if(@TParams) { 4532 add_substitution($MangledNS, $Repl, 0); 4533 } 4534 $Mangled .= "N".$MangledNS; 4535 if(@TParams) 4536 { # templates 4537 $Mangled .= "I"; 4538 foreach my $TParam (@TParams) { 4539 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl); 4540 } 4541 $Mangled .= "E"; 4542 } 4543 $Mangled .= "E"; 4544 } 4545 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/) 4546 { 4547 if($BaseType{"Type"} eq "MethodPtr") { 4548 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F"; 4549 } 4550 else { 4551 $Mangled .= "PF"; 4552 } 4553 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4554 my @Params = keys(%{$BaseType{"Param"}}); 4555 foreach my $Num (sort {int($a)<=>int($b)} @Params) { 4556 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl); 4557 } 4558 if(not @Params) { 4559 $Mangled .= "v"; 4560 } 4561 $Mangled .= "E"; 4562 } 4563 elsif($BaseType{"Type"} eq "FieldPtr") 4564 { 4565 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl); 4566 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); 4567 } 4568 $Mangled = $MPrefix.$Mangled;# add prefix (RPK) 4569 if(my $Optimized = write_substitution($Mangled, \%ReplCopy)) 4570 { 4571 if($Mangled eq $Optimized) 4572 { 4573 if($ShortName!~/::/) 4574 { # remove "N ... E" 4575 if($MPrefix) { 4576 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g; 4577 } 4578 else { 4579 $Mangled=~s/\AN(.+)E\Z/$1/g; 4580 } 4581 } 4582 } 4583 else { 4584 $Mangled = $Optimized; 4585 } 4586 } 4587 add_substitution($Mangled, $Repl, 1); 4588 return $Mangled; 4589} 4590 4591sub mangle_template_param($$$) 4592{ # types + literals 4593 my ($TParam, $LibVersion, $Repl) = @_; 4594 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) { 4595 return mangle_param($TPTid, $LibVersion, $Repl); 4596 } 4597 elsif($TParam=~/\A(\d+)(\w+)\Z/) 4598 { # class_name<1u>::method(...) 4599 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E"; 4600 } 4601 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/) 4602 { # class_name<(signed char)1>::method(...) 4603 return "L".$IntrinsicMangling{$1}.$2."E"; 4604 } 4605 elsif($TParam eq "true") 4606 { # class_name<true>::method(...) 4607 return "Lb1E"; 4608 } 4609 elsif($TParam eq "false") 4610 { # class_name<true>::method(...) 4611 return "Lb0E"; 4612 } 4613 else { # internal error 4614 return length($TParam).$TParam; 4615 } 4616} 4617 4618sub add_substitution($$$) 4619{ 4620 my ($Value, $Repl, $Rec) = @_; 4621 if($Rec) 4622 { # subtypes 4623 my @Subs = ($Value); 4624 while($Value=~s/\A(R|P|K)//) { 4625 push(@Subs, $Value); 4626 } 4627 foreach (reverse(@Subs)) { 4628 add_substitution($_, $Repl, 0); 4629 } 4630 return; 4631 } 4632 return if($Value=~/\AS(\d*)_\Z/); 4633 $Value=~s/\AN(.+)E\Z/$1/g; 4634 return if(defined $Repl->{$Value}); 4635 return if(length($Value)<=1); 4636 return if($StdcxxMangling{$Value}); 4637 # check for duplicates 4638 my $Base = $Value; 4639 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4640 { 4641 my $Num = $Repl->{$Type}; 4642 my $Replace = macro_mangle($Num); 4643 $Base=~s/\Q$Replace\E/$Type/; 4644 } 4645 if(my $OldNum = $Repl->{$Base}) 4646 { 4647 $Repl->{$Value} = $OldNum; 4648 return; 4649 } 4650 my @Repls = sort {$b<=>$a} values(%{$Repl}); 4651 if(@Repls) { 4652 $Repl->{$Value} = $Repls[0]+1; 4653 } 4654 else { 4655 $Repl->{$Value} = -1; 4656 } 4657 # register duplicates 4658 # upward 4659 $Base = $Value; 4660 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 4661 { 4662 next if($Base eq $Type); 4663 my $Num = $Repl->{$Type}; 4664 my $Replace = macro_mangle($Num); 4665 $Base=~s/\Q$Type\E/$Replace/; 4666 $Repl->{$Base} = $Repl->{$Value}; 4667 } 4668} 4669 4670sub macro_mangle($) 4671{ 4672 my $Num = $_[0]; 4673 if($Num==-1) { 4674 return "S_"; 4675 } 4676 else 4677 { 4678 my $Code = ""; 4679 if($Num<10) 4680 { # S0_, S1_, S2_, ... 4681 $Code = $Num; 4682 } 4683 elsif($Num>=10 and $Num<=35) 4684 { # SA_, SB_, SC_, ... 4685 $Code = chr(55+$Num); 4686 } 4687 else 4688 { # S10_, S11_, S12_ 4689 $Code = $Num-26; # 26 is length of english alphabet 4690 } 4691 return "S".$Code."_"; 4692 } 4693} 4694 4695sub write_stdcxx_substitution($) 4696{ 4697 my $Mangled = $_[0]; 4698 if($StdcxxMangling{$Mangled}) { 4699 return $StdcxxMangling{$Mangled}; 4700 } 4701 else 4702 { 4703 my @Repls = keys(%StdcxxMangling); 4704 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4705 foreach my $MangledType (@Repls) 4706 { 4707 my $Replace = $StdcxxMangling{$MangledType}; 4708 #if($Mangled!~/$Replace/) { 4709 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4710 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4711 #} 4712 } 4713 } 4714 return $Mangled; 4715} 4716 4717sub write_substitution($$) 4718{ 4719 my ($Mangled, $Repl) = @_; 4720 if(defined $Repl->{$Mangled} 4721 and my $MnglNum = $Repl->{$Mangled}) { 4722 $Mangled = macro_mangle($MnglNum); 4723 } 4724 else 4725 { 4726 my @Repls = keys(%{$Repl}); 4727 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls; 4728 # FIXME: how to apply replacements? by num or by pos 4729 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 4730 foreach my $MangledType (@Repls) 4731 { 4732 my $Replace = macro_mangle($Repl->{$MangledType}); 4733 if($Mangled!~/$Replace/) { 4734 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 4735 $Mangled=~s/\Q$MangledType\E/$Replace/g; 4736 } 4737 } 4738 } 4739 return $Mangled; 4740} 4741 4742sub delete_keywords($) 4743{ 4744 my $TypeName = $_[0]; 4745 $TypeName=~s/\b(enum|struct|union|class) //g; 4746 return $TypeName; 4747} 4748 4749sub uncover_typedefs($$) 4750{ 4751 my ($TypeName, $LibVersion) = @_; 4752 return "" if(not $TypeName); 4753 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) { 4754 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}; 4755 } 4756 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), ""); 4757 while($TypeName_New ne $TypeName_Pre) 4758 { 4759 $TypeName_Pre = $TypeName_New; 4760 my $TypeName_Copy = $TypeName_New; 4761 my %Words = (); 4762 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io) 4763 { 4764 if(not $Intrinsic_Keywords{$1}) { 4765 $Words{$1} = 1; 4766 } 4767 } 4768 foreach my $Word (keys(%Words)) 4769 { 4770 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word}; 4771 next if(not $BaseType_Name); 4772 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/); 4773 if($BaseType_Name=~/\([\*]+\)/) 4774 { # FuncPtr 4775 if($TypeName_New=~/\Q$Word\E(.*)\Z/) 4776 { 4777 my $Type_Suffix = $1; 4778 $TypeName_New = $BaseType_Name; 4779 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) { 4780 $TypeName_New = formatName($TypeName_New, "T"); 4781 } 4782 } 4783 } 4784 else 4785 { 4786 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) { 4787 $TypeName_New = formatName($TypeName_New, "T"); 4788 } 4789 } 4790 } 4791 } 4792 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New); 4793} 4794 4795sub isInternal($) 4796{ 4797 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 4798 { 4799 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) 4800 { 4801 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/) 4802 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL* 4803 return 1; 4804 } 4805 } 4806 } 4807 return 0; 4808} 4809 4810sub getDataVal($$) 4811{ 4812 my ($InfoId, $TypeId) = @_; 4813 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4814 { 4815 if($Info=~/init[ ]*:[ ]*@(\d+) /) 4816 { 4817 if(defined $LibInfo{$Version}{"info_type"}{$1} 4818 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr") 4819 { 4820 if(my $Nop = getTreeAttr_Op($1)) 4821 { 4822 if(defined $LibInfo{$Version}{"info_type"}{$Nop} 4823 and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr") 4824 { 4825 if(my $Addr = getTreeAttr_Op($1)) { 4826 return getInitVal($Addr, $TypeId); 4827 } 4828 } 4829 } 4830 } 4831 else { 4832 return getInitVal($1, $TypeId); 4833 } 4834 } 4835 } 4836 return undef; 4837} 4838 4839sub getInitVal($$) 4840{ 4841 my ($InfoId, $TypeId) = @_; 4842 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4843 { 4844 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId}) 4845 { 4846 if($InfoType eq "integer_cst") 4847 { 4848 my $Val = getNodeIntCst($InfoId); 4849 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/) 4850 { # characters 4851 $Val = chr($Val); 4852 } 4853 return $Val; 4854 } 4855 elsif($InfoType eq "string_cst") { 4856 return getNodeStrCst($InfoId); 4857 } 4858 elsif($InfoType eq "var_decl") 4859 { 4860 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) { 4861 return $Name; 4862 } 4863 } 4864 } 4865 } 4866 return undef; 4867} 4868 4869sub set_Class_And_Namespace($) 4870{ 4871 my $InfoId = $_[0]; 4872 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) 4873 { 4874 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) 4875 { 4876 my $NSInfoId = $1; 4877 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 4878 { 4879 if($InfoType eq "namespace_decl") { 4880 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId); 4881 } 4882 elsif($InfoType eq "record_type") { 4883 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId; 4884 } 4885 } 4886 } 4887 } 4888 if($SymbolInfo{$Version}{$InfoId}{"Class"} 4889 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) 4890 { 4891 if($COMMON_LANGUAGE{$Version} ne "C++") 4892 { # skip 4893 return 1; 4894 } 4895 } 4896 4897 return 0; 4898} 4899 4900sub debugMangling($) 4901{ 4902 my $LibVersion = $_[0]; 4903 my %Mangled = (); 4904 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 4905 { 4906 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 4907 { 4908 if($Mngl=~/\A(_Z|\?)/) { 4909 $Mangled{$Mngl}=$InfoId; 4910 } 4911 } 4912 } 4913 translateSymbols(keys(%Mangled), $LibVersion); 4914 foreach my $Mngl (keys(%Mangled)) 4915 { 4916 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC"); 4917 my $U2 = $tr_name{$Mngl}; 4918 if($U1 ne $U2) { 4919 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n"); 4920 } 4921 } 4922} 4923 4924sub linkSymbol($) 4925{ # link symbols from shared libraries 4926 # with the symbols from header files 4927 my $InfoId = $_[0]; 4928 # try to mangle symbol 4929 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"}) 4930 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 4931 or $EMERGENCY_MODE_48) 4932 { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) 4933 # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions 4934 # GCC 4.8.[012] doesn't mangle anything 4935 if(not $CheckHeadersOnly) 4936 { 4937 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) { 4938 return correct_incharge($InfoId, $Version, $Mangled); 4939 } 4940 } 4941 if($CheckHeadersOnly 4942 or not $BinaryOnly 4943 or $EMERGENCY_MODE_48) 4944 { # 1. --headers-only mode 4945 # 2. not mangled src-only symbols 4946 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) { 4947 return $Mangled; 4948 } 4949 } 4950 } 4951 return ""; 4952} 4953 4954sub setLanguage($$) 4955{ 4956 my ($LibVersion, $Lang) = @_; 4957 if(not $UserLang) { 4958 $COMMON_LANGUAGE{$LibVersion} = $Lang; 4959 } 4960} 4961 4962sub getSymbolInfo($) 4963{ 4964 my $InfoId = $_[0]; 4965 if(isInternal($InfoId)) { 4966 return; 4967 } 4968 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); 4969 if(not $SymbolInfo{$Version}{$InfoId}{"Header"} 4970 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) 4971 { 4972 delete($SymbolInfo{$Version}{$InfoId}); 4973 return; 4974 } 4975 setFuncAccess($InfoId); 4976 setFuncKind($InfoId); 4977 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) 4978 { 4979 delete($SymbolInfo{$Version}{$InfoId}); 4980 return; 4981 } 4982 4983 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId); 4984 if(my $Return = getFuncReturn($InfoId)) 4985 { 4986 if(not defined $TypeInfo{$Version}{$Return} 4987 or not $TypeInfo{$Version}{$Return}{"Name"}) 4988 { 4989 delete($SymbolInfo{$Version}{$InfoId}); 4990 return; 4991 } 4992 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return; 4993 } 4994 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) 4995 { 4996 if(defined $MissedTypedef{$Version}{$Rid}) 4997 { 4998 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { 4999 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; 5000 } 5001 } 5002 } 5003 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) { 5004 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5005 } 5006 my $Orig = getFuncOrig($InfoId); 5007 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig); 5008 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1) 5009 { 5010 delete($SymbolInfo{$Version}{$InfoId}); 5011 return; 5012 } 5013 5014 if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0) 5015 { 5016 delete($SymbolInfo{$Version}{$InfoId}); 5017 return; 5018 } 5019 5020 if(defined $TemplateInstance{$Version}{"Func"}{$Orig}) 5021 { 5022 my $Tmpl = $BasicTemplate{$Version}{$InfoId}; 5023 5024 my @TParams = getTParams($Orig, "Func"); 5025 if(not @TParams) 5026 { 5027 delete($SymbolInfo{$Version}{$InfoId}); 5028 return; 5029 } 5030 foreach my $Pos (0 .. $#TParams) 5031 { 5032 my $Val = $TParams[$Pos]; 5033 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val; 5034 5035 if($Tmpl) 5036 { 5037 if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) 5038 { 5039 $TemplateMap{$Version}{$InfoId}{$Arg} = $Val; 5040 } 5041 } 5042 } 5043 5044 if($Tmpl) 5045 { 5046 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) 5047 { 5048 if($Pos>$#TParams) 5049 { 5050 my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; 5051 $TemplateMap{$Version}{$InfoId}{$Arg} = ""; 5052 } 5053 } 5054 } 5055 5056 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/) 5057 { # operator<< <T>, operator>> <T> 5058 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " "; 5059 } 5060 if(@TParams) { 5061 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".join(", ", @TParams).">"; 5062 } 5063 else { 5064 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<...>"; 5065 } 5066 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S"); 5067 } 5068 else 5069 { # support for GCC 3.4 5070 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5071 } 5072 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) 5073 { 5074 if($OSgroup eq "windows") 5075 { # cut the offset 5076 $MnglName=~s/\@\d+\Z//g; 5077 } 5078 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; 5079 5080 # NOTE: mangling of some symbols may change depending on GCC version 5081 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E 5082 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_ 5083 } 5084 5085 if($SymbolInfo{$Version}{$InfoId}{"MnglName"} 5086 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) 5087 { 5088 delete($SymbolInfo{$Version}{$InfoId}); 5089 return; 5090 } 5091 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) 5092 { # destructors have an empty parameter list 5093 my $Skip = setFuncParams($InfoId); 5094 if($Skip) 5095 { 5096 delete($SymbolInfo{$Version}{$InfoId}); 5097 return; 5098 } 5099 } 5100 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) { 5101 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1; 5102 } 5103 5104 if(set_Class_And_Namespace($InfoId)) 5105 { 5106 delete($SymbolInfo{$Version}{$InfoId}); 5107 return; 5108 } 5109 5110 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5111 { 5112 if(not defined $TypeInfo{$Version}{$ClassId} 5113 or not $TypeInfo{$Version}{$ClassId}{"Name"}) 5114 { 5115 delete($SymbolInfo{$Version}{$InfoId}); 5116 return; 5117 } 5118 } 5119 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) 5120 { # extern "C" 5121 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; 5122 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5123 } 5124 if($UserLang and $UserLang eq "C") 5125 { # --lang=C option 5126 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5127 } 5128 if($COMMON_LANGUAGE{$Version} eq "C++") 5129 { # correct mangled & short names 5130 # C++ or --headers-only mode 5131 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/) 5132 { # support for old GCC versions: reconstruct real names for constructors and destructors 5133 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"})); 5134 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; 5135 } 5136 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5137 { # try to mangle symbol (link with libraries) 5138 if(my $Mangled = linkSymbol($InfoId)) { 5139 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; 5140 } 5141 } 5142 if($OStarget eq "windows") 5143 { # link MS C++ symbols from library with GCC symbols from headers 5144 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) 5145 { # exported symbols 5146 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1; 5147 } 5148 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC")) 5149 { # pure virtual symbols 5150 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2; 5151 } 5152 } 5153 } 5154 else 5155 { # not mangled in C 5156 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5157 } 5158 if(not $CheckHeadersOnly 5159 and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function" 5160 and not $SymbolInfo{$Version}{$InfoId}{"Class"}) 5161 { 5162 my $Incorrect = 0; 5163 5164 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5165 { 5166 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0 5167 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) 5168 { # mangled in the TU dump, but not mangled in the library 5169 $Incorrect = 1; 5170 } 5171 } 5172 else 5173 { 5174 if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C") 5175 { # all C++ functions are not mangled in the TU dump 5176 $Incorrect = 1; 5177 } 5178 } 5179 if($Incorrect) 5180 { 5181 if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) { 5182 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5183 } 5184 } 5185 } 5186 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5187 { # can't detect symbol name 5188 delete($SymbolInfo{$Version}{$InfoId}); 5189 return; 5190 } 5191 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5192 and my $Spec = getVirtSpec($Orig)) 5193 { # identify virtual and pure virtual functions 5194 # NOTE: constructors cannot be virtual 5195 # NOTE: in GCC 4.7 D1 destructors have no virtual spec 5196 # in the TU dump, so taking it from the original symbol 5197 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"} 5198 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/)) 5199 { # NOTE: D2 destructors are not present in a v-table 5200 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1; 5201 } 5202 } 5203 if(isInline($InfoId)) { 5204 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1; 5205 } 5206 if(hasThrow($InfoId)) { 5207 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1; 5208 } 5209 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5210 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) 5211 { 5212 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"} 5213 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"}) 5214 { # inline or auto-generated constructor 5215 delete($TypeInfo{$Version}{$ClassId}{"Copied"}); 5216 } 5217 } 5218 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5219 { 5220 if(not $ExtraDump) 5221 { 5222 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) 5223 { # non-target symbols 5224 delete($SymbolInfo{$Version}{$InfoId}); 5225 return; 5226 } 5227 } 5228 } 5229 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method" 5230 or $SymbolInfo{$Version}{$InfoId}{"Constructor"} 5231 or $SymbolInfo{$Version}{$InfoId}{"Destructor"} 5232 or $SymbolInfo{$Version}{$InfoId}{"Class"}) 5233 { 5234 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) 5235 { 5236 delete($SymbolInfo{$Version}{$InfoId}); 5237 return; 5238 } 5239 } 5240 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) 5241 { 5242 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5243 { # one instance for one mangled name only 5244 delete($SymbolInfo{$Version}{$InfoId}); 5245 return; 5246 } 5247 else { 5248 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1; 5249 } 5250 } 5251 if($SymbolInfo{$Version}{$InfoId}{"Constructor"} 5252 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { 5253 delete($SymbolInfo{$Version}{$InfoId}{"Return"}); 5254 } 5255 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/ 5256 and $SymbolInfo{$Version}{$InfoId}{"Class"}) 5257 { 5258 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function") 5259 { # static methods 5260 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5261 } 5262 } 5263 if(getFuncLink($InfoId) eq "Static") { 5264 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; 5265 } 5266 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/) 5267 { 5268 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) 5269 { 5270 if($Unmangled=~/\.\_\d/) 5271 { 5272 delete($SymbolInfo{$Version}{$InfoId}); 5273 return; 5274 } 5275 } 5276 } 5277 5278 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) { 5279 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5280 } 5281 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) { 5282 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5283 } 5284 5285 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { 5286 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1; 5287 } 5288 5289 if($ExtraDump) { 5290 $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); 5291 } 5292} 5293 5294sub guessHeader($) 5295{ 5296 my $InfoId = $_[0]; 5297 my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; 5298 my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}; 5299 my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):""; 5300 my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"}; 5301 if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName}) 5302 { 5303 if(get_filename($HPath) eq $Header) 5304 { 5305 my $HDir = get_filename(get_dirname($HPath)); 5306 if($HDir ne "include" 5307 and $HDir=~/\A[a-z]+\Z/i) { 5308 return join_P($HDir, $Header); 5309 } 5310 } 5311 } 5312 return $Header; 5313} 5314 5315sub isInline($) 5316{ # "body: undefined" in the tree 5317 # -fkeep-inline-functions GCC option should be specified 5318 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5319 { 5320 if($Info=~/ undefined /i) { 5321 return 0; 5322 } 5323 } 5324 return 1; 5325} 5326 5327sub hasThrow($) 5328{ 5329 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5330 { 5331 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5332 return getTreeAttr_Unql($1, "unql"); 5333 } 5334 } 5335 return 1; 5336} 5337 5338sub getTypeId($) 5339{ 5340 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5341 { 5342 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5343 return $1; 5344 } 5345 } 5346 return ""; 5347} 5348 5349sub setTypeMemb($$) 5350{ 5351 my ($TypeId, $TypeAttr) = @_; 5352 my $TypeType = $TypeAttr->{"Type"}; 5353 my ($Pos, $UnnamedPos) = (0, 0); 5354 my $StaticFields = 0; 5355 if($TypeType eq "Enum") 5356 { 5357 my $MInfoId = getTreeAttr_Csts($TypeId); 5358 while($MInfoId) 5359 { 5360 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId); 5361 my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId)); 5362 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName; 5363 $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName; 5364 $MInfoId = getNextElem($MInfoId); 5365 $Pos += 1; 5366 } 5367 } 5368 elsif($TypeType=~/\A(Struct|Class|Union)\Z/) 5369 { 5370 my $MInfoId = getTreeAttr_Flds($TypeId); 5371 while($MInfoId) 5372 { 5373 my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId}; 5374 my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId}; 5375 if(not $IType or $IType ne "field_decl") 5376 { # search for fields, skip other stuff in the declaration 5377 5378 if($IType eq "var_decl") 5379 { # static field 5380 $StaticFields = 1; 5381 } 5382 5383 $MInfoId = getNextElem($MInfoId); 5384 next; 5385 } 5386 my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId)); 5387 if(index($StructMembName, "_vptr.")==0) 5388 { # virtual tables 5389 $StructMembName = "_vptr"; 5390 } 5391 if(not $StructMembName) 5392 { # unnamed fields 5393 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1) 5394 { 5395 my $UnnamedTid = getTreeAttr_Type($MInfoId); 5396 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid)); 5397 if(isAnon($UnnamedTName)) 5398 { # rename unnamed fields to unnamed0, unnamed1, ... 5399 $StructMembName = "unnamed".($UnnamedPos++); 5400 } 5401 } 5402 } 5403 if(not $StructMembName) 5404 { # unnamed fields and base classes 5405 $MInfoId = getNextElem($MInfoId); 5406 next; 5407 } 5408 my $MembTypeId = getTreeAttr_Type($MInfoId); 5409 if(defined $MissedTypedef{$Version}{$MembTypeId}) 5410 { 5411 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) { 5412 $MembTypeId = $AddedTid; 5413 } 5414 } 5415 5416 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId; 5417 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName; 5418 if((my $Access = getTreeAccess($MInfoId)) ne "public") 5419 { # marked only protected and private, public by default 5420 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access; 5421 } 5422 if($MInfo=~/spec:\s*mutable /) 5423 { # mutable fields 5424 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1; 5425 } 5426 if(my $Algn = getAlgn($MInfoId)) { 5427 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn; 5428 } 5429 if(my $BFSize = getBitField($MInfoId)) 5430 { # in bits 5431 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize; 5432 } 5433 else 5434 { # in bytes 5435 if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1) 5436 { # template 5437 delete($TypeAttr->{"Memb"}{$Pos}{"algn"}); 5438 } 5439 else { 5440 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; 5441 } 5442 } 5443 5444 $MInfoId = getNextElem($MInfoId); 5445 $Pos += 1; 5446 } 5447 } 5448 5449 return $StaticFields; 5450} 5451 5452sub setFuncParams($) 5453{ 5454 my $InfoId = $_[0]; 5455 my $ParamInfoId = getTreeAttr_Args($InfoId); 5456 5457 my $FType = getFuncType($InfoId); 5458 5459 if($FType eq "Method") 5460 { # check type of "this" pointer 5461 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId); 5462 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"}) 5463 { 5464 if($ObjectName=~/\bconst(| volatile)\*const\b/) { 5465 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; 5466 } 5467 if($ObjectName=~/\bvolatile\b/) { 5468 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; 5469 } 5470 } 5471 else 5472 { # skip 5473 return 1; 5474 } 5475 # skip "this"-parameter 5476 # $ParamInfoId = getNextElem($ParamInfoId); 5477 } 5478 my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1); 5479 while($ParamInfoId) 5480 { # formal args 5481 my $ParamTypeId = getTreeAttr_Type($ParamInfoId); 5482 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId)); 5483 if(not $ParamName) 5484 { # unnamed 5485 $ParamName = "p".($PPos+1); 5486 } 5487 if(defined $MissedTypedef{$Version}{$ParamTypeId}) 5488 { 5489 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) { 5490 $ParamTypeId = $AddedTid; 5491 } 5492 } 5493 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"}; 5494 if(not $PType or $PType eq "Unknown") { 5495 return 1; 5496 } 5497 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"}; 5498 if(not $PTName) { 5499 return 1; 5500 } 5501 if($PTName eq "void") { 5502 last; 5503 } 5504 if($ParamName eq "__vtt_parm" 5505 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**") 5506 { 5507 $Vtt_Pos = $Pos; 5508 $ParamInfoId = getNextElem($ParamInfoId); 5509 next; 5510 } 5511 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5512 5513 if(my %Base = get_BaseType($ParamTypeId, $Version)) 5514 { 5515 if(defined $Base{"Template"}) { 5516 return 1; 5517 } 5518 } 5519 5520 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName; 5521 if(my $Algn = getAlgn($ParamInfoId)) { 5522 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE; 5523 } 5524 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /) 5525 { # foo(register type arg) 5526 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1; 5527 } 5528 $ParamInfoId = getNextElem($ParamInfoId); 5529 $Pos += 1; 5530 if($ParamName ne "this" or $FType ne "Method") { 5531 $PPos += 1; 5532 } 5533 } 5534 if(setFuncArgs($InfoId, $Vtt_Pos)) { 5535 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1"; 5536 } 5537 return 0; 5538} 5539 5540sub setFuncArgs($$) 5541{ 5542 my ($InfoId, $Vtt_Pos) = @_; 5543 my $FuncTypeId = getFuncTypeId($InfoId); 5544 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId); 5545 my $FType = getFuncType($InfoId); 5546 5547 if($FType eq "Method") 5548 { 5549 # skip "this"-parameter 5550 # $ParamListElemId = getNextElem($ParamListElemId); 5551 } 5552 if(not $ParamListElemId) 5553 { # foo(...) 5554 return 1; 5555 } 5556 my $HaveVoid = 0; 5557 my ($Pos, $PPos) = (0, 0); 5558 while($ParamListElemId) 5559 { # actual params: may differ from formal args 5560 # formal int*const 5561 # actual: int* 5562 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos) 5563 { 5564 $Vtt_Pos=-1; 5565 $ParamListElemId = getNextElem($ParamListElemId); 5566 next; 5567 } 5568 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId); 5569 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void") 5570 { 5571 $HaveVoid = 1; 5572 last; 5573 } 5574 else 5575 { 5576 if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5577 { 5578 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5579 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) 5580 { # unnamed 5581 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1); 5582 } 5583 } 5584 elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) 5585 { 5586 if($Pos>0 or getFuncType($InfoId) ne "Method") 5587 { # params 5588 if($OldId ne $ParamTypeId) 5589 { 5590 my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version}); 5591 my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version}); 5592 5593 if($Old_Pure{"Name"} ne $New_Pure{"Name"}) { 5594 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; 5595 } 5596 } 5597 } 5598 } 5599 } 5600 if(my $PurpId = getTreeAttr_Purp($ParamListElemId)) 5601 { # default arguments 5602 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) 5603 { 5604 if($PurpType eq "nop_expr") 5605 { # func ( const char* arg = (const char*)(void*)0 ) 5606 $PurpId = getTreeAttr_Op($PurpId); 5607 } 5608 my $Val = getInitVal($PurpId, $ParamTypeId); 5609 if(defined $Val) { 5610 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val; 5611 } 5612 } 5613 } 5614 $ParamListElemId = getNextElem($ParamListElemId); 5615 if($Pos!=0 or $FType ne "Method") { 5616 $PPos += 1; 5617 } 5618 $Pos += 1; 5619 } 5620 return ($Pos>=1 and not $HaveVoid); 5621} 5622 5623sub getTreeAttr_Chan($) 5624{ 5625 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5626 { 5627 if($Info=~/chan[ ]*:[ ]*@(\d+) /) { 5628 return $1; 5629 } 5630 } 5631 return ""; 5632} 5633 5634sub getTreeAttr_Chain($) 5635{ 5636 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5637 { 5638 if($Info=~/chain[ ]*:[ ]*@(\d+) /) { 5639 return $1; 5640 } 5641 } 5642 return ""; 5643} 5644 5645sub getTreeAttr_Unql($) 5646{ 5647 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5648 { 5649 if($Info=~/unql[ ]*:[ ]*@(\d+) /) { 5650 return $1; 5651 } 5652 } 5653 return ""; 5654} 5655 5656sub getTreeAttr_Scpe($) 5657{ 5658 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5659 { 5660 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) { 5661 return $1; 5662 } 5663 } 5664 return ""; 5665} 5666 5667sub getTreeAttr_Type($) 5668{ 5669 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5670 { 5671 if($Info=~/type[ ]*:[ ]*@(\d+) /) { 5672 return $1; 5673 } 5674 } 5675 return ""; 5676} 5677 5678sub getTreeAttr_Name($) 5679{ 5680 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5681 { 5682 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 5683 return $1; 5684 } 5685 } 5686 return ""; 5687} 5688 5689sub getTreeAttr_Mngl($) 5690{ 5691 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5692 { 5693 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) { 5694 return $1; 5695 } 5696 } 5697 return ""; 5698} 5699 5700sub getTreeAttr_Prms($) 5701{ 5702 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5703 { 5704 if($Info=~/prms[ ]*:[ ]*@(\d+) /) { 5705 return $1; 5706 } 5707 } 5708 return ""; 5709} 5710 5711sub getTreeAttr_Fncs($) 5712{ 5713 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5714 { 5715 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) { 5716 return $1; 5717 } 5718 } 5719 return ""; 5720} 5721 5722sub getTreeAttr_Csts($) 5723{ 5724 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5725 { 5726 if($Info=~/csts[ ]*:[ ]*@(\d+) /) { 5727 return $1; 5728 } 5729 } 5730 return ""; 5731} 5732 5733sub getTreeAttr_Purp($) 5734{ 5735 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5736 { 5737 if($Info=~/purp[ ]*:[ ]*@(\d+) /) { 5738 return $1; 5739 } 5740 } 5741 return ""; 5742} 5743 5744sub getTreeAttr_Op($) 5745{ 5746 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5747 { 5748 if($Info=~/op 0[ ]*:[ ]*@(\d+) /) { 5749 return $1; 5750 } 5751 } 5752 return ""; 5753} 5754 5755sub getTreeAttr_Valu($) 5756{ 5757 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5758 { 5759 if($Info=~/valu[ ]*:[ ]*@(\d+) /) { 5760 return $1; 5761 } 5762 } 5763 return ""; 5764} 5765 5766sub getTreeAttr_Flds($) 5767{ 5768 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5769 { 5770 if($Info=~/flds[ ]*:[ ]*@(\d+) /) { 5771 return $1; 5772 } 5773 } 5774 return ""; 5775} 5776 5777sub getTreeAttr_Binf($) 5778{ 5779 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5780 { 5781 if($Info=~/binf[ ]*:[ ]*@(\d+) /) { 5782 return $1; 5783 } 5784 } 5785 return ""; 5786} 5787 5788sub getTreeAttr_Args($) 5789{ 5790 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5791 { 5792 if($Info=~/args[ ]*:[ ]*@(\d+) /) { 5793 return $1; 5794 } 5795 } 5796 return ""; 5797} 5798 5799sub getTreeValue($) 5800{ 5801 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5802 { 5803 if($Info=~/low[ ]*:[ ]*([^ ]+) /) { 5804 return $1; 5805 } 5806 } 5807 return ""; 5808} 5809 5810sub getTreeAccess($) 5811{ 5812 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5813 { 5814 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /) 5815 { 5816 my $Access = $1; 5817 if($Access eq "prot") { 5818 return "protected"; 5819 } 5820 elsif($Access eq "priv") { 5821 return "private"; 5822 } 5823 } 5824 elsif($Info=~/ protected /) 5825 { # support for old GCC versions 5826 return "protected"; 5827 } 5828 elsif($Info=~/ private /) 5829 { # support for old GCC versions 5830 return "private"; 5831 } 5832 } 5833 return "public"; 5834} 5835 5836sub setFuncAccess($) 5837{ 5838 my $Access = getTreeAccess($_[0]); 5839 if($Access eq "protected") { 5840 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1; 5841 } 5842 elsif($Access eq "private") { 5843 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1; 5844 } 5845} 5846 5847sub setTypeAccess($$) 5848{ 5849 my ($TypeId, $TypeAttr) = @_; 5850 my $Access = getTreeAccess($TypeId); 5851 if($Access eq "protected") { 5852 $TypeAttr->{"Protected"} = 1; 5853 } 5854 elsif($Access eq "private") { 5855 $TypeAttr->{"Private"} = 1; 5856 } 5857} 5858 5859sub setFuncKind($) 5860{ 5861 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5862 { 5863 if($Info=~/pseudo tmpl/) { 5864 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1; 5865 } 5866 elsif($Info=~/ constructor /) { 5867 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1; 5868 } 5869 elsif($Info=~/ destructor /) { 5870 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1; 5871 } 5872 } 5873} 5874 5875sub getVirtSpec($) 5876{ 5877 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5878 { 5879 if($Info=~/spec[ ]*:[ ]*pure /) { 5880 return "PureVirt"; 5881 } 5882 elsif($Info=~/spec[ ]*:[ ]*virt /) { 5883 return "Virt"; 5884 } 5885 elsif($Info=~/ pure\s+virtual /) 5886 { # support for old GCC versions 5887 return "PureVirt"; 5888 } 5889 elsif($Info=~/ virtual /) 5890 { # support for old GCC versions 5891 return "Virt"; 5892 } 5893 } 5894 return ""; 5895} 5896 5897sub getFuncLink($) 5898{ 5899 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 5900 { 5901 if($Info=~/link[ ]*:[ ]*static /) { 5902 return "Static"; 5903 } 5904 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) { 5905 return $1; 5906 } 5907 } 5908 return ""; 5909} 5910 5911sub select_Symbol_NS($$) 5912{ 5913 my ($Symbol, $LibVersion) = @_; 5914 return "" if(not $Symbol or not $LibVersion); 5915 my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 5916 if(not $NS) 5917 { 5918 if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { 5919 $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"}; 5920 } 5921 } 5922 if($NS) 5923 { 5924 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5925 return $NS; 5926 } 5927 else 5928 { 5929 while($NS=~s/::[^:]+\Z//) 5930 { 5931 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5932 return $NS; 5933 } 5934 } 5935 } 5936 } 5937 5938 return ""; 5939} 5940 5941sub select_Type_NS($$) 5942{ 5943 my ($TypeName, $LibVersion) = @_; 5944 return "" if(not $TypeName or not $LibVersion); 5945 if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"}) 5946 { 5947 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5948 return $NS; 5949 } 5950 else 5951 { 5952 while($NS=~s/::[^:]+\Z//) 5953 { 5954 if(defined $NestedNameSpaces{$LibVersion}{$NS}) { 5955 return $NS; 5956 } 5957 } 5958 } 5959 } 5960 return ""; 5961} 5962 5963sub getNameSpace($) 5964{ 5965 my $InfoId = $_[0]; 5966 if(my $NSInfoId = getTreeAttr_Scpe($InfoId)) 5967 { 5968 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) 5969 { 5970 if($InfoType eq "namespace_decl") 5971 { 5972 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /) 5973 { 5974 my $NameSpace = getTreeStr($1); 5975 if($NameSpace eq "::") 5976 { # global namespace 5977 return ""; 5978 } 5979 if(my $BaseNameSpace = getNameSpace($NSInfoId)) { 5980 $NameSpace = $BaseNameSpace."::".$NameSpace; 5981 } 5982 $NestedNameSpaces{$Version}{$NameSpace} = 1; 5983 return $NameSpace; 5984 } 5985 else { 5986 return ""; 5987 } 5988 } 5989 elsif($InfoType ne "function_decl") 5990 { # inside data type 5991 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId); 5992 return $Name; 5993 } 5994 } 5995 } 5996 return ""; 5997} 5998 5999sub getEnumMembVal($) 6000{ 6001 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6002 { 6003 if($Info=~/valu[ ]*:[ ]*\@(\d+)/) 6004 { 6005 if(my $VInfo = $LibInfo{$Version}{"info"}{$1}) 6006 { 6007 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/) 6008 { # in newer versions of GCC the value is in the "const_decl->cnst" node 6009 return getTreeValue($1); 6010 } 6011 else 6012 { # some old versions of GCC (3.3) have the value in the "integer_cst" node 6013 return getTreeValue($1); 6014 } 6015 } 6016 } 6017 } 6018 return ""; 6019} 6020 6021sub getSize($) 6022{ 6023 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6024 { 6025 if($Info=~/size[ ]*:[ ]*\@(\d+)/) { 6026 return getTreeValue($1); 6027 } 6028 } 6029 return 0; 6030} 6031 6032sub getAlgn($) 6033{ 6034 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6035 { 6036 if($Info=~/algn[ ]*:[ ]*(\d+) /) { 6037 return $1; 6038 } 6039 } 6040 return ""; 6041} 6042 6043sub getBitField($) 6044{ 6045 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 6046 { 6047 if($Info=~/ bitfield /) { 6048 return getSize($_[0]); 6049 } 6050 } 6051 return 0; 6052} 6053 6054sub getNextElem($) 6055{ 6056 if(my $Chan = getTreeAttr_Chan($_[0])) { 6057 return $Chan; 6058 } 6059 elsif(my $Chain = getTreeAttr_Chain($_[0])) { 6060 return $Chain; 6061 } 6062 return ""; 6063} 6064 6065sub registerHeader($$) 6066{ # input: absolute path of header, relative path or name 6067 my ($Header, $LibVersion) = @_; 6068 if(not $Header) { 6069 return ""; 6070 } 6071 if(is_abs($Header) and not -f $Header) 6072 { # incorrect absolute path 6073 exitStatus("Access_Error", "can't access \'$Header\'"); 6074 } 6075 if(skipHeader($Header, $LibVersion)) 6076 { # skip 6077 return ""; 6078 } 6079 if(my $Header_Path = identifyHeader($Header, $LibVersion)) 6080 { 6081 detect_header_includes($Header_Path, $LibVersion); 6082 6083 if(defined $Tolerance and $Tolerance=~/3/) 6084 { # 3 - skip headers that include non-Linux headers 6085 if($OSgroup ne "windows") 6086 { 6087 foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}})) 6088 { 6089 if(specificHeader($Inc, "windows")) { 6090 return ""; 6091 } 6092 } 6093 } 6094 } 6095 6096 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path}) 6097 { # redirect 6098 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"} 6099 or skipHeader($RHeader_Path, $LibVersion)) 6100 { # skip 6101 return ""; 6102 } 6103 $Header_Path = $RHeader_Path; 6104 } 6105 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) 6106 { # skip 6107 return ""; 6108 } 6109 6110 if(my $HName = get_filename($Header_Path)) 6111 { # register 6112 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName; 6113 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1; 6114 } 6115 6116 if(($Header=~/\.(\w+)\Z/ and $1 ne "h") 6117 or $Header!~/\.(\w+)\Z/) 6118 { # hpp, hh, etc. 6119 setLanguage($LibVersion, "C++"); 6120 $CPP_HEADERS = 1; 6121 } 6122 6123 if($CheckHeadersOnly 6124 and $Header=~/(\A|\/)c\+\+(\/|\Z)/) 6125 { # /usr/include/c++/4.6.1/... 6126 $STDCXX_TESTING = 1; 6127 } 6128 6129 return $Header_Path; 6130 } 6131 return ""; 6132} 6133 6134sub registerDir($$$) 6135{ 6136 my ($Dir, $WithDeps, $LibVersion) = @_; 6137 $Dir=~s/[\/\\]+\Z//g; 6138 return if(not $LibVersion or not $Dir or not -d $Dir); 6139 $Dir = get_abs_path($Dir); 6140 6141 my $Mode = "All"; 6142 if($WithDeps) 6143 { 6144 if($RegisteredDirs{$LibVersion}{$Dir}{1}) { 6145 return; 6146 } 6147 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) { 6148 $Mode = "DepsOnly"; 6149 } 6150 } 6151 else 6152 { 6153 if($RegisteredDirs{$LibVersion}{$Dir}{1} 6154 or $RegisteredDirs{$LibVersion}{$Dir}{0}) { 6155 return; 6156 } 6157 } 6158 $Header_Dependency{$LibVersion}{$Dir} = 1; 6159 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1; 6160 if($Mode eq "DepsOnly") 6161 { 6162 foreach my $Path (cmd_find($Dir,"d")) { 6163 $Header_Dependency{$LibVersion}{$Path} = 1; 6164 } 6165 return; 6166 } 6167 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f")) 6168 { 6169 if($WithDeps) 6170 { 6171 my $SubDir = $Path; 6172 while(($SubDir = get_dirname($SubDir)) ne $Dir) 6173 { # register all sub directories 6174 $Header_Dependency{$LibVersion}{$SubDir} = 1; 6175 } 6176 } 6177 next if(is_not_header($Path)); 6178 next if(ignore_path($Path)); 6179 # Neighbors 6180 foreach my $Part (get_prefixes($Path)) { 6181 $Include_Neighbors{$LibVersion}{$Part} = $Path; 6182 } 6183 } 6184 if(get_filename($Dir) eq "include") 6185 { # search for "lib/include/" directory 6186 my $LibDir = $Dir; 6187 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) { 6188 registerDir($LibDir, $WithDeps, $LibVersion); 6189 } 6190 } 6191} 6192 6193sub parse_redirect($$$) 6194{ 6195 my ($Content, $Path, $LibVersion) = @_; 6196 my @Errors = (); 6197 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) { 6198 push(@Errors, $1); 6199 } 6200 my $Redirect = ""; 6201 foreach (@Errors) 6202 { 6203 s/\s{2,}/ /g; 6204 if(/(only|must\ include 6205 |update\ to\ include 6206 |replaced\ with 6207 |replaced\ by|renamed\ to 6208 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix) 6209 { 6210 $Redirect = $2; 6211 last; 6212 } 6213 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i) 6214 { 6215 $Redirect = $2; 6216 last; 6217 } 6218 elsif(/this\ header\ should\ not\ be\ used 6219 |programs\ should\ not\ directly\ include 6220 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header)) 6221 |is\ not\ supported\ API\ for\ general\ use 6222 |do\ not\ use 6223 |should\ not\ be\ (used|using) 6224 |cannot\ be\ included\ directly/ix and not /\ from\ /i) { 6225 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6226 } 6227 } 6228 if($Redirect) 6229 { 6230 $Redirect=~s/\A<//g; 6231 $Redirect=~s/>\Z//g; 6232 } 6233 return $Redirect; 6234} 6235 6236sub parse_includes($$) 6237{ 6238 my ($Content, $Path) = @_; 6239 my %Includes = (); 6240 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m) 6241 { # C/C++: include, Objective C/C++: import directive 6242 my $Header = $2; 6243 my $Method = substr($Header, 0, 1, ""); 6244 substr($Header, length($Header)-1, 1, ""); 6245 $Header = path_format($Header, $OSgroup); 6246 if($Method eq "\"" or is_abs($Header)) 6247 { 6248 if(-e join_P(get_dirname($Path), $Header)) 6249 { # relative path exists 6250 $Includes{$Header} = -1; 6251 } 6252 else 6253 { # include "..." that doesn't exist is equal to include <...> 6254 $Includes{$Header} = 2; 6255 } 6256 } 6257 else { 6258 $Includes{$Header} = 1; 6259 } 6260 } 6261 if($ExtraInfo) 6262 { 6263 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m) 6264 { # FT_FREETYPE_H 6265 $Includes{$2} = 0; 6266 } 6267 } 6268 return \%Includes; 6269} 6270 6271sub ignore_path($) 6272{ 6273 my $Path = $_[0]; 6274 if($Path=~/\~\Z/) 6275 {# skipping system backup files 6276 return 1; 6277 } 6278 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/) 6279 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories 6280 return 1; 6281 } 6282 return 0; 6283} 6284 6285sub sortByWord($$) 6286{ 6287 my ($ArrRef, $W) = @_; 6288 return if(length($W)<2); 6289 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef}; 6290} 6291 6292sub sortHeaders($$) 6293{ 6294 my ($H1, $H2) = @_; 6295 6296 $H1=~s/\.[a-z]+\Z//ig; 6297 $H2=~s/\.[a-z]+\Z//ig; 6298 6299 my $Hname1 = get_filename($H1); 6300 my $Hname2 = get_filename($H2); 6301 my $HDir1 = get_dirname($H1); 6302 my $HDir2 = get_dirname($H2); 6303 my $Dirname1 = get_filename($HDir1); 6304 my $Dirname2 = get_filename($HDir2); 6305 6306 $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6307 $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 6308 6309 if($_[0] eq $_[1] 6310 or $H1 eq $H2) { 6311 return 0; 6312 } 6313 elsif($H1=~/\A\Q$H2\E/) { 6314 return 1; 6315 } 6316 elsif($H2=~/\A\Q$H1\E/) { 6317 return -1; 6318 } 6319 elsif($HDir1=~/\Q$Hname1\E/i 6320 and $HDir2!~/\Q$Hname2\E/i) 6321 { # include/glib-2.0/glib.h 6322 return -1; 6323 } 6324 elsif($HDir2=~/\Q$Hname2\E/i 6325 and $HDir1!~/\Q$Hname1\E/i) 6326 { # include/glib-2.0/glib.h 6327 return 1; 6328 } 6329 elsif($Hname1=~/\Q$Dirname1\E/i 6330 and $Hname2!~/\Q$Dirname2\E/i) 6331 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6332 return -1; 6333 } 6334 elsif($Hname2=~/\Q$Dirname2\E/i 6335 and $Hname1!~/\Q$Dirname1\E/i) 6336 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 6337 return 1; 6338 } 6339 elsif($Hname1=~/(config|lib|util)/i 6340 and $Hname2!~/(config|lib|util)/i) 6341 { # include/alsa/asoundlib.h 6342 return -1; 6343 } 6344 elsif($Hname2=~/(config|lib|util)/i 6345 and $Hname1!~/(config|lib|util)/i) 6346 { # include/alsa/asoundlib.h 6347 return 1; 6348 } 6349 else 6350 { 6351 my $R1 = checkRelevance($H1); 6352 my $R2 = checkRelevance($H2); 6353 if($R1 and not $R2) 6354 { # libebook/e-book.h 6355 return -1; 6356 } 6357 elsif($R2 and not $R1) 6358 { # libebook/e-book.h 6359 return 1; 6360 } 6361 else 6362 { 6363 return (lc($H1) cmp lc($H2)); 6364 } 6365 } 6366} 6367 6368sub searchForHeaders($) 6369{ 6370 my $LibVersion = $_[0]; 6371 6372 # gcc standard include paths 6373 registerGccHeaders(); 6374 6375 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING) 6376 { # c++ standard include paths 6377 registerCppHeaders(); 6378 } 6379 6380 # processing header paths 6381 foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}}, 6382 @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) 6383 { 6384 my $IPath = $Path; 6385 if($SystemRoot) 6386 { 6387 if(is_abs($Path)) { 6388 $Path = $SystemRoot.$Path; 6389 } 6390 } 6391 if(not -e $Path) { 6392 exitStatus("Access_Error", "can't access \'$Path\'"); 6393 } 6394 elsif(-f $Path) { 6395 exitStatus("Access_Error", "\'$Path\' - not a directory"); 6396 } 6397 elsif(-d $Path) 6398 { 6399 $Path = get_abs_path($Path); 6400 registerDir($Path, 0, $LibVersion); 6401 if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) { 6402 push(@{$Add_Include_Paths{$LibVersion}}, $Path); 6403 } 6404 else { 6405 push(@{$Include_Paths{$LibVersion}}, $Path); 6406 } 6407 } 6408 } 6409 if(@{$Include_Paths{$LibVersion}}) { 6410 $INC_PATH_AUTODETECT{$LibVersion} = 0; 6411 } 6412 6413 # registering directories 6414 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6415 { 6416 next if(not -e $Path); 6417 $Path = get_abs_path($Path); 6418 $Path = path_format($Path, $OSgroup); 6419 if(-d $Path) { 6420 registerDir($Path, 1, $LibVersion); 6421 } 6422 elsif(-f $Path) 6423 { 6424 my $Dir = get_dirname($Path); 6425 if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}}) 6426 and not $LocalIncludes{$Dir}) 6427 { 6428 registerDir($Dir, 1, $LibVersion); 6429 # if(my $OutDir = get_dirname($Dir)) 6430 # { # registering the outer directory 6431 # if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}}) 6432 # and not $LocalIncludes{$OutDir}) { 6433 # registerDir($OutDir, 0, $LibVersion); 6434 # } 6435 # } 6436 } 6437 } 6438 } 6439 6440 # clean memory 6441 %RegisteredDirs = (); 6442 6443 # registering headers 6444 my $Position = 0; 6445 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) 6446 { 6447 if(is_abs($Dest) and not -e $Dest) { 6448 exitStatus("Access_Error", "can't access \'$Dest\'"); 6449 } 6450 $Dest = path_format($Dest, $OSgroup); 6451 if(is_header($Dest, 1, $LibVersion)) 6452 { 6453 if(my $HPath = registerHeader($Dest, $LibVersion)) { 6454 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++; 6455 } 6456 } 6457 elsif(-d $Dest) 6458 { 6459 my @Registered = (); 6460 foreach my $Path (cmd_find($Dest,"f")) 6461 { 6462 next if(ignore_path($Path)); 6463 next if(not is_header($Path, 0, $LibVersion)); 6464 if(my $HPath = registerHeader($Path, $LibVersion)) { 6465 push(@Registered, $HPath); 6466 } 6467 } 6468 @Registered = sort {sortHeaders($a, $b)} @Registered; 6469 sortByWord(\@Registered, $TargetLibraryShortName); 6470 foreach my $Path (@Registered) { 6471 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++; 6472 } 6473 } 6474 else { 6475 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file"); 6476 } 6477 } 6478 6479 if(defined $Tolerance and $Tolerance=~/4/) 6480 { # 4 - skip headers included by others 6481 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 6482 { 6483 if(defined $Header_Includes_R{$LibVersion}{$Path}) { 6484 delete($Registered_Headers{$LibVersion}{$Path}); 6485 } 6486 } 6487 } 6488 6489 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"}) 6490 { # preparing preamble headers 6491 foreach my $Header (split(/\s*\n\s*/, $HList)) 6492 { 6493 if(is_abs($Header) and not -f $Header) { 6494 exitStatus("Access_Error", "can't access file \'$Header\'"); 6495 } 6496 $Header = path_format($Header, $OSgroup); 6497 if(my $Header_Path = is_header($Header, 1, $LibVersion)) 6498 { 6499 next if(skipHeader($Header_Path, $LibVersion)); 6500 push_U($Include_Preamble{$LibVersion}, $Header_Path); 6501 } 6502 else { 6503 exitStatus("Access_Error", "can't identify \'$Header\' as a header file"); 6504 } 6505 } 6506 } 6507 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}})) 6508 { # set relative paths (for duplicates) 6509 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2) 6510 { # search for duplicates 6511 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0]; 6512 my $Prefix = get_dirname($FirstPath); 6513 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/) 6514 { # detect a shortest distinguishing prefix 6515 my $NewPrefix = $1; 6516 my %Identity = (); 6517 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6518 { 6519 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) { 6520 $Identity{$Path} = $1; 6521 } 6522 } 6523 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) 6524 { # all names are different with current prefix 6525 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { 6526 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path}; 6527 } 6528 last; 6529 } 6530 $Prefix = $NewPrefix; # increase prefix 6531 } 6532 } 6533 } 6534 6535 # clean memory 6536 %HeaderName_Paths = (); 6537 6538 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}})) 6539 { # ordering headers according to descriptor 6540 my $PairName = $Include_Order{$LibVersion}{$HeaderName}; 6541 my ($Pos, $PairPos) = (-1, -1); 6542 my ($Path, $PairPath) = (); 6543 my @Paths = keys(%{$Registered_Headers{$LibVersion}}); 6544 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths; 6545 foreach my $Header_Path (@Paths) 6546 { 6547 if(get_filename($Header_Path) eq $PairName) 6548 { 6549 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6550 $PairPath = $Header_Path; 6551 } 6552 if(get_filename($Header_Path) eq $HeaderName) 6553 { 6554 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; 6555 $Path = $Header_Path; 6556 } 6557 } 6558 if($PairPos!=-1 and $Pos!=-1 6559 and int($PairPos)<int($Pos)) 6560 { 6561 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}}; 6562 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}}; 6563 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp; 6564 } 6565 } 6566 if(not keys(%{$Registered_Headers{$LibVersion}})) { 6567 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"}); 6568 } 6569} 6570 6571sub detect_real_includes($$) 6572{ 6573 my ($AbsPath, $LibVersion) = @_; 6574 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath); 6575 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath} 6576 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6577 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6578 } 6579 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1; 6580 6581 my $Path = callPreprocessor($AbsPath, "", $LibVersion); 6582 return () if(not $Path); 6583 open(PREPROC, $Path); 6584 while(<PREPROC>) 6585 { 6586 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/) 6587 { 6588 my $Include = path_format($1, $OSgroup); 6589 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) { 6590 next; 6591 } 6592 if($Include eq $AbsPath) { 6593 next; 6594 } 6595 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1; 6596 } 6597 } 6598 close(PREPROC); 6599 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6600} 6601 6602sub detect_header_includes($$) 6603{ 6604 my ($Path, $LibVersion) = @_; 6605 return if(not $LibVersion or not $Path); 6606 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) { 6607 return; 6608 } 6609 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1; 6610 6611 if(not -e $Path) { 6612 return; 6613 } 6614 6615 my $Content = readFile($Path); 6616 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion)) 6617 { # detect error directive in headers 6618 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion)) 6619 { 6620 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) { 6621 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion); 6622 } 6623 if($RedirectPath ne $Path) { 6624 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath; 6625 } 6626 } 6627 else 6628 { # can't find 6629 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; 6630 } 6631 } 6632 if(my $Inc = parse_includes($Content, $Path)) 6633 { 6634 foreach my $Include (keys(%{$Inc})) 6635 { # detect includes 6636 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include}; 6637 6638 if(defined $Tolerance and $Tolerance=~/4/) 6639 { 6640 if(my $HPath = identifyHeader($Include, $LibVersion)) 6641 { 6642 $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1; 6643 } 6644 } 6645 } 6646 } 6647} 6648 6649sub fromLibc($) 6650{ # system GLIBC header 6651 my $Path = $_[0]; 6652 my ($Dir, $Name) = separate_path($Path); 6653 if($OStarget eq "symbian") 6654 { 6655 if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name}) 6656 { # epoc32/include/libc/{stdio, ...}.h 6657 return 1; 6658 } 6659 } 6660 else 6661 { 6662 if($Dir eq "/usr/include" and $GlibcHeader{$Name}) 6663 { # /usr/include/{stdio, ...}.h 6664 return 1; 6665 } 6666 } 6667 return 0; 6668} 6669 6670sub isLibcDir($) 6671{ # system GLIBC directory 6672 my $Dir = $_[0]; 6673 my ($OutDir, $Name) = separate_path($Dir); 6674 if($OStarget eq "symbian") 6675 { 6676 if(get_filename($OutDir) eq "libc" 6677 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6678 { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h 6679 return 1; 6680 } 6681 } 6682 else 6683 { # linux 6684 if($OutDir eq "/usr/include" 6685 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 6686 { # /usr/include/{sys,bits,asm,asm-*}/*.h 6687 return 1; 6688 } 6689 } 6690 return 0; 6691} 6692 6693sub detect_recursive_includes($$) 6694{ 6695 my ($AbsPath, $LibVersion) = @_; 6696 return () if(not $AbsPath); 6697 if(isCyclical(\@RecurInclude, $AbsPath)) { 6698 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6699 } 6700 my ($AbsDir, $Name) = separate_path($AbsPath); 6701 if(isLibcDir($AbsDir)) 6702 { # system GLIBC internals 6703 return () if(not $ExtraInfo); 6704 } 6705 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { 6706 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6707 } 6708 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i); 6709 6710 if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING) 6711 { # skip /usr/include/c++/*/ headers 6712 return () if(not $ExtraInfo); 6713 } 6714 6715 push(@RecurInclude, $AbsPath); 6716 if(grep { $AbsDir eq $_ } @DefaultGccPaths 6717 or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath))) 6718 { # check "real" (non-"model") include paths 6719 my @Paths = detect_real_includes($AbsPath, $LibVersion); 6720 pop(@RecurInclude); 6721 return @Paths; 6722 } 6723 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) { 6724 detect_header_includes($AbsPath, $LibVersion); 6725 } 6726 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) 6727 { 6728 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include}; 6729 my $HPath = ""; 6730 if($IncType<0) 6731 { # for #include "..." 6732 my $Candidate = join_P($AbsDir, $Include); 6733 if(-f $Candidate) { 6734 $HPath = realpath($Candidate); 6735 } 6736 } 6737 elsif($IncType>0 6738 and $Include=~/[\/\\]/) # and not find_in_defaults($Include) 6739 { # search for the nearest header 6740 # QtCore/qabstractanimation.h includes <QtCore/qobject.h> 6741 my $Candidate = join_P(get_dirname($AbsDir), $Include); 6742 if(-f $Candidate) { 6743 $HPath = $Candidate; 6744 } 6745 } 6746 if(not $HPath) { 6747 $HPath = identifyHeader($Include, $LibVersion); 6748 } 6749 next if(not $HPath); 6750 if($HPath eq $AbsPath) { 6751 next; 6752 } 6753 6754 if($Debug) 6755 { # boundary headers 6756# if($HPath=~/vtk/ and $AbsPath!~/vtk/) 6757# { 6758# print STDERR "$AbsPath -> $HPath\n"; 6759# } 6760 } 6761 6762 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType; 6763 if($IncType>0) 6764 { # only include <...>, skip include "..." prefixes 6765 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1; 6766 } 6767 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion)) 6768 { 6769 if($IncPath eq $AbsPath) { 6770 next; 6771 } 6772 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath}; 6773 if($RIncType==-1) 6774 { # include "..." 6775 $RIncType = $IncType; 6776 } 6777 elsif($RIncType==2) 6778 { 6779 if($IncType!=-1) { 6780 $RIncType = $IncType; 6781 } 6782 } 6783 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType; 6784 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) { 6785 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1; 6786 } 6787 } 6788 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}})) 6789 { 6790 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2 6791 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}) 6792 { # distinguish math.h from glibc and math.h from the tested library 6793 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}); 6794 last; 6795 } 6796 } 6797 } 6798 pop(@RecurInclude); 6799 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); 6800} 6801 6802sub find_in_framework($$$) 6803{ 6804 my ($Header, $Framework, $LibVersion) = @_; 6805 return "" if(not $Header or not $Framework or not $LibVersion); 6806 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) { 6807 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}; 6808 } 6809 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}})) 6810 { 6811 if(get_filename($Dependency) eq $Framework 6812 and -f get_dirname($Dependency)."/".$Header) { 6813 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency)); 6814 } 6815 } 6816 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = ""); 6817} 6818 6819sub find_in_defaults($) 6820{ 6821 my $Header = $_[0]; 6822 return "" if(not $Header); 6823 if(defined $Cache{"find_in_defaults"}{$Header}) { 6824 return $Cache{"find_in_defaults"}{$Header}; 6825 } 6826 foreach my $Dir (@DefaultIncPaths, 6827 @DefaultGccPaths, 6828 @DefaultCppPaths, 6829 @UsersIncPath) 6830 { 6831 next if(not $Dir); 6832 if(-f $Dir."/".$Header) { 6833 return ($Cache{"find_in_defaults"}{$Header}=$Dir); 6834 } 6835 } 6836 return ($Cache{"find_in_defaults"}{$Header}=""); 6837} 6838 6839sub cmp_paths($$) 6840{ 6841 my ($Path1, $Path2) = @_; 6842 my @Parts1 = split(/[\/\\]/, $Path1); 6843 my @Parts2 = split(/[\/\\]/, $Path2); 6844 foreach my $Num (0 .. $#Parts1) 6845 { 6846 my $Part1 = $Parts1[$Num]; 6847 my $Part2 = $Parts2[$Num]; 6848 if($GlibcDir{$Part1} 6849 and not $GlibcDir{$Part2}) { 6850 return 1; 6851 } 6852 elsif($GlibcDir{$Part2} 6853 and not $GlibcDir{$Part1}) { 6854 return -1; 6855 } 6856 elsif($Part1=~/glib/ 6857 and $Part2!~/glib/) { 6858 return 1; 6859 } 6860 elsif($Part1!~/glib/ 6861 and $Part2=~/glib/) { 6862 return -1; 6863 } 6864 elsif(my $CmpRes = ($Part1 cmp $Part2)) { 6865 return $CmpRes; 6866 } 6867 } 6868 return 0; 6869} 6870 6871sub checkRelevance($) 6872{ 6873 my $Path = $_[0]; 6874 return 0 if(not $Path); 6875 6876 if($SystemRoot) { 6877 $Path = cut_path_prefix($Path, $SystemRoot); 6878 } 6879 6880 my $Name = lc(get_filename($Path)); 6881 my $Dir = lc(get_dirname($Path)); 6882 6883 $Name=~s/\.\w+\Z//g; # remove extension (.h) 6884 6885 foreach my $Token (split(/[_\d\W]+/, $Name)) 6886 { 6887 my $Len = length($Token); 6888 next if($Len<=1); 6889 if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/) 6890 { # include/evolution-data-server-1.4/libebook/e-book.h 6891 return 1; 6892 } 6893 if($Len>=4 and index($Dir, $Token)!=-1) 6894 { # include/gupnp-1.0/libgupnp/gupnp-context.h 6895 return 1; 6896 } 6897 } 6898 return 0; 6899} 6900 6901sub checkFamily(@) 6902{ 6903 my @Paths = @_; 6904 return 1 if($#Paths<=0); 6905 my %Prefix = (); 6906 foreach my $Path (@Paths) 6907 { 6908 if($SystemRoot) { 6909 $Path = cut_path_prefix($Path, $SystemRoot); 6910 } 6911 if(my $Dir = get_dirname($Path)) 6912 { 6913 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix 6914 $Prefix{$Dir} += 1; 6915 $Prefix{get_dirname($Dir)} += 1; 6916 } 6917 } 6918 foreach (sort keys(%Prefix)) 6919 { 6920 if(get_depth($_)>=3 6921 and $Prefix{$_}==$#Paths+1) { 6922 return 1; 6923 } 6924 } 6925 return 0; 6926} 6927 6928sub isAcceptable($$$) 6929{ 6930 my ($Header, $Candidate, $LibVersion) = @_; 6931 my $HName = get_filename($Header); 6932 if(get_dirname($Header)) 6933 { # with prefix 6934 return 1; 6935 } 6936 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/) 6937 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/ 6938 return 1; 6939 } 6940 if(checkRelevance($Candidate)) 6941 { # allow to search for atk.h in /usr/include/atk-1.0/atk/ 6942 return 1; 6943 } 6944 if(checkFamily(getSystemHeaders($HName, $LibVersion))) 6945 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h 6946 # /usr/include/qt4/Qt/qsslconfiguration.h 6947 return 1; 6948 } 6949 if($OStarget eq "symbian") 6950 { 6951 if($Candidate=~/[\/\\]stdapis[\/\\]/) { 6952 return 1; 6953 } 6954 } 6955 return 0; 6956} 6957 6958sub isRelevant($$$) 6959{ # disallow to search for "abstract" headers in too deep directories 6960 my ($Header, $Candidate, $LibVersion) = @_; 6961 my $HName = get_filename($Header); 6962 if($OStarget eq "symbian") 6963 { 6964 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) { 6965 return 0; 6966 } 6967 } 6968 if($OStarget ne "bsd") 6969 { 6970 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/) 6971 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h 6972 return 0; 6973 } 6974 } 6975 if($OStarget ne "windows") 6976 { 6977 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/) 6978 { # skip /usr/include/wine/msvcrt 6979 return 0; 6980 } 6981 } 6982 if(not get_dirname($Header) 6983 and $Candidate=~/[\/\\]wx[\/\\]/) 6984 { # do NOT search in system /wx/ directory 6985 # for headers without a prefix: sstream.h 6986 return 0; 6987 } 6988 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR 6989 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/) 6990 { # skip ../c++/3.3.3/ if using ../c++/4.5/ 6991 return 0; 6992 } 6993 if($Candidate=~/[\/\\]asm-/ 6994 and (my $Arch = getArch($LibVersion)) ne "unknown") 6995 { # arch-specific header files 6996 if($Candidate!~/[\/\\]asm-\Q$Arch\E/) 6997 {# skip ../asm-arm/ if using x86 architecture 6998 return 0; 6999 } 7000 } 7001 my @Candidates = getSystemHeaders($HName, $LibVersion); 7002 if($#Candidates==1) 7003 { # unique header 7004 return 1; 7005 } 7006 my @SCandidates = getSystemHeaders($Header, $LibVersion); 7007 if($#SCandidates==1) 7008 { # unique name 7009 return 1; 7010 } 7011 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0; 7012 if(get_depth($Candidate)-$SystemDepth>=5) 7013 { # abstract headers in too deep directories 7014 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/ 7015 if(not isAcceptable($Header, $Candidate, $LibVersion)) { 7016 return 0; 7017 } 7018 } 7019 if($Header eq "parser.h" 7020 and $Candidate!~/\/libxml2\//) 7021 { # select parser.h from xml2 library 7022 return 0; 7023 } 7024 if(not get_dirname($Header) 7025 and keys(%{$SystemHeaders{$HName}})>=3) 7026 { # many headers with the same name 7027 # like thread.h included without a prefix 7028 if(not checkFamily(@Candidates)) { 7029 return 0; 7030 } 7031 } 7032 return 1; 7033} 7034 7035sub selectSystemHeader($$) 7036{ # cache function 7037 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) { 7038 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}; 7039 } 7040 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_)); 7041} 7042 7043sub selectSystemHeader_I($$) 7044{ 7045 my ($Header, $LibVersion) = @_; 7046 if(-f $Header) { 7047 return $Header; 7048 } 7049 if(is_abs($Header) and not -f $Header) 7050 { # incorrect absolute path 7051 return ""; 7052 } 7053 if(defined $ConfHeaders{lc($Header)}) 7054 { # too abstract configuration headers 7055 return ""; 7056 } 7057 my $HName = get_filename($Header); 7058 if($OSgroup ne "windows") 7059 { 7060 if(defined $WinHeaders{lc($HName)} 7061 or $HName=~/windows|win32|win64/i) 7062 { # windows headers 7063 return ""; 7064 } 7065 } 7066 if($OSgroup ne "macos") 7067 { 7068 if($HName eq "fp.h") 7069 { # pngconf.h includes fp.h in Mac OS 7070 return ""; 7071 } 7072 } 7073 7074 if(defined $ObsoleteHeaders{$HName}) 7075 { # obsolete headers 7076 return ""; 7077 } 7078 if($OSgroup eq "linux" or $OSgroup eq "bsd") 7079 { 7080 if(defined $AlienHeaders{$HName} 7081 or defined $AlienHeaders{$Header}) 7082 { # alien headers from other systems 7083 return ""; 7084 } 7085 } 7086 7087 foreach my $Path (@{$SystemPaths{"include"}}) 7088 { # search in default paths 7089 if(-f $Path."/".$Header) { 7090 return join_P($Path,$Header); 7091 } 7092 } 7093 if(not defined $Cache{"checkSystemFiles"}) 7094 { # register all headers in system include dirs 7095 checkSystemFiles(); 7096 } 7097 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)} 7098 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion)) 7099 { 7100 if(isRelevant($Header, $Candidate, $LibVersion)) { 7101 return $Candidate; 7102 } 7103 } 7104 # error 7105 return ""; 7106} 7107 7108sub getSystemHeaders($$) 7109{ 7110 my ($Header, $LibVersion) = @_; 7111 my @Candidates = (); 7112 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}})) 7113 { 7114 if(skipHeader($Candidate, $LibVersion)) { 7115 next; 7116 } 7117 push(@Candidates, $Candidate); 7118 } 7119 return @Candidates; 7120} 7121 7122sub cut_path_prefix($$) 7123{ 7124 my ($Path, $Prefix) = @_; 7125 return $Path if(not $Prefix); 7126 $Prefix=~s/[\/\\]+\Z//; 7127 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//; 7128 return $Path; 7129} 7130 7131sub is_default_include_dir($) 7132{ 7133 my $Dir = $_[0]; 7134 $Dir=~s/[\/\\]+\Z//; 7135 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths); 7136} 7137 7138sub identifyHeader($$) 7139{ # cache function 7140 my ($Header, $LibVersion) = @_; 7141 if(not $Header) { 7142 return ""; 7143 } 7144 $Header=~s/\A(\.\.[\\\/])+//g; 7145 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) { 7146 return $Cache{"identifyHeader"}{$LibVersion}{$Header}; 7147 } 7148 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion)); 7149} 7150 7151sub identifyHeader_I($$) 7152{ # search for header by absolute path, relative path or name 7153 my ($Header, $LibVersion) = @_; 7154 if(-f $Header) 7155 { # it's relative or absolute path 7156 return get_abs_path($Header); 7157 } 7158 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING 7159 and my $HeaderDir = find_in_defaults($Header)) 7160 { # search for libc headers in the /usr/include 7161 # for non-libc target library before searching 7162 # in the library paths 7163 return join_P($HeaderDir,$Header); 7164 } 7165 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header}) 7166 { # search in the target library paths 7167 return $Path; 7168 } 7169 elsif(defined $DefaultGccHeader{$Header}) 7170 { # search in the internal GCC include paths 7171 return $DefaultGccHeader{$Header}; 7172 } 7173 elsif(my $DefaultDir = find_in_defaults($Header)) 7174 { # search in the default GCC include paths 7175 return join_P($DefaultDir,$Header); 7176 } 7177 elsif(defined $DefaultCppHeader{$Header}) 7178 { # search in the default G++ include paths 7179 return $DefaultCppHeader{$Header}; 7180 } 7181 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion)) 7182 { # search everywhere in the system 7183 return $AnyPath; 7184 } 7185 elsif($OSgroup eq "macos") 7186 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h" 7187 if(my $Dir = get_dirname($Header)) 7188 { 7189 my $RelPath = "Headers\/".get_filename($Header); 7190 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) { 7191 return join_P($HeaderDir, $RelPath); 7192 } 7193 } 7194 } 7195 # cannot find anything 7196 return ""; 7197} 7198 7199sub getLocation($) 7200{ 7201 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7202 { 7203 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) { 7204 return (path_format($1, $OSgroup), $2); 7205 } 7206 } 7207 return (); 7208} 7209 7210sub getNameByInfo($) 7211{ 7212 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7213 { 7214 if($Info=~/name[ ]*:[ ]*@(\d+) /) 7215 { 7216 if(my $NInfo = $LibInfo{$Version}{"info"}{$1}) 7217 { 7218 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/) 7219 { # short unsigned int (may include spaces) 7220 my $Str = $1; 7221 if($CppMode{$Version} 7222 and $Str=~/\Ac99_(.+)\Z/) 7223 { 7224 if($CppKeywords_A{$1}) { 7225 $Str=$1; 7226 } 7227 } 7228 return $Str; 7229 } 7230 } 7231 } 7232 } 7233 return ""; 7234} 7235 7236sub getTreeStr($) 7237{ 7238 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7239 { 7240 if($Info=~/strg[ ]*:[ ]*([^ ]*)/) 7241 { 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 return ""; 7254} 7255 7256sub getFuncShortName($) 7257{ 7258 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7259 { 7260 if(index($Info, " operator ")!=-1) 7261 { 7262 if(index($Info, " conversion ")!=-1) 7263 { 7264 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"}) 7265 { 7266 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) { 7267 return "operator ".$RName; 7268 } 7269 } 7270 } 7271 else 7272 { 7273 if($Info=~/ operator[ ]+([a-zA-Z]+) /) 7274 { 7275 if(my $Ind = $Operator_Indication{$1}) { 7276 return "operator".$Ind; 7277 } 7278 elsif(not $UnknownOperator{$1}) 7279 { 7280 printMsg("WARNING", "unknown operator $1"); 7281 $UnknownOperator{$1} = 1; 7282 } 7283 } 7284 } 7285 } 7286 else 7287 { 7288 if($Info=~/name[ ]*:[ ]*@(\d+) /) { 7289 return getTreeStr($1); 7290 } 7291 } 7292 } 7293 return ""; 7294} 7295 7296sub getFuncReturn($) 7297{ 7298 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7299 { 7300 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7301 { 7302 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) { 7303 return $1; 7304 } 7305 } 7306 } 7307 return ""; 7308} 7309 7310sub getFuncOrig($) 7311{ 7312 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7313 { 7314 if($Info=~/orig[ ]*:[ ]*@(\d+) /) { 7315 return $1; 7316 } 7317 } 7318 return $_[0]; 7319} 7320 7321sub unmangleArray(@) 7322{ 7323 if($_[0]=~/\A\?/) 7324 { # MSVC mangling 7325 my $UndNameCmd = get_CmdPath("undname"); 7326 if(not $UndNameCmd) { 7327 exitStatus("Not_Found", "can't find \"undname\""); 7328 } 7329 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7330 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`); 7331 } 7332 else 7333 { # GCC mangling 7334 my $CppFiltCmd = get_CmdPath("c++filt"); 7335 if(not $CppFiltCmd) { 7336 exitStatus("Not_Found", "can't find c++filt in PATH"); 7337 } 7338 if(not defined $CPPFILT_SUPPORT_FILE) 7339 { 7340 my $Info = `$CppFiltCmd -h 2>&1`; 7341 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/; 7342 } 7343 my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":""; 7344 if($CPPFILT_SUPPORT_FILE) 7345 { # new versions of c++filt can take a file 7346 if($#_>$MAX_CPPFILT_FILE_SIZE) 7347 { # c++filt <= 2.22 may crash on large files (larger than 8mb) 7348 # this is fixed in the oncoming version of Binutils 7349 my @Half = splice(@_, 0, ($#_+1)/2); 7350 return (unmangleArray(@Half), unmangleArray(@_)) 7351 } 7352 else 7353 { 7354 writeFile("$TMP_DIR/unmangle", join("\n", @_)); 7355 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`; 7356 if($?==139) 7357 { # segmentation fault 7358 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant"); 7359 } 7360 return split(/\n/, $Res); 7361 } 7362 } 7363 else 7364 { # old-style unmangling 7365 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) 7366 { 7367 my @Half = splice(@_, 0, ($#_+1)/2); 7368 return (unmangleArray(@Half), unmangleArray(@_)) 7369 } 7370 else 7371 { 7372 my $Strings = join(" ", @_); 7373 my $Res = `$CppFiltCmd $NoStrip $Strings`; 7374 if($?==139) 7375 { # segmentation fault 7376 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant"); 7377 } 7378 return split(/\n/, $Res); 7379 } 7380 } 7381 } 7382} 7383 7384sub get_ChargeLevel($$) 7385{ 7386 my ($Symbol, $LibVersion) = @_; 7387 return "" if($Symbol!~/\A(_Z|\?)/); 7388 if(defined $CompleteSignature{$LibVersion}{$Symbol} 7389 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) 7390 { 7391 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}) 7392 { 7393 if($Symbol=~/C1[EI]/) { 7394 return "[in-charge]"; 7395 } 7396 elsif($Symbol=~/C2[EI]/) { 7397 return "[not-in-charge]"; 7398 } 7399 } 7400 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) 7401 { 7402 if($Symbol=~/D1[EI]/) { 7403 return "[in-charge]"; 7404 } 7405 elsif($Symbol=~/D2[EI]/) { 7406 return "[not-in-charge]"; 7407 } 7408 elsif($Symbol=~/D0[EI]/) { 7409 return "[in-charge-deleting]"; 7410 } 7411 } 7412 } 7413 else 7414 { 7415 if($Symbol=~/C1[EI]/) { 7416 return "[in-charge]"; 7417 } 7418 elsif($Symbol=~/C2[EI]/) { 7419 return "[not-in-charge]"; 7420 } 7421 elsif($Symbol=~/D1[EI]/) { 7422 return "[in-charge]"; 7423 } 7424 elsif($Symbol=~/D2[EI]/) { 7425 return "[not-in-charge]"; 7426 } 7427 elsif($Symbol=~/D0[EI]/) { 7428 return "[in-charge-deleting]"; 7429 } 7430 } 7431 return ""; 7432} 7433 7434sub get_Signature_M($$) 7435{ 7436 my ($Symbol, $LibVersion) = @_; 7437 my $Signature_M = $tr_name{$Symbol}; 7438 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 7439 { # add return type name 7440 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M; 7441 } 7442 return $Signature_M; 7443} 7444 7445sub get_Signature($$) 7446{ 7447 my ($Symbol, $LibVersion) = @_; 7448 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) { 7449 return $Cache{"get_Signature"}{$LibVersion}{$Symbol}; 7450 } 7451 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 7452 my ($Signature, @Param_Types_FromUnmangledName) = (); 7453 7454 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 7455 7456 if($Symbol=~/\A(_Z|\?)/) 7457 { 7458 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 7459 { 7460 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 7461 $ClassName=~s/\bstruct //g; 7462 7463 if(index($Symbol, "_ZTV")==0) { 7464 return "vtable for $ClassName [data]"; 7465 } 7466 7467 $Signature .= $ClassName."::"; 7468 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { 7469 $Signature .= "~"; 7470 } 7471 $Signature .= $ShortName; 7472 } 7473 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) { 7474 $Signature .= $NameSpace."::".$ShortName; 7475 } 7476 else { 7477 $Signature .= $ShortName; 7478 } 7479 my ($Short, $Params) = split_Signature($tr_name{$MnglName}); 7480 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1); 7481 } 7482 else 7483 { 7484 $Signature .= $MnglName; 7485 } 7486 my @ParamArray = (); 7487 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 7488 { 7489 if($Pos eq "") { 7490 next; 7491 } 7492 7493 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}; 7494 if(not $ParamTypeId) { 7495 next; 7496 } 7497 7498 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"}; 7499 if(not $ParamTypeName) { 7500 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos]; 7501 } 7502 foreach my $Typedef (keys(%ChangedTypedef)) 7503 { 7504 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 7505 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g; 7506 } 7507 } 7508 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) 7509 { 7510 if($ParamName eq "this" 7511 and $Symbol=~/\A(_Z|\?)/) 7512 { # do NOT show first hidded "this"-parameter 7513 next; 7514 } 7515 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName)); 7516 } 7517 else { 7518 push(@ParamArray, $ParamTypeName); 7519 } 7520 } 7521 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"} 7522 or $GlobalDataObject{$LibVersion}{$Symbol}) { 7523 $Signature .= " [data]"; 7524 } 7525 else 7526 { 7527 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) 7528 { # add [in-charge] 7529 $Signature .= " ".$ChargeLevel; 7530 } 7531 $Signature .= " (".join(", ", @ParamArray).")"; 7532 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"} 7533 or $Symbol=~/\A_ZN(V|)K/) { 7534 $Signature .= " const"; 7535 } 7536 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"} 7537 or $Symbol=~/\A_ZN(K|)V/) { 7538 $Signature .= " volatile"; 7539 } 7540 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"} 7541 and $Symbol=~/\A(_Z|\?)/) 7542 { # for static methods 7543 $Signature .= " [static]"; 7544 } 7545 } 7546 if(defined $ShowRetVal 7547 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { 7548 $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"}; 7549 } 7550 if($SymbolVersion) { 7551 $Signature .= $VersionSpec.$SymbolVersion; 7552 } 7553 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature); 7554} 7555 7556sub create_member_decl($$) 7557{ 7558 my ($TName, $Member) = @_; 7559 if($TName=~/\([\*]+\)/) 7560 { 7561 $TName=~s/\(([\*]+)\)/\($1$Member\)/; 7562 return $TName; 7563 } 7564 else 7565 { 7566 my @ArraySizes = (); 7567 while($TName=~s/(\[[^\[\]]*\])\Z//) { 7568 push(@ArraySizes, $1); 7569 } 7570 return $TName." ".$Member.join("", @ArraySizes); 7571 } 7572} 7573 7574sub getFuncType($) 7575{ 7576 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7577 { 7578 if($Info=~/type[ ]*:[ ]*@(\d+) /) 7579 { 7580 if(my $Type = $LibInfo{$Version}{"info_type"}{$1}) 7581 { 7582 if($Type eq "method_type") { 7583 return "Method"; 7584 } 7585 elsif($Type eq "function_type") { 7586 return "Function"; 7587 } 7588 else { 7589 return "Other"; 7590 } 7591 } 7592 } 7593 } 7594 return ""; 7595} 7596 7597sub getFuncTypeId($) 7598{ 7599 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) 7600 { 7601 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) { 7602 return $1; 7603 } 7604 } 7605 return 0; 7606} 7607 7608sub isAnon($) 7609{ # "._N" or "$_N" in older GCC versions 7610 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/); 7611} 7612 7613sub formatName($$) 7614{ # type name correction 7615 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) { 7616 return $Cache{"formatName"}{$_[1]}{$_[0]}; 7617 } 7618 7619 my $N = $_[0]; 7620 7621 if($_[1] ne "S") 7622 { 7623 $N=~s/\A[ ]+//g; 7624 $N=~s/[ ]+\Z//g; 7625 $N=~s/[ ]{2,}/ /g; 7626 } 7627 7628 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const 7629 7630 $N=~s/\b(const|volatile) ([\w\:]+)([\*&,>]|\Z)/$2 $1$3/g; # "const void" to "void const" 7631 7632 $N=~s/\bvolatile const\b/const volatile/g; 7633 7634 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g; 7635 $N=~s/\b(short|long) int\b/$1/g; 7636 7637 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g; 7638 7639 while($N=~s/>>/> >/g) {}; 7640 7641 if($_[1] eq "S") 7642 { 7643 if(index($N, "operator")!=-1) { 7644 $N=~s/\b(operator[ ]*)> >/$1>>/; 7645 } 7646 } 7647 7648 $N=~s/,([^ ])/, $1/g; 7649 7650 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N); 7651} 7652 7653sub get_HeaderDeps($$) 7654{ 7655 my ($AbsPath, $LibVersion) = @_; 7656 return () if(not $AbsPath or not $LibVersion); 7657 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) { 7658 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7659 } 7660 my %IncDir = (); 7661 detect_recursive_includes($AbsPath, $LibVersion); 7662 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) 7663 { 7664 next if(not $HeaderPath); 7665 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/); 7666 my $Dir = get_dirname($HeaderPath); 7667 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}})) 7668 { 7669 my $Dep = $Dir; 7670 if($Prefix) 7671 { 7672 if($OSgroup eq "windows") 7673 { # case insensitive seach on windows 7674 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) { 7675 next; 7676 } 7677 } 7678 elsif($OSgroup eq "macos") 7679 { # seach in frameworks 7680 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7681 { 7682 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/) 7683 {# frameworks 7684 my ($HFramework, $HName) = ($1, $2); 7685 $Dep = $HFramework; 7686 } 7687 else 7688 {# mismatch 7689 next; 7690 } 7691 } 7692 } 7693 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 7694 { # Linux, FreeBSD 7695 next; 7696 } 7697 } 7698 if(not $Dep) 7699 { # nothing to include 7700 next; 7701 } 7702 if(is_default_include_dir($Dep)) 7703 { # included by the compiler 7704 next; 7705 } 7706 if(get_depth($Dep)==1) 7707 { # too short 7708 next; 7709 } 7710 if(isLibcDir($Dep)) 7711 { # do NOT include /usr/include/{sys,bits} 7712 next; 7713 } 7714 $IncDir{$Dep} = 1; 7715 } 7716 } 7717 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion); 7718 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; 7719} 7720 7721sub sortIncPaths($$) 7722{ 7723 my ($ArrRef, $LibVersion) = @_; 7724 if(not $ArrRef or $#{$ArrRef}<0) { 7725 return $ArrRef; 7726 } 7727 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef}; 7728 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef}; 7729 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef}; 7730 return $ArrRef; 7731} 7732 7733sub sortDeps($$$) 7734{ 7735 if($Header_Dependency{$_[2]}{$_[0]} 7736 and not $Header_Dependency{$_[2]}{$_[1]}) { 7737 return 1; 7738 } 7739 elsif(not $Header_Dependency{$_[2]}{$_[0]} 7740 and $Header_Dependency{$_[2]}{$_[1]}) { 7741 return -1; 7742 } 7743 return 0; 7744} 7745 7746sub join_P($$) 7747{ 7748 my $S = "/"; 7749 if($OSgroup eq "windows") { 7750 $S = "\\"; 7751 } 7752 return join($S, @_); 7753} 7754 7755sub get_namespace_additions($) 7756{ 7757 my $NameSpaces = $_[0]; 7758 my ($Additions, $AddNameSpaceId) = ("", 1); 7759 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces})) 7760 { 7761 next if($SkipNameSpaces{$Version}{$NS}); 7762 next if(not $NS or $NameSpaces->{$NS}==-1); 7763 next if($NS=~/(\A|::)iterator(::|\Z)/i); 7764 next if($NS=~/\A__/i); 7765 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING); 7766 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports 7767 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = (); 7768 my @NS_Parts = split(/::/, $NS); 7769 next if($#NS_Parts==-1); 7770 next if($NS_Parts[0]=~/\A(random|or)\Z/); 7771 foreach my $NS_Part (@NS_Parts) 7772 { 7773 $TypeDecl_Prefix .= "namespace $NS_Part\{"; 7774 $TypeDecl_Suffix .= "}"; 7775 } 7776 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix; 7777 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};"; 7778 $Additions.=" $TypeDecl\n $FuncDecl\n"; 7779 $AddNameSpaceId+=1; 7780 } 7781 return $Additions; 7782} 7783 7784sub path_format($$) 7785{ 7786 my ($Path, $Fmt) = @_; 7787 $Path=~s/[\/\\]+\.?\Z//g; 7788 if($Fmt eq "windows") 7789 { 7790 $Path=~s/\//\\/g; 7791 $Path=lc($Path); 7792 } 7793 else 7794 { # forward slash to pass into MinGW GCC 7795 $Path=~s/\\/\//g; 7796 } 7797 return $Path; 7798} 7799 7800sub inc_opt($$) 7801{ 7802 my ($Path, $Style) = @_; 7803 if($Style eq "GCC") 7804 { # GCC options 7805 if($OSgroup eq "windows") 7806 { # to MinGW GCC 7807 return "-I\"".path_format($Path, "unix")."\""; 7808 } 7809 elsif($OSgroup eq "macos" 7810 and $Path=~/\.framework\Z/) 7811 { # to Apple's GCC 7812 return "-F".esc(get_dirname($Path)); 7813 } 7814 else { 7815 return "-I".esc($Path); 7816 } 7817 } 7818 elsif($Style eq "CL") { 7819 return "/I \"".$Path."\""; 7820 } 7821 return ""; 7822} 7823 7824sub platformSpecs($) 7825{ 7826 my $LibVersion = $_[0]; 7827 my $Arch = getArch($LibVersion); 7828 if($OStarget eq "symbian") 7829 { # options for GCCE compiler 7830 my %Symbian_Opts = map {$_=>1} ( 7831 "-D__GCCE__", 7832 "-DUNICODE", 7833 "-fexceptions", 7834 "-D__SYMBIAN32__", 7835 "-D__MARM_INTERWORK__", 7836 "-D_UNICODE", 7837 "-D__S60_50__", 7838 "-D__S60_3X__", 7839 "-D__SERIES60_3X__", 7840 "-D__EPOC32__", 7841 "-D__MARM__", 7842 "-D__EABI__", 7843 "-D__MARM_ARMV5__", 7844 "-D__SUPPORT_CPP_EXCEPTIONS__", 7845 "-march=armv5t", 7846 "-mapcs", 7847 "-mthumb-interwork", 7848 "-DEKA2", 7849 "-DSYMBIAN_ENABLE_SPLIT_HEADERS" 7850 ); 7851 return join(" ", keys(%Symbian_Opts)); 7852 } 7853 elsif($OSgroup eq "windows" 7854 and get_dumpmachine($GCC_PATH)=~/mingw/i) 7855 { # add options to MinGW compiler 7856 # to simulate the MSVC compiler 7857 my %MinGW_Opts = map {$_=>1} ( 7858 "-D_WIN32", 7859 "-D_STDCALL_SUPPORTED", 7860 "-D__int64=\"long long\"", 7861 "-D__int32=int", 7862 "-D__int16=short", 7863 "-D__int8=char", 7864 "-D__possibly_notnullterminated=\" \"", 7865 "-D__nullterminated=\" \"", 7866 "-D__nullnullterminated=\" \"", 7867 "-D__w64=\" \"", 7868 "-D__ptr32=\" \"", 7869 "-D__ptr64=\" \"", 7870 "-D__forceinline=inline", 7871 "-D__inline=inline", 7872 "-D__uuidof(x)=IID()", 7873 "-D__try=", 7874 "-D__except(x)=", 7875 "-D__declspec(x)=__attribute__((x))", 7876 "-D__pragma(x)=", 7877 "-D_inline=inline", 7878 "-D__forceinline=__inline", 7879 "-D__stdcall=__attribute__((__stdcall__))", 7880 "-D__cdecl=__attribute__((__cdecl__))", 7881 "-D__fastcall=__attribute__((__fastcall__))", 7882 "-D__thiscall=__attribute__((__thiscall__))", 7883 "-D_stdcall=__attribute__((__stdcall__))", 7884 "-D_cdecl=__attribute__((__cdecl__))", 7885 "-D_fastcall=__attribute__((__fastcall__))", 7886 "-D_thiscall=__attribute__((__thiscall__))", 7887 "-DSHSTDAPI_(x)=x", 7888 "-D_MSC_EXTENSIONS", 7889 "-DSECURITY_WIN32", 7890 "-D_MSC_VER=1500", 7891 "-D_USE_DECLSPECS_FOR_SAL", 7892 "-D__noop=\" \"", 7893 "-DDECLSPEC_DEPRECATED=\" \"", 7894 "-D__builtin_alignof(x)=__alignof__(x)", 7895 "-DSORTPP_PASS"); 7896 if($Arch eq "x86") { 7897 $MinGW_Opts{"-D_M_IX86=300"}=1; 7898 } 7899 elsif($Arch eq "x86_64") { 7900 $MinGW_Opts{"-D_M_AMD64=300"}=1; 7901 } 7902 elsif($Arch eq "ia64") { 7903 $MinGW_Opts{"-D_M_IA64=300"}=1; 7904 } 7905 return join(" ", keys(%MinGW_Opts)); 7906 } 7907 return ""; 7908} 7909 7910my %C_Structure = map {$_=>1} ( 7911# FIXME: Can't separate union and struct data types before dumping, 7912# so it sometimes cause compilation errors for unknown reason 7913# when trying to declare TYPE* tmp_add_class_N 7914# This is a list of such structures + list of other C structures 7915 "sigval", 7916 "sigevent", 7917 "sigaction", 7918 "sigvec", 7919 "sigstack", 7920 "timeval", 7921 "timezone", 7922 "rusage", 7923 "rlimit", 7924 "wait", 7925 "flock", 7926 "stat", 7927 "_stat", 7928 "stat32", 7929 "_stat32", 7930 "stat64", 7931 "_stat64", 7932 "_stati64", 7933 "if_nameindex", 7934 "usb_device", 7935 "sigaltstack", 7936 "sysinfo", 7937 "timeLocale", 7938 "tcp_debug", 7939 "rpc_createerr", 7940 # Other 7941 "timespec", 7942 "random_data", 7943 "drand48_data", 7944 "_IO_marker", 7945 "_IO_FILE", 7946 "lconv", 7947 "sched_param", 7948 "tm", 7949 "itimerspec", 7950 "_pthread_cleanup_buffer", 7951 "fd_set", 7952 "siginfo", 7953 "mallinfo", 7954 "timex", 7955 "sigcontext", 7956 "ucontext", 7957 # Mac 7958 "_timex", 7959 "_class_t", 7960 "_category_t", 7961 "_class_ro_t", 7962 "_protocol_t", 7963 "_message_ref_t", 7964 "_super_message_ref_t", 7965 "_ivar_t", 7966 "_ivar_list_t" 7967); 7968 7969sub getCompileCmd($$$) 7970{ 7971 my ($Path, $Opt, $Inc) = @_; 7972 my $GccCall = $GCC_PATH; 7973 if($Opt) { 7974 $GccCall .= " ".$Opt; 7975 } 7976 $GccCall .= " -x "; 7977 if($OSgroup eq "macos") { 7978 $GccCall .= "objective-"; 7979 } 7980 7981 if($EMERGENCY_MODE_48) 7982 { # workaround for GCC 4.8 (C only) 7983 $GccCall .= "c++"; 7984 } 7985 elsif(check_gcc($GCC_PATH, "4")) 7986 { # compile as "C++" header 7987 # to obtain complete dump using GCC 4.0 7988 $GccCall .= "c++-header"; 7989 } 7990 else 7991 { # compile as "C++" source 7992 # GCC 3.3 cannot compile headers 7993 $GccCall .= "c++"; 7994 } 7995 if(my $Opts = platformSpecs($Version)) 7996 { # platform-specific options 7997 $GccCall .= " ".$Opts; 7998 } 7999 # allow extra qualifications 8000 # and other nonconformant code 8001 $GccCall .= " -fpermissive"; 8002 $GccCall .= " -w"; 8003 if($NoStdInc) 8004 { 8005 $GccCall .= " -nostdinc"; 8006 $GccCall .= " -nostdinc++"; 8007 } 8008 if(my $Opts_GCC = getGCC_Opts($Version)) 8009 { # user-defined options 8010 $GccCall .= " ".$Opts_GCC; 8011 } 8012 $GccCall .= " \"$Path\""; 8013 if($Inc) 8014 { # include paths 8015 $GccCall .= " ".$Inc; 8016 } 8017 return $GccCall; 8018} 8019 8020sub detectPreamble($$) 8021{ 8022 my ($Content, $LibVersion) = @_; 8023 my %HeaderElems = ( 8024 # Types 8025 "stdio.h" => ["FILE", "va_list"], 8026 "stddef.h" => ["NULL", "ptrdiff_t"], 8027 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t", 8028 "int8_t", "int16_t", "int32_t", "int64_t"], 8029 "time.h" => ["time_t"], 8030 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char", 8031 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"], 8032 "unistd.h" => ["gid_t", "uid_t", "socklen_t"], 8033 "stdbool.h" => ["_Bool"], 8034 "rpc/xdr.h" => ["bool_t"], 8035 "in_systm.h" => ["n_long", "n_short"], 8036 # Fields 8037 "arpa/inet.h" => ["fw_src", "ip_src"], 8038 # Functions 8039 "stdlib.h" => ["free", "malloc", "size_t"], 8040 "string.h" => ["memmove", "strcmp"] 8041 ); 8042 my %AutoPreamble = (); 8043 foreach (keys(%HeaderElems)) 8044 { 8045 foreach my $Elem (@{$HeaderElems{$_}}) { 8046 $AutoPreamble{$Elem} = $_; 8047 } 8048 } 8049 my %Types = (); 8050 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//) 8051 { # error: 'FILE' has not been declared 8052 $Types{$2} = 1; 8053 } 8054 if(keys(%Types)) 8055 { 8056 my %AddHeaders = (); 8057 foreach my $Type (keys(%Types)) 8058 { 8059 if(my $Header = $AutoPreamble{$Type}) 8060 { 8061 if(my $Path = identifyHeader($Header, $LibVersion)) 8062 { 8063 if(skipHeader($Path, $LibVersion)) { 8064 next; 8065 } 8066 $Path = path_format($Path, $OSgroup); 8067 $AddHeaders{$Path}{"Type"} = $Type; 8068 $AddHeaders{$Path}{"Header"} = $Header; 8069 } 8070 } 8071 } 8072 if(keys(%AddHeaders)) { 8073 return \%AddHeaders; 8074 } 8075 } 8076 return undef; 8077} 8078 8079sub checkCTags($) 8080{ 8081 my $Path = $_[0]; 8082 if(not $Path) { 8083 return; 8084 } 8085 my $CTags = undef; 8086 8087 if($OSgroup eq "bsd") 8088 { # use ectags on BSD 8089 $CTags = get_CmdPath("ectags"); 8090 if(not $CTags) { 8091 printMsg("WARNING", "can't find \'ectags\' program"); 8092 } 8093 } 8094 if(not $CTags) { 8095 $CTags = get_CmdPath("ctags"); 8096 } 8097 if(not $CTags) 8098 { 8099 printMsg("WARNING", "can't find \'ctags\' program"); 8100 return; 8101 } 8102 8103 if($OSgroup ne "linux") 8104 { # macos, freebsd, etc. 8105 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`; 8106 if($Info!~/exuberant/i) 8107 { 8108 printMsg("WARNING", "incompatible version of \'ctags\' program"); 8109 return; 8110 } 8111 } 8112 8113 my $Out = $TMP_DIR."/ctags.txt"; 8114 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\""); 8115 if($Debug) { 8116 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt"); 8117 } 8118 open(CTAGS, "<", $Out); 8119 while(my $Line = <CTAGS>) 8120 { 8121 chomp($Line); 8122 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line); 8123 if(defined $Intrinsic_Keywords{$Name}) 8124 { # noise 8125 next; 8126 } 8127 if($Type eq "n") 8128 { 8129 if(index($Scpe, "class:")==0) { 8130 next; 8131 } 8132 if(index($Scpe, "struct:")==0) { 8133 next; 8134 } 8135 if(index($Scpe, "namespace:")==0) 8136 { 8137 if($Scpe=~s/\Anamespace://) { 8138 $Name = $Scpe."::".$Name; 8139 } 8140 } 8141 $TUnit_NameSpaces{$Version}{$Name} = 1; 8142 } 8143 elsif($Type eq "p") 8144 { 8145 if(not $Scpe or index($Scpe, "namespace:")==0) { 8146 $TUnit_Funcs{$Version}{$Name} = 1; 8147 } 8148 } 8149 elsif($Type eq "x") 8150 { 8151 if(not $Scpe or index($Scpe, "namespace:")==0) { 8152 $TUnit_Vars{$Version}{$Name} = 1; 8153 } 8154 } 8155 } 8156 close(CTAGS); 8157} 8158 8159sub preChange($$) 8160{ 8161 my ($HeaderPath, $IncStr) = @_; 8162 8163 my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr); 8164 my $Content = undef; 8165 8166 if($OStarget eq "windows" 8167 and get_dumpmachine($GCC_PATH)=~/mingw/i 8168 and $MinGWMode{$Version}!=-1) 8169 { # modify headers to compile by MinGW 8170 if(not $Content) 8171 { # preprocessing 8172 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8173 } 8174 if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g) 8175 { # __asm { ... } 8176 $MinGWMode{$Version}=1; 8177 } 8178 if($Content=~s/\s+(\/ \/.*?)\n/\n/g) 8179 { # comments after preprocessing 8180 $MinGWMode{$Version}=1; 8181 } 8182 if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g) 8183 { # 0xffui8 8184 $MinGWMode{$Version}=1; 8185 } 8186 8187 if($MinGWMode{$Version}) { 8188 printMsg("INFO", "Using MinGW compatibility mode"); 8189 } 8190 } 8191 8192 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly) 8193 and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS) 8194 { # rename C++ keywords in C code 8195 # disable this code by -cpp-compatible option 8196 if(not $Content) 8197 { # preprocessing 8198 $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; 8199 } 8200 my $RegExp_C = join("|", keys(%CppKeywords_C)); 8201 my $RegExp_F = join("|", keys(%CppKeywords_F)); 8202 my $RegExp_O = join("|", keys(%CppKeywords_O)); 8203 8204 my $Detected = undef; 8205 8206 while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/$1$2c99_$3$4/g) 8207 { # MATCH: 8208 # int foo(int new, int class, int (*new)(int)); 8209 # int foo(char template[], char*); 8210 # unsigned private: 8; 8211 # DO NOT MATCH: 8212 # #pragma GCC visibility push(default) 8213 $CppMode{$Version} = 1; 8214 $Detected = "$1$2$3$4" if(not defined $Detected); 8215 } 8216 if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g) 8217 { # MATCH: 8218 # int delete(...); 8219 # int explicit(...); 8220 # DO NOT MATCH: 8221 # void operator delete(...) 8222 $CppMode{$Version} = 1; 8223 $Detected = "$1$2$3" if(not defined $Detected); 8224 } 8225 if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g) 8226 { # MATCH: 8227 # int bool; 8228 # DO NOT MATCH: 8229 # bool X; 8230 # return *this; 8231 # throw; 8232 $CppMode{$Version} = 1; 8233 $Detected = "$1$2$3" if(not defined $Detected); 8234 } 8235 if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g) 8236 { # MATCH: 8237 # int operator(...); 8238 # DO NOT MATCH: 8239 # int operator()(...); 8240 $CppMode{$Version} = 1; 8241 $Detected = "$1$2$3" if(not defined $Detected); 8242 } 8243 if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g) 8244 { # MATCH: 8245 # int foo(int operator); 8246 # int foo(int operator, int other); 8247 # DO NOT MATCH: 8248 # int operator,(...); 8249 $CppMode{$Version} = 1; 8250 $Detected = "$1$2$3" if(not defined $Detected); 8251 } 8252 if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g) 8253 { # MATCH: 8254 # int foo(gboolean *bool); 8255 # DO NOT MATCH: 8256 # void setTabEnabled(int index, bool); 8257 $CppMode{$Version} = 1; 8258 $Detected = "$1$2$3" if(not defined $Detected); 8259 } 8260 if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g) 8261 { # MATCH: 8262 # int foo(int* this); 8263 # int bar(int this); 8264 # int baz(int throw); 8265 # DO NOT MATCH: 8266 # foo(X, this); 8267 $CppMode{$Version} = 1; 8268 $Detected = "$1$2$3$4" if(not defined $Detected); 8269 } 8270 if($Content=~s/(struct |extern )(template) /$1c99_$2 /g) 8271 { # MATCH: 8272 # struct template {...}; 8273 # extern template foo(...); 8274 $CppMode{$Version} = 1; 8275 $Detected = "$1$2" if(not defined $Detected); 8276 } 8277 8278 if($CppMode{$Version} == 1) 8279 { 8280 if($Debug) 8281 { 8282 $Detected=~s/\A\s+//g; 8283 printMsg("INFO", "Detected code: \"$Detected\""); 8284 } 8285 } 8286 8287 # remove typedef enum NAME NAME; 8288 my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g; 8289 my $N = 0; 8290 while($N<=$#FwdTypedefs-1) 8291 { 8292 my $S = $FwdTypedefs[$N]; 8293 if($S eq $FwdTypedefs[$N+1]) 8294 { 8295 $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g; 8296 $CppMode{$Version} = 1; 8297 8298 if($Debug) { 8299 printMsg("INFO", "Detected code: \"typedef enum $S $S;\""); 8300 } 8301 } 8302 $N+=2; 8303 } 8304 8305 if($CppMode{$Version}==1) { 8306 printMsg("INFO", "Using C++ compatibility mode"); 8307 } 8308 } 8309 8310 if($CppMode{$Version}==1 8311 or $MinGWMode{$Version}==1) 8312 { 8313 my $IPath = $TMP_DIR."/dump$Version.i"; 8314 writeFile($IPath, $Content); 8315 return $IPath; 8316 } 8317 8318 return undef; 8319} 8320 8321sub getDump() 8322{ 8323 if(not $GCC_PATH) { 8324 exitStatus("Error", "internal error - GCC path is not set"); 8325 } 8326 8327 my @Headers = keys(%{$Registered_Headers{$Version}}); 8328 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers; 8329 8330 my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC"); 8331 8332 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h"; 8333 my $HeaderPath = $TmpHeaderPath; 8334 8335 # write tmp-header 8336 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n"); 8337 if(my $AddDefines = $Descriptor{$Version}{"Defines"}) 8338 { 8339 $AddDefines=~s/\n\s+/\n /g; 8340 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n"; 8341 } 8342 print TMP_HEADER "\n // add includes\n"; 8343 foreach my $HPath (@{$Include_Preamble{$Version}}) { 8344 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8345 } 8346 foreach my $HPath (@Headers) 8347 { 8348 if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) { 8349 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; 8350 } 8351 } 8352 close(TMP_HEADER); 8353 8354 if($ExtraInfo) 8355 { # extra information for other tools 8356 if($IncludeString) { 8357 writeFile($ExtraInfo."/include-string", $IncludeString); 8358 } 8359 writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version})); 8360 writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version})); 8361 8362 if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}})) 8363 { 8364 my $REDIR = ""; 8365 foreach my $P1 (sort @Redirects) { 8366 $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n"; 8367 } 8368 writeFile($ExtraInfo."/include-redirect", $REDIR); 8369 } 8370 } 8371 8372 if(not keys(%{$TargetHeaders{$Version}})) 8373 { # Target headers 8374 addTargetHeaders($Version); 8375 } 8376 8377 # clean memory 8378 %RecursiveIncludes = (); 8379 %Header_Include_Prefix = (); 8380 %Header_Includes = (); 8381 8382 # clean cache 8383 delete($Cache{"identifyHeader"}); 8384 delete($Cache{"detect_header_includes"}); 8385 delete($Cache{"selectSystemHeader"}); 8386 8387 # preprocessing stage 8388 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version); 8389 checkPreprocessedUnit($Pre); 8390 8391 if($ExtraInfo) 8392 { # extra information for other tools 8393 writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}}))); 8394 } 8395 8396 # clean memory 8397 delete($Include_Neighbors{$Version}); 8398 delete($PreprocessedHeaders{$Version}); 8399 8400 if($COMMON_LANGUAGE{$Version} eq "C++") { 8401 checkCTags($Pre); 8402 } 8403 8404 if(my $PrePath = preChange($TmpHeaderPath, $IncludeString)) 8405 { # try to correct the preprocessor output 8406 $HeaderPath = $PrePath; 8407 } 8408 8409 if($COMMON_LANGUAGE{$Version} eq "C++") 8410 { # add classes and namespaces to the dump 8411 my $CHdump = "-fdump-class-hierarchy -c"; 8412 if($CppMode{$Version}==1 8413 or $MinGWMode{$Version}==1) { 8414 $CHdump .= " -fpreprocessed"; 8415 } 8416 my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString); 8417 chdir($TMP_DIR); 8418 system($ClassHierarchyCmd." >null 2>&1"); 8419 chdir($ORIG_DIR); 8420 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0]) 8421 { 8422 my $Content = readFile($ClassDump); 8423 foreach my $ClassInfo (split(/\n\n/, $Content)) 8424 { 8425 if($ClassInfo=~/\AClass\s+(.+)\s*/i) 8426 { 8427 my $CName = $1; 8428 next if($CName=~/\A(__|_objc_|_opaque_)/); 8429 $TUnit_NameSpaces{$Version}{$CName} = -1; 8430 if($CName=~/\A[\w:]+\Z/) 8431 { # classes 8432 $TUnit_Classes{$Version}{$CName} = 1; 8433 } 8434 if($CName=~/(\w[\w:]*)::/) 8435 { # namespaces 8436 my $NS = $1; 8437 if(not defined $TUnit_NameSpaces{$Version}{$NS}) { 8438 $TUnit_NameSpaces{$Version}{$NS} = 1; 8439 } 8440 } 8441 } 8442 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i) 8443 { # read v-tables (advanced approach) 8444 my ($CName, $VTable) = ($1, $2); 8445 $ClassVTable_Content{$Version}{$CName} = $VTable; 8446 } 8447 } 8448 foreach my $NS (keys(%{$AddNameSpaces{$Version}})) 8449 { # add user-defined namespaces 8450 $TUnit_NameSpaces{$Version}{$NS} = 1; 8451 } 8452 if($Debug) 8453 { # debug mode 8454 mkpath($DEBUG_PATH{$Version}); 8455 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt"); 8456 } 8457 unlink($ClassDump); 8458 } 8459 8460 # add namespaces and classes 8461 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version})) 8462 { # GCC on all supported platforms does not include namespaces to the dump by default 8463 appendFile($HeaderPath, "\n // add namespaces\n".$NS_Add); 8464 } 8465 # some GCC versions don't include class methods to the TU dump by default 8466 my ($AddClass, $ClassNum) = ("", 0); 8467 my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions 8468 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}})) 8469 { 8470 next if($C_Structure{$CName}); 8471 next if(not $STDCXX_TESTING and $CName=~/\Astd::/); 8472 next if($SkipTypes{$Version}{$CName}); 8473 if(not $Force and $GCC_44 8474 and $OSgroup eq "linux") 8475 { # optimization for linux with GCC >= 4.4 8476 # disable this code by -force option 8477 if(index($CName, "::")!=-1) 8478 { # should be added by name space 8479 next; 8480 } 8481 } 8482 else 8483 { 8484 if($CName=~/\A(.+)::[^:]+\Z/ 8485 and $TUnit_Classes{$Version}{$1}) 8486 { # classes inside other classes 8487 next; 8488 } 8489 } 8490 if(defined $TUnit_Funcs{$Version}{$CName}) 8491 { # the same name for a function and type 8492 next; 8493 } 8494 if(defined $TUnit_Vars{$Version}{$CName}) 8495 { # the same name for a variable and type 8496 next; 8497 } 8498 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n"; 8499 } 8500 if($AddClass) { 8501 appendFile($HeaderPath, "\n // add classes\n".$AddClass); 8502 } 8503 } 8504 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n"); 8505 # create TU dump 8506 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c"; 8507 if($UserLang eq "C") { 8508 $TUdump .= " -U__cplusplus -D_Bool=\"bool\""; 8509 } 8510 if($CppMode{$Version}==1 8511 or $MinGWMode{$Version}==1) { 8512 $TUdump .= " -fpreprocessed"; 8513 } 8514 my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString); 8515 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n"); 8516 chdir($TMP_DIR); 8517 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1"); 8518 my $Errors = ""; 8519 if($?) 8520 { # failed to compile, but the TU dump still can be created 8521 if($Errors = readFile($TMP_DIR."/tu_errors")) 8522 { # try to recompile 8523 # FIXME: handle other errors and try to recompile 8524 if($CppMode{$Version}==1 8525 and index($Errors, "c99_")!=-1 8526 and not defined $CppIncompat) 8527 { # disable c99 mode and try again 8528 $CppMode{$Version}=-1; 8529 8530 if($Debug) 8531 { 8532 # printMsg("INFO", $Errors); 8533 } 8534 8535 printMsg("INFO", "Disabling C++ compatibility mode"); 8536 resetLogging($Version); 8537 $TMP_DIR = tempdir(CLEANUP=>1); 8538 return getDump(); 8539 } 8540 elsif($AutoPreambleMode{$Version}!=-1 8541 and my $AddHeaders = detectPreamble($Errors, $Version)) 8542 { # add auto preamble headers and try again 8543 $AutoPreambleMode{$Version}=-1; 8544 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first 8545 foreach my $Num (0 .. $#Headers) 8546 { 8547 my $Path = $Headers[$Num]; 8548 if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}})) 8549 { 8550 push_U($Include_Preamble{$Version}, $Path); 8551 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'"); 8552 } 8553 } 8554 resetLogging($Version); 8555 $TMP_DIR = tempdir(CLEANUP=>1); 8556 return getDump(); 8557 } 8558 elsif($Cpp0xMode{$Version}!=-1 8559 and ($Errors=~/\Q-std=c++0x\E/ 8560 or $Errors=~/is not a class or namespace/)) 8561 { # c++0x: enum class 8562 if(check_gcc($GCC_PATH, "4.6")) 8563 { 8564 $Cpp0xMode{$Version}=-1; 8565 printMsg("INFO", "Enabling c++0x mode"); 8566 resetLogging($Version); 8567 $TMP_DIR = tempdir(CLEANUP=>1); 8568 $CompilerOptions{$Version} .= " -std=c++0x"; 8569 return getDump(); 8570 } 8571 else { 8572 printMsg("WARNING", "Probably c++0x construction detected"); 8573 } 8574 8575 } 8576 elsif($MinGWMode{$Version}==1) 8577 { # disable MinGW mode and try again 8578 $MinGWMode{$Version}=-1; 8579 resetLogging($Version); 8580 $TMP_DIR = tempdir(CLEANUP=>1); 8581 return getDump(); 8582 } 8583 writeLog($Version, $Errors); 8584 } 8585 else { 8586 writeLog($Version, "$!: $?\n"); 8587 } 8588 printMsg("ERROR", "some errors occurred when compiling headers"); 8589 printErrorLog($Version); 8590 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"}; 8591 writeLog($Version, "\n"); # new line 8592 } 8593 chdir($ORIG_DIR); 8594 unlink($TmpHeaderPath); 8595 unlink($HeaderPath); 8596 8597 if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) { 8598 return $TUs[0]; 8599 } 8600 else 8601 { 8602 my $Msg = "can't compile header(s)"; 8603 if($Errors=~/error trying to exec \W+cc1plus\W+/) { 8604 $Msg .= "\nDid you install G++?"; 8605 } 8606 exitStatus("Cannot_Compile", $Msg); 8607 } 8608} 8609 8610sub cmd_file($) 8611{ 8612 my $Path = $_[0]; 8613 return "" if(not $Path or not -e $Path); 8614 if(my $CmdPath = get_CmdPath("file")) { 8615 return `$CmdPath -b \"$Path\"`; 8616 } 8617 return ""; 8618} 8619 8620sub getIncString($$) 8621{ 8622 my ($ArrRef, $Style) = @_; 8623 return "" if(not $ArrRef or $#{$ArrRef}<0); 8624 my $String = ""; 8625 foreach (@{$ArrRef}) { 8626 $String .= " ".inc_opt($_, $Style); 8627 } 8628 return $String; 8629} 8630 8631sub getIncPaths(@) 8632{ 8633 my @HeaderPaths = @_; 8634 my @IncPaths = @{$Add_Include_Paths{$Version}}; 8635 if($INC_PATH_AUTODETECT{$Version}) 8636 { # auto-detecting dependencies 8637 my %Includes = (); 8638 foreach my $HPath (@HeaderPaths) 8639 { 8640 foreach my $Dir (get_HeaderDeps($HPath, $Version)) 8641 { 8642 if($Skip_Include_Paths{$Version}{$Dir}) { 8643 next; 8644 } 8645 if($SystemRoot) 8646 { 8647 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) { 8648 next; 8649 } 8650 } 8651 $Includes{$Dir} = 1; 8652 } 8653 } 8654 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) { 8655 push_U(\@IncPaths, $Dir); 8656 } 8657 } 8658 else 8659 { # user-defined paths 8660 @IncPaths = @{$Include_Paths{$Version}}; 8661 } 8662 return \@IncPaths; 8663} 8664 8665sub push_U($@) 8666{ # push unique 8667 if(my $Array = shift @_) 8668 { 8669 if(@_) 8670 { 8671 my %Exist = map {$_=>1} @{$Array}; 8672 foreach my $Elem (@_) 8673 { 8674 if(not defined $Exist{$Elem}) 8675 { 8676 push(@{$Array}, $Elem); 8677 $Exist{$Elem} = 1; 8678 } 8679 } 8680 } 8681 } 8682} 8683 8684sub callPreprocessor($$$) 8685{ 8686 my ($Path, $Inc, $LibVersion) = @_; 8687 return "" if(not $Path or not -f $Path); 8688 my $IncludeString=$Inc; 8689 if(not $Inc) { 8690 $IncludeString = getIncString(getIncPaths($Path), "GCC"); 8691 } 8692 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString); 8693 my $Out = $TMP_DIR."/preprocessed.h"; 8694 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\""); 8695 return $Out; 8696} 8697 8698sub cmd_find($;$$$$) 8699{ # native "find" is much faster than File::Find (~6x) 8700 # also the File::Find doesn't support --maxdepth N option 8701 # so using the cross-platform wrapper for the native one 8702 my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_; 8703 return () if(not $Path or not -e $Path); 8704 if($OSgroup eq "windows") 8705 { 8706 $Path = get_abs_path($Path); 8707 $Path = path_format($Path, $OSgroup); 8708 my $Cmd = "dir \"$Path\" /B /O"; 8709 if($MaxDepth!=1) { 8710 $Cmd .= " /S"; 8711 } 8712 if($Type eq "d") { 8713 $Cmd .= " /AD"; 8714 } 8715 elsif($Type eq "f") { 8716 $Cmd .= " /A-D"; 8717 } 8718 my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`); 8719 if($Name) 8720 { 8721 if(not $UseRegex) 8722 { # FIXME: how to search file names in MS shell? 8723 # wildcard to regexp 8724 $Name=~s/\*/.*/g; 8725 $Name='\A'.$Name.'\Z'; 8726 } 8727 @Files = grep { /$Name/i } @Files; 8728 } 8729 my @AbsPaths = (); 8730 foreach my $File (@Files) 8731 { 8732 if(not is_abs($File)) { 8733 $File = join_P($Path, $File); 8734 } 8735 if($Type eq "f" and not -f $File) 8736 { # skip dirs 8737 next; 8738 } 8739 push(@AbsPaths, path_format($File, $OSgroup)); 8740 } 8741 if($Type eq "d") { 8742 push(@AbsPaths, $Path); 8743 } 8744 return @AbsPaths; 8745 } 8746 else 8747 { 8748 my $FindCmd = get_CmdPath("find"); 8749 if(not $FindCmd) { 8750 exitStatus("Not_Found", "can't find a \"find\" command"); 8751 } 8752 $Path = get_abs_path($Path); 8753 if(-d $Path and -l $Path 8754 and $Path!~/\/\Z/) 8755 { # for directories that are symlinks 8756 $Path.="/"; 8757 } 8758 my $Cmd = $FindCmd." \"$Path\""; 8759 if($MaxDepth) { 8760 $Cmd .= " -maxdepth $MaxDepth"; 8761 } 8762 if($Type) { 8763 $Cmd .= " -type $Type"; 8764 } 8765 if($Name and not $UseRegex) 8766 { # wildcards 8767 $Cmd .= " -name \"$Name\""; 8768 } 8769 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`; 8770 if($? and $!) { 8771 printMsg("ERROR", "problem with \'find\' utility ($?): $!"); 8772 } 8773 my @Files = split(/\n/, $Res); 8774 if($Name and $UseRegex) 8775 { # regex 8776 @Files = grep { /$Name/ } @Files; 8777 } 8778 return @Files; 8779 } 8780} 8781 8782sub unpackDump($) 8783{ 8784 my $Path = $_[0]; 8785 return "" if(not $Path or not -e $Path); 8786 $Path = get_abs_path($Path); 8787 $Path = path_format($Path, $OSgroup); 8788 my ($Dir, $FileName) = separate_path($Path); 8789 my $UnpackDir = $TMP_DIR."/unpack"; 8790 rmtree($UnpackDir); 8791 mkpath($UnpackDir); 8792 if($FileName=~s/\Q.zip\E\Z//g) 8793 { # *.zip 8794 my $UnzipCmd = get_CmdPath("unzip"); 8795 if(not $UnzipCmd) { 8796 exitStatus("Not_Found", "can't find \"unzip\" command"); 8797 } 8798 chdir($UnpackDir); 8799 system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\""); 8800 if($?) { 8801 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8802 } 8803 chdir($ORIG_DIR); 8804 my @Contents = cmd_find($UnpackDir, "f"); 8805 if(not @Contents) { 8806 exitStatus("Error", "can't extract \'$Path\'"); 8807 } 8808 return $Contents[0]; 8809 } 8810 elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g) 8811 { # *.tar.gz 8812 # *.tar.gz.amd64 (dh & cdbs) 8813 if($OSgroup eq "windows") 8814 { # -xvzf option is not implemented in tar.exe (2003) 8815 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead 8816 my $TarCmd = get_CmdPath("tar"); 8817 if(not $TarCmd) { 8818 exitStatus("Not_Found", "can't find \"tar\" command"); 8819 } 8820 my $GzipCmd = get_CmdPath("gzip"); 8821 if(not $GzipCmd) { 8822 exitStatus("Not_Found", "can't find \"gzip\" command"); 8823 } 8824 chdir($UnpackDir); 8825 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k) 8826 if($?) { 8827 exitStatus("Error", "can't extract \'$Path\'"); 8828 } 8829 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\""); 8830 if($?) { 8831 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8832 } 8833 chdir($ORIG_DIR); 8834 unlink($Dir."/".$FileName.".tar"); 8835 my @Contents = cmd_find($UnpackDir, "f"); 8836 if(not @Contents) { 8837 exitStatus("Error", "can't extract \'$Path\'"); 8838 } 8839 return $Contents[0]; 8840 } 8841 else 8842 { # Unix, Mac 8843 my $TarCmd = get_CmdPath("tar"); 8844 if(not $TarCmd) { 8845 exitStatus("Not_Found", "can't find \"tar\" command"); 8846 } 8847 chdir($UnpackDir); 8848 system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\""); 8849 if($?) { 8850 exitStatus("Error", "can't extract \'$Path\' ($?): $!"); 8851 } 8852 chdir($ORIG_DIR); 8853 my @Contents = cmd_find($UnpackDir, "f"); 8854 if(not @Contents) { 8855 exitStatus("Error", "can't extract \'$Path\'"); 8856 } 8857 return $Contents[0]; 8858 } 8859 } 8860} 8861 8862sub createArchive($$) 8863{ 8864 my ($Path, $To) = @_; 8865 if(not $To) { 8866 $To = "."; 8867 } 8868 if(not $Path or not -e $Path 8869 or not -d $To) { 8870 return ""; 8871 } 8872 my ($From, $Name) = separate_path($Path); 8873 if($OSgroup eq "windows") 8874 { # *.zip 8875 my $ZipCmd = get_CmdPath("zip"); 8876 if(not $ZipCmd) { 8877 exitStatus("Not_Found", "can't find \"zip\""); 8878 } 8879 my $Pkg = $To."/".$Name.".zip"; 8880 unlink($Pkg); 8881 chdir($To); 8882 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\""); 8883 if($?) 8884 { # cannot allocate memory (or other problems with "zip") 8885 unlink($Path); 8886 exitStatus("Error", "can't pack the ABI dump: ".$!); 8887 } 8888 chdir($ORIG_DIR); 8889 unlink($Path); 8890 return $Pkg; 8891 } 8892 else 8893 { # *.tar.gz 8894 my $TarCmd = get_CmdPath("tar"); 8895 if(not $TarCmd) { 8896 exitStatus("Not_Found", "can't find \"tar\""); 8897 } 8898 my $GzipCmd = get_CmdPath("gzip"); 8899 if(not $GzipCmd) { 8900 exitStatus("Not_Found", "can't find \"gzip\""); 8901 } 8902 my $Pkg = abs_path($To)."/".$Name.".tar.gz"; 8903 unlink($Pkg); 8904 chdir($From); 8905 system($TarCmd, "-czf", $Pkg, $Name); 8906 if($?) 8907 { # cannot allocate memory (or other problems with "tar") 8908 unlink($Path); 8909 exitStatus("Error", "can't pack the ABI dump: ".$!); 8910 } 8911 chdir($ORIG_DIR); 8912 unlink($Path); 8913 return $To."/".$Name.".tar.gz"; 8914 } 8915} 8916 8917sub is_header_file($) 8918{ 8919 if($_[0]=~/\.($HEADER_EXT)\Z/i) { 8920 return $_[0]; 8921 } 8922 return 0; 8923} 8924 8925sub is_not_header($) 8926{ 8927 if($_[0]=~/\.\w+\Z/ 8928 and $_[0]!~/\.($HEADER_EXT)\Z/i) { 8929 return 1; 8930 } 8931 return 0; 8932} 8933 8934sub is_header($$$) 8935{ 8936 my ($Header, $UserDefined, $LibVersion) = @_; 8937 return 0 if(-d $Header); 8938 if(-f $Header) { 8939 $Header = get_abs_path($Header); 8940 } 8941 else 8942 { 8943 if(is_abs($Header)) 8944 { # incorrect absolute path 8945 return 0; 8946 } 8947 if(my $HPath = identifyHeader($Header, $LibVersion)) { 8948 $Header = $HPath; 8949 } 8950 else 8951 { # can't find header 8952 return 0; 8953 } 8954 } 8955 if($Header=~/\.\w+\Z/) 8956 { # have an extension 8957 return is_header_file($Header); 8958 } 8959 else 8960 { 8961 if($UserDefined==2) 8962 { # specified on the command line 8963 if(cmd_file($Header)!~/HTML|XML/i) { 8964 return $Header; 8965 } 8966 } 8967 elsif($UserDefined) 8968 { # specified in the XML-descriptor 8969 # header file without an extension 8970 return $Header; 8971 } 8972 else 8973 { 8974 if(index($Header, "/include/")!=-1 8975 or cmd_file($Header)=~/C[\+]*\s+program/i) 8976 { # !~/HTML|XML|shared|dynamic/i 8977 return $Header; 8978 } 8979 } 8980 } 8981 return 0; 8982} 8983 8984sub addTargetHeaders($) 8985{ 8986 my $LibVersion = $_[0]; 8987 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}})) 8988 { 8989 my $RegDir = get_dirname($RegHeader); 8990 $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1; 8991 8992 if(not $INC_PATH_AUTODETECT{$LibVersion}) { 8993 detect_recursive_includes($RegHeader, $LibVersion); 8994 } 8995 8996 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}})) 8997 { 8998 my $Dir = get_dirname($RecInc); 8999 9000 if(familiarDirs($RegDir, $Dir) 9001 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1) 9002 { # in the same directory or included by #include "..." 9003 $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1; 9004 } 9005 } 9006 } 9007} 9008 9009sub familiarDirs($$) 9010{ 9011 my ($D1, $D2) = @_; 9012 if($D1 eq $D2) { 9013 return 1; 9014 } 9015 9016 my $U1 = index($D1, "/usr/"); 9017 my $U2 = index($D2, "/usr/"); 9018 9019 if($U1==0 and $U2!=0) { 9020 return 0; 9021 } 9022 9023 if($U2==0 and $U1!=0) { 9024 return 0; 9025 } 9026 9027 if(index($D2, $D1."/")==0) { 9028 return 1; 9029 } 9030 9031 # /usr/include/DIR 9032 # /home/user/DIR 9033 9034 my $DL = get_depth($D1); 9035 9036 my @Dirs1 = ($D1); 9037 while($DL - get_depth($D1)<=2 9038 and get_depth($D1)>=4 9039 and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { 9040 push(@Dirs1, $D1); 9041 } 9042 9043 my @Dirs2 = ($D2); 9044 while(get_depth($D2)>=4 9045 and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { 9046 push(@Dirs2, $D2); 9047 } 9048 9049 foreach my $P1 (@Dirs1) 9050 { 9051 foreach my $P2 (@Dirs2) 9052 { 9053 9054 if($P1 eq $P2) { 9055 return 1; 9056 } 9057 } 9058 } 9059 return 0; 9060} 9061 9062sub readHeaders($) 9063{ 9064 $Version = $_[0]; 9065 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ..."); 9066 my $DumpPath = getDump(); 9067 if($Debug) 9068 { # debug mode 9069 mkpath($DEBUG_PATH{$Version}); 9070 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt"); 9071 } 9072 getInfo($DumpPath); 9073} 9074 9075sub prepareTypes($) 9076{ 9077 my $LibVersion = $_[0]; 9078 if(not checkDump($LibVersion, "2.0")) 9079 { # support for old ABI dumps 9080 # type names have been corrected in ACC 1.22 (dump 2.0 format) 9081 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9082 { 9083 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9084 if($TName=~/\A(\w+)::(\w+)/) { 9085 my ($P1, $P2) = ($1, $2); 9086 if($P1 eq $P2) { 9087 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/; 9088 } 9089 else { 9090 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/; 9091 } 9092 } 9093 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName; 9094 } 9095 } 9096 if(not checkDump($LibVersion, "2.5")) 9097 { # support for old ABI dumps 9098 # V < 2.5: array size == "number of elements" 9099 # V >= 2.5: array size in bytes 9100 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9101 { 9102 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9103 if($Type{"Type"} eq "Array") 9104 { 9105 if(my $Size = $Type{"Size"}) 9106 { # array[N] 9107 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion}); 9108 $Size *= $Base{"Size"}; 9109 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size"; 9110 } 9111 else 9112 { # array[] is a pointer 9113 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion}; 9114 } 9115 } 9116 } 9117 } 9118 my $V2 = ($LibVersion==1)?2:1; 9119 if(not checkDump($LibVersion, "2.7")) 9120 { # support for old ABI dumps 9121 # size of "method ptr" corrected in 2.7 9122 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9123 { 9124 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 9125 if($PureType{"Type"} eq "MethodPtr") 9126 { 9127 my %Type = get_Type($TypeId, $LibVersion); 9128 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2); 9129 my %Type2 = get_Type($TypeId_2, $V2); 9130 if($Type{"Size"} ne $Type2{"Size"}) { 9131 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"}; 9132 } 9133 } 9134 } 9135 } 9136} 9137 9138sub prepareSymbols($) 9139{ 9140 my $LibVersion = $_[0]; 9141 9142 if(not keys(%{$SymbolInfo{$LibVersion}})) 9143 { # check if input is valid 9144 if(not $ExtendedCheck) 9145 { 9146 if($CheckHeadersOnly) { 9147 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")"); 9148 } 9149 else { 9150 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")"); 9151 } 9152 } 9153 } 9154 9155 my $Remangle = 0; 9156 if(not checkDump(1, "2.10") 9157 or not checkDump(2, "2.10")) 9158 { # different formats 9159 $Remangle = 1; 9160 } 9161 if($CheckHeadersOnly) 9162 { # different languages 9163 if($UserLang) 9164 { # --lang=LANG for both versions 9165 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"}) 9166 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"})) 9167 { 9168 if($UserLang eq "C++") 9169 { # remangle symbols 9170 $Remangle = 1; 9171 } 9172 elsif($UserLang eq "C") 9173 { # remove mangling 9174 $Remangle = -1; 9175 } 9176 } 9177 } 9178 } 9179 9180 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}})) 9181 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2 9182 if(not checkDump($LibVersion, "2.13")) 9183 { # support for old ABI dumps 9184 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 9185 { 9186 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) 9187 { 9188 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"}; 9189 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"}; 9190 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 9191 if(defined $DVal and $DVal ne "") 9192 { 9193 if($TName eq "char") { 9194 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal); 9195 } 9196 elsif($TName eq "bool") { 9197 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false"; 9198 } 9199 } 9200 } 9201 } 9202 } 9203 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) 9204 { 9205 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 9206 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}) 9207 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 9208 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg) 9209 # + support for old ABI dumps 9210 next; 9211 } 9212 } 9213 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9214 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9215 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}; 9216 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; 9217 9218 my $SRemangle = 0; 9219 if(not checkDump(1, "2.12") 9220 or not checkDump(2, "2.12")) 9221 { # support for old ABI dumps 9222 if($ShortName eq "operator>>") 9223 { 9224 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9225 { # corrected mangling of operator>> 9226 $SRemangle = 1; 9227 } 9228 } 9229 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9230 { 9231 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 9232 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/) 9233 { # corrected mangling of const global data 9234 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8) 9235 # and incorrectly mangled by old ACC versions 9236 $SRemangle = 1; 9237 } 9238 } 9239 } 9240 if(not $CheckHeadersOnly) 9241 { # support for old ABI dumps 9242 if(not checkDump(1, "2.17") 9243 or not checkDump(2, "2.17")) 9244 { 9245 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 9246 { 9247 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 9248 { 9249 if(link_symbol($ShortName, $LibVersion, "-Deps")) 9250 { 9251 $MnglName = $ShortName; 9252 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9253 } 9254 } 9255 } 9256 } 9257 } 9258 if($Remangle==1 or $SRemangle==1) 9259 { # support for old ABI dumps: some symbols are not mangled in old dumps 9260 # mangle both sets of symbols (old and new) 9261 # NOTE: remangling all symbols by the same mangler 9262 if($MnglName=~/\A_ZN(V|)K/) 9263 { # mangling may be incorrect on old ABI dumps 9264 # because of absent "Const" attribute 9265 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1; 9266 } 9267 if($MnglName=~/\A_ZN(K|)V/) 9268 { # mangling may be incorrect on old ABI dumps 9269 # because of absent "Volatile" attribute 9270 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1; 9271 } 9272 if(($ClassID and $MnglName!~/\A(_Z|\?)/) 9273 or (not $ClassID and $CheckHeadersOnly) 9274 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps"))) 9275 { # support for old ABI dumps, GCC >= 4.0 9276 # remangling all manually mangled symbols 9277 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC")) 9278 { 9279 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; 9280 $MangledNames{$LibVersion}{$MnglName} = 1; 9281 } 9282 } 9283 } 9284 elsif($Remangle==-1) 9285 { # remove mangling 9286 $MnglName = ""; 9287 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = ""; 9288 } 9289 if(not $MnglName) { 9290 next; 9291 } 9292 9293 # NOTE: duplicated entries in the ABI Dump 9294 if(defined $CompleteSignature{$LibVersion}{$MnglName}) 9295 { 9296 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 9297 { 9298 if($SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} eq "p1") 9299 { 9300 next; 9301 } 9302 } 9303 } 9304 9305 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"}) 9306 { # NOTE: global data may enter here twice 9307 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9308 9309 } 9310 if(not checkDump($LibVersion, "2.6")) 9311 { # support for old dumps 9312 # add "Volatile" attribute 9313 if($MnglName=~/_Z(K|)V/) { 9314 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1; 9315 } 9316 } 9317 # symbol and its symlink have same signatures 9318 if($SymVer{$LibVersion}{$MnglName}) { 9319 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9320 } 9321 9322 if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"}) 9323 { 9324 %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9325 9326 if($SymVer{$LibVersion}{$Alias}) { 9327 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9328 } 9329 } 9330 9331 # clean memory 9332 delete($SymbolInfo{$LibVersion}{$InfoId}); 9333 } 9334 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") { 9335 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion); 9336 } 9337 if($ExtendedCheck) 9338 { # --ext option 9339 addExtension($LibVersion); 9340 } 9341 9342 # clean memory 9343 delete($SymbolInfo{$LibVersion}); 9344 9345 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 9346 { # detect allocable classes with public exported constructors 9347 # or classes with auto-generated or inline-only constructors 9348 # and other temp info 9349 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 9350 { 9351 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 9352 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"} 9353 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}) 9354 { # Class() { ... } will not be exported 9355 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9356 { 9357 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) { 9358 $AllocableClass{$LibVersion}{$ClassName} = 1; 9359 } 9360 } 9361 } 9362 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) 9363 { # all imported class methods 9364 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary")) 9365 { 9366 if($CheckHeadersOnly) 9367 { 9368 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 9369 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 9370 { # all symbols except non-virtual inline 9371 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9372 } 9373 } 9374 else { 9375 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9376 } 9377 } 9378 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) { 9379 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1; 9380 } 9381 } 9382 $ClassNames{$LibVersion}{$ClassName} = 1; 9383 } 9384 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) 9385 { 9386 my %Base = get_BaseType($RetId, $LibVersion); 9387 if(defined $Base{"Type"} 9388 and $Base{"Type"}=~/Struct|Class/) 9389 { 9390 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"}; 9391 if($Name=~/<([^<>\s]+)>/) 9392 { 9393 if(my $Tid = getTypeIdByName($1, $LibVersion)) { 9394 $ReturnedClass{$LibVersion}{$Tid} = 1; 9395 } 9396 } 9397 else { 9398 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1; 9399 } 9400 } 9401 } 9402 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 9403 { 9404 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"}; 9405 if(get_PLevel($PId, $LibVersion)>=1) 9406 { 9407 if(my %Base = get_BaseType($PId, $LibVersion)) 9408 { 9409 if($Base{"Type"}=~/Struct|Class/) 9410 { 9411 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1; 9412 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1)) 9413 { # mark all derived classes 9414 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1; 9415 } 9416 } 9417 } 9418 } 9419 } 9420 9421 # mapping {short name => symbols} 9422 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1; 9423 } 9424 foreach my $MnglName (keys(%VTableClass)) 9425 { # reconstruct attributes of v-tables 9426 if(index($MnglName, "_ZTV")==0) 9427 { 9428 if(my $ClassName = $VTableClass{$MnglName}) 9429 { 9430 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 9431 { 9432 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"}; 9433 $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId; 9434 } 9435 } 9436 } 9437 } 9438 9439 # types 9440 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) 9441 { 9442 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}) 9443 { 9444 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) { 9445 $ClassNames{$LibVersion}{$TName} = 1; 9446 } 9447 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"}) 9448 { 9449 $ClassNames{$LibVersion}{$TName} = 1; 9450 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}})) 9451 { 9452 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) { 9453 $ClassNames{$LibVersion}{$BName} = 1; 9454 } 9455 } 9456 } 9457 } 9458 } 9459} 9460 9461sub getFirst($$) 9462{ 9463 my ($Tid, $LibVersion) = @_; 9464 if(not $Tid) { 9465 return $Tid; 9466 } 9467 9468 if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9469 { 9470 if($TName_Tid{$LibVersion}{$Name}) { 9471 return $TName_Tid{$LibVersion}{$Name}; 9472 } 9473 } 9474 9475 return $Tid; 9476} 9477 9478sub register_SymbolUsage($$$) 9479{ 9480 my ($InfoId, $UsedType, $LibVersion) = @_; 9481 9482 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; 9483 if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion)) 9484 { 9485 register_TypeUsage($RTid, $UsedType, $LibVersion); 9486 $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid; 9487 } 9488 if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion)) 9489 { 9490 register_TypeUsage($FCid, $UsedType, $LibVersion); 9491 $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid; 9492 9493 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) 9494 { # register "this" pointer 9495 register_TypeUsage($ThisId, $UsedType, $LibVersion); 9496 } 9497 if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion)) 9498 { # register "this" pointer (const method) 9499 register_TypeUsage($ThisId_C, $UsedType, $LibVersion); 9500 } 9501 } 9502 foreach my $PPos (keys(%{$FuncInfo{"Param"}})) 9503 { 9504 if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion)) 9505 { 9506 register_TypeUsage($PTid, $UsedType, $LibVersion); 9507 $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; 9508 } 9509 } 9510 foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) 9511 { 9512 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; 9513 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9514 register_TypeUsage($TTid, $UsedType, $LibVersion); 9515 } 9516 } 9517} 9518 9519sub register_TypeUsage($$$) 9520{ 9521 my ($TypeId, $UsedType, $LibVersion) = @_; 9522 if(not $TypeId) { 9523 return; 9524 } 9525 if($UsedType->{$TypeId}) 9526 { # already registered 9527 return; 9528 } 9529 9530 my %TInfo = get_Type($TypeId, $LibVersion); 9531 if($TInfo{"Type"}) 9532 { 9533 if(my $NS = $TInfo{"NameSpace"}) 9534 { 9535 if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) { 9536 register_TypeUsage($NSTid, $UsedType, $LibVersion); 9537 } 9538 } 9539 9540 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) 9541 { 9542 $UsedType->{$TypeId} = 1; 9543 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) 9544 { 9545 foreach my $BaseId (keys(%{$TInfo{"Base"}})) { 9546 register_TypeUsage($BaseId, $UsedType, $LibVersion); 9547 } 9548 foreach my $TPos (keys(%{$TInfo{"TParam"}})) 9549 { 9550 my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; 9551 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { 9552 register_TypeUsage($TTid, $UsedType, $LibVersion); 9553 } 9554 } 9555 } 9556 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}})) 9557 { 9558 if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion)) 9559 { 9560 register_TypeUsage($MTid, $UsedType, $LibVersion); 9561 $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; 9562 } 9563 } 9564 if($TInfo{"Type"} eq "FuncPtr" 9565 or $TInfo{"Type"} eq "MethodPtr" 9566 or $TInfo{"Type"} eq "Func") 9567 { 9568 if(my $RTid = $TInfo{"Return"}) { 9569 register_TypeUsage($RTid, $UsedType, $LibVersion); 9570 } 9571 foreach my $PPos (keys(%{$TInfo{"Param"}})) 9572 { 9573 if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { 9574 register_TypeUsage($PTid, $UsedType, $LibVersion); 9575 } 9576 } 9577 } 9578 if($TInfo{"Type"} eq "FieldPtr") 9579 { 9580 if(my $RTid = $TInfo{"Return"}) { 9581 register_TypeUsage($RTid, $UsedType, $LibVersion); 9582 } 9583 if(my $CTid = $TInfo{"Class"}) { 9584 register_TypeUsage($CTid, $UsedType, $LibVersion); 9585 } 9586 } 9587 if($TInfo{"Type"} eq "MethodPtr") 9588 { 9589 if(my $CTid = $TInfo{"Class"}) { 9590 register_TypeUsage($CTid, $UsedType, $LibVersion); 9591 } 9592 } 9593 } 9594 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) 9595 { 9596 $UsedType->{$TypeId} = 1; 9597 if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion)) 9598 { 9599 register_TypeUsage($BTid, $UsedType, $LibVersion); 9600 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid; 9601 } 9602 } 9603 else 9604 { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. 9605 $UsedType->{$TypeId} = 1; 9606 } 9607 } 9608} 9609 9610sub selectSymbol($$$$) 9611{ # select symbol to check or to dump 9612 my ($Symbol, $SInfo, $Level, $LibVersion) = @_; 9613 9614 if($Level eq "Dump") 9615 { 9616 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"}) 9617 { # TODO: check if this symbol is from 9618 # base classes of other target symbols 9619 return 1; 9620 } 9621 } 9622 9623 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/) 9624 { # stdc++ interfaces 9625 return 0; 9626 } 9627 9628 my $Target = 0; 9629 if(my $Header = $SInfo->{"Header"}) { 9630 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2)); 9631 } 9632 if($ExtendedCheck) 9633 { 9634 if(index($Symbol, "external_func_")==0) { 9635 $Target = 1; 9636 } 9637 } 9638 if($CheckHeadersOnly or $Level eq "Source") 9639 { 9640 if($Target) 9641 { 9642 if($Level eq "Dump") 9643 { # dumped 9644 if($BinaryOnly) 9645 { 9646 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) { 9647 return 1; 9648 } 9649 } 9650 else { 9651 return 1; 9652 } 9653 } 9654 elsif($Level eq "Source") 9655 { # checked 9656 return 1; 9657 } 9658 elsif($Level eq "Binary") 9659 { # checked 9660 if(not $SInfo->{"InLine"} or $SInfo->{"Data"} 9661 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) { 9662 return 1; 9663 } 9664 } 9665 } 9666 } 9667 else 9668 { # library is available 9669 if(link_symbol($Symbol, $LibVersion, "-Deps")) 9670 { # exported symbols 9671 return 1; 9672 } 9673 if($Level eq "Dump") 9674 { # dumped 9675 if($BinaryOnly) 9676 { 9677 if($SInfo->{"Data"}) 9678 { 9679 if($Target) { 9680 return 1; 9681 } 9682 } 9683 } 9684 else 9685 { # SrcBin 9686 if($Target) { 9687 return 1; 9688 } 9689 } 9690 } 9691 elsif($Level eq "Source") 9692 { # checked 9693 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"} 9694 or isInLineInst($SInfo, $LibVersion)) 9695 { # skip LOCAL symbols 9696 if($Target) { 9697 return 1; 9698 } 9699 } 9700 } 9701 elsif($Level eq "Binary") 9702 { # checked 9703 if($SInfo->{"PureVirt"} or $SInfo->{"Data"}) 9704 { 9705 if($Target) { 9706 return 1; 9707 } 9708 } 9709 } 9710 } 9711 return 0; 9712} 9713 9714sub cleanDump($) 9715{ # clean data 9716 my $LibVersion = $_[0]; 9717 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 9718 { 9719 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}})) 9720 { 9721 delete($SymbolInfo{$LibVersion}{$InfoId}); 9722 next; 9723 } 9724 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 9725 if(not $MnglName) 9726 { 9727 delete($SymbolInfo{$LibVersion}{$InfoId}); 9728 next; 9729 } 9730 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 9731 if(not $ShortName) 9732 { 9733 delete($SymbolInfo{$LibVersion}{$InfoId}); 9734 next; 9735 } 9736 if($MnglName eq $ShortName) 9737 { # remove duplicate data 9738 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}); 9739 } 9740 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) { 9741 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"}); 9742 } 9743 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { 9744 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"}); 9745 } 9746 delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"}); 9747 } 9748 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 9749 { 9750 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}})) 9751 { 9752 delete($TypeInfo{$LibVersion}{$Tid}); 9753 next; 9754 } 9755 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"}); 9756 foreach my $Attr ("Header", "Line", "Size", "NameSpace") 9757 { 9758 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) { 9759 delete($TypeInfo{$LibVersion}{$Tid}{$Attr}); 9760 } 9761 } 9762 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) { 9763 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"}); 9764 } 9765 } 9766} 9767 9768sub pickType($$) 9769{ 9770 my ($Tid, $LibVersion) = @_; 9771 9772 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid}) 9773 { 9774 if(defined $TypeInfo{$LibVersion}{$Dupl}) 9775 { 9776 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"}) 9777 { # duplicate 9778 return 0; 9779 } 9780 } 9781 } 9782 9783 my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}; 9784 9785 if(isBuiltIn($THeader)) { 9786 return 0; 9787 } 9788 9789 if($TypeInfo{$LibVersion}{$Tid}{"Type"}!~/Class|Struct|Union|Enum|Typedef/) { 9790 return 0; 9791 } 9792 9793 if(isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"})) { 9794 return 0; 9795 } 9796 9797 if(selfTypedef($Tid, $LibVersion)) { 9798 return 0; 9799 } 9800 9801 if(not isTargetType($Tid, $LibVersion)) { 9802 return 0; 9803 } 9804 9805 return 0; 9806} 9807 9808sub isTargetType($$) 9809{ 9810 my ($Tid, $LibVersion) = @_; 9811 9812 if($TypeInfo{$LibVersion}{$Tid}{"Type"}!~/Class|Struct|Union|Enum|Typedef/) 9813 { # derived 9814 return 1; 9815 } 9816 9817 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}) 9818 { # NOTE: header is defined to source if undefined (DWARF dumps) 9819 if(not is_target_header($THeader, $LibVersion)) 9820 { # from target headers 9821 return 0; 9822 } 9823 } 9824 else 9825 { # NOTE: if type is defined in source 9826 if($UsedDump{$LibVersion}{"Public"}) 9827 { 9828 if(isPrivateABI($Tid, $LibVersion)) { 9829 return 0; 9830 } 9831 else { 9832 return 1; 9833 } 9834 } 9835 else { 9836 return 0; 9837 } 9838 } 9839 9840 if($SkipInternalTypes) 9841 { 9842 if($TypeInfo{$LibVersion}{$Tid}{"Name"}=~/($SkipInternalTypes)/) 9843 { 9844 return 0; 9845 } 9846 } 9847 9848 return 1; 9849} 9850 9851sub remove_Unused($$) 9852{ # remove unused data types from the ABI dump 9853 my ($LibVersion, $Kind) = @_; 9854 9855 my %UsedType = (); 9856 9857 foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}})) 9858 { 9859 register_SymbolUsage($InfoId, \%UsedType, $LibVersion); 9860 } 9861 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9862 { 9863 if($UsedType{$Tid}) 9864 { # All & Extended 9865 next; 9866 } 9867 9868 if($Kind eq "Extended") 9869 { 9870 if(pickType($Tid, $LibVersion)) 9871 { 9872 my %Tree = (); 9873 register_TypeUsage($Tid, \%Tree, $LibVersion); 9874 9875 my $Tmpl = 0; 9876 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9877 { 9878 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9879 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 9880 { 9881 $Tmpl = 1; 9882 last; 9883 } 9884 } 9885 if(not $Tmpl) 9886 { 9887 foreach (keys(%Tree)) { 9888 $UsedType{$_} = 1; 9889 } 9890 } 9891 } 9892 } 9893 } 9894 9895 my %Delete = (); 9896 9897 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9898 { # remove unused types 9899 if($UsedType{$Tid}) 9900 { # All & Extended 9901 next; 9902 } 9903 9904 if($Kind eq "Extra") 9905 { 9906 my %Tree = (); 9907 register_TypeUsage($Tid, \%Tree, $LibVersion); 9908 9909 foreach (sort {int($a)<=>int($b)} keys(%Tree)) 9910 { 9911 if(defined $TypeInfo{$LibVersion}{$_}{"Template"} 9912 or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") 9913 { 9914 $Delete{$Tid} = 1; 9915 last; 9916 } 9917 } 9918 } 9919 else 9920 { 9921 # remove type 9922 delete($TypeInfo{$LibVersion}{$Tid}); 9923 } 9924 } 9925 9926 if($Kind eq "Extra") 9927 { # remove duplicates 9928 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 9929 { 9930 if($UsedType{$Tid}) 9931 { # All & Extended 9932 next; 9933 } 9934 9935 my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 9936 9937 if($TName_Tid{$LibVersion}{$Name} ne $Tid) { 9938 delete($TypeInfo{$LibVersion}{$Tid}); 9939 } 9940 } 9941 } 9942 9943 foreach my $Tid (keys(%Delete)) 9944 { 9945 delete($TypeInfo{$LibVersion}{$Tid}); 9946 } 9947} 9948 9949sub check_Completeness($$) 9950{ 9951 my ($Info, $LibVersion) = @_; 9952 9953 # data types 9954 if(defined $Info->{"Memb"}) 9955 { 9956 foreach my $Pos (keys(%{$Info->{"Memb"}})) 9957 { 9958 if(defined $Info->{"Memb"}{$Pos}{"type"}) { 9959 check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion); 9960 } 9961 } 9962 } 9963 if(defined $Info->{"Base"}) 9964 { 9965 foreach my $Bid (keys(%{$Info->{"Base"}})) { 9966 check_TypeInfo($Bid, $LibVersion); 9967 } 9968 } 9969 if(defined $Info->{"BaseType"}) { 9970 check_TypeInfo($Info->{"BaseType"}, $LibVersion); 9971 } 9972 if(defined $Info->{"TParam"}) 9973 { 9974 foreach my $Pos (keys(%{$Info->{"TParam"}})) 9975 { 9976 my $TName = $Info->{"TParam"}{$Pos}{"name"}; 9977 if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) { 9978 next; 9979 } 9980 if($TName eq "_BoolType") { 9981 next; 9982 } 9983 if($TName=~/\Asizeof\(/) { 9984 next; 9985 } 9986 if(my $Tid = $TName_Tid{$LibVersion}{$TName}) { 9987 check_TypeInfo($Tid, $LibVersion); 9988 } 9989 else 9990 { 9991 if(defined $Debug) { 9992 printMsg("WARNING", "missed type $TName"); 9993 } 9994 } 9995 } 9996 } 9997 9998 # symbols 9999 if(defined $Info->{"Param"}) 10000 { 10001 foreach my $Pos (keys(%{$Info->{"Param"}})) 10002 { 10003 if(defined $Info->{"Param"}{$Pos}{"type"}) { 10004 check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion); 10005 } 10006 } 10007 } 10008 if(defined $Info->{"Return"}) { 10009 check_TypeInfo($Info->{"Return"}, $LibVersion); 10010 } 10011 if(defined $Info->{"Class"}) { 10012 check_TypeInfo($Info->{"Class"}, $LibVersion); 10013 } 10014} 10015 10016sub check_TypeInfo($$) 10017{ 10018 my ($Tid, $LibVersion) = @_; 10019 10020 if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) { 10021 return; 10022 } 10023 $CheckedTypeInfo{$LibVersion}{$Tid} = 1; 10024 10025 if(defined $TypeInfo{$LibVersion}{$Tid}) 10026 { 10027 if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) { 10028 printMsg("ERROR", "missed type name ($Tid)"); 10029 } 10030 check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion); 10031 } 10032 else { 10033 printMsg("ERROR", "missed type id $Tid"); 10034 } 10035} 10036 10037sub selfTypedef($$) 10038{ 10039 my ($TypeId, $LibVersion) = @_; 10040 my %Type = get_Type($TypeId, $LibVersion); 10041 if($Type{"Type"} eq "Typedef") 10042 { 10043 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion}); 10044 if($Base{"Type"}=~/Class|Struct/) 10045 { 10046 if($Type{"Name"} eq $Base{"Name"}) { 10047 return 1; 10048 } 10049 elsif($Type{"Name"}=~/::(\w+)\Z/) 10050 { 10051 if($Type{"Name"} eq $Base{"Name"}."::".$1) 10052 { # QPointer<QWidget>::QPointer 10053 return 1; 10054 } 10055 } 10056 } 10057 } 10058 return 0; 10059} 10060 10061sub addExtension($) 10062{ 10063 my $LibVersion = $_[0]; 10064 foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 10065 { 10066 if(pickType($Tid, $LibVersion)) 10067 { 10068 my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"}; 10069 $TName=~s/\A(struct|union|class|enum) //; 10070 my $Symbol = "external_func_".$TName; 10071 10072 %{$CompleteSignature{$LibVersion}{$Symbol}} = ( 10073 "Header" => "extended.h", 10074 "ShortName" => $Symbol, 10075 "MnglName" => $Symbol, 10076 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } } 10077 ); 10078 10079 $ExtendedSymbols{$Symbol} = 1; 10080 $CheckedSymbols{"Binary"}{$Symbol} = 1; 10081 $CheckedSymbols{"Source"}{$Symbol} = 1; 10082 } 10083 } 10084 $ExtendedSymbols{"external_func_0"} = 1; 10085 $CheckedSymbols{"Binary"}{"external_func_0"} = 1; 10086 $CheckedSymbols{"Source"}{"external_func_0"} = 1; 10087} 10088 10089sub findMethod($$$) 10090{ 10091 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10092 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}})) 10093 { 10094 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) { 10095 return $VirtMethodInClass; 10096 } 10097 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) { 10098 return $VirtMethodInBaseClasses; 10099 } 10100 } 10101 return ""; 10102} 10103 10104sub findMethod_Class($$$) 10105{ 10106 my ($VirtFunc, $ClassId, $LibVersion) = @_; 10107 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 10108 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName}); 10109 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1); 10110 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"}; 10111 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10112 { # search for interface with the same parameters suffix (overridden) 10113 if($TargetSuffix eq get_symbol_suffix($Candidate, 1)) 10114 { 10115 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) 10116 { 10117 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) 10118 { 10119 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/) 10120 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/) 10121 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) { 10122 return $Candidate; 10123 } 10124 } 10125 } 10126 else 10127 { 10128 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) { 10129 return $Candidate; 10130 } 10131 } 10132 } 10133 } 10134 return ""; 10135} 10136 10137sub registerVTable($) 10138{ 10139 my $LibVersion = $_[0]; 10140 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) 10141 { 10142 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"} 10143 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"}) 10144 { 10145 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"}; 10146 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/); 10147 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"} 10148 and $Symbol=~/D2E/) 10149 { # pure virtual D2-destructors are marked as "virt" in the dump 10150 # virtual D2-destructors are NOT marked as "virt" in the dump 10151 # both destructors are not presented in the v-table 10152 next; 10153 } 10154 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 10155 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1; 10156 } 10157 } 10158} 10159 10160sub registerOverriding($) 10161{ 10162 my $LibVersion = $_[0]; 10163 my @Classes = keys(%{$VirtualTable{$LibVersion}}); 10164 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes; 10165 foreach my $ClassName (@Classes) 10166 { 10167 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10168 { 10169 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"}) 10170 { # pure virtuals 10171 next; 10172 } 10173 my $ClassId = $TName_Tid{$LibVersion}{$ClassName}; 10174 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion)) 10175 { 10176 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"} 10177 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"}) 10178 { # both overridden virtual methods 10179 # and implemented pure virtual methods 10180 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden; 10181 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1; 10182 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model 10183 } 10184 } 10185 } 10186 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { 10187 delete($VirtualTable{$LibVersion}{$ClassName}); 10188 } 10189 } 10190} 10191 10192sub setVirtFuncPositions($) 10193{ 10194 my $LibVersion = $_[0]; 10195 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}})) 10196 { 10197 my ($Num, $Rel) = (1, 0); 10198 10199 if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}})) 10200 { 10201 if($UsedDump{$LibVersion}{"DWARF"}) { 10202 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs; 10203 } 10204 else { 10205 @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs; 10206 } 10207 foreach my $VirtFunc (@Funcs) 10208 { 10209 if($UsedDump{$LibVersion}{"DWARF"}) { 10210 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"}; 10211 } 10212 else { 10213 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++; 10214 } 10215 10216 # set relative positions 10217 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc} 10218 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc}) 10219 { # relative position excluding added and removed virtual functions 10220 if(not $CompleteSignature{1}{$VirtFunc}{"Override"} 10221 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) { 10222 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++; 10223 } 10224 } 10225 } 10226 } 10227 } 10228 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}})) 10229 { 10230 my $AbsNum = 1; 10231 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) { 10232 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++; 10233 } 10234 } 10235} 10236 10237sub get_sub_classes($$$) 10238{ 10239 my ($ClassId, $LibVersion, $Recursive) = @_; 10240 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId}); 10241 my @Subs = (); 10242 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 10243 { 10244 if($Recursive) 10245 { 10246 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) { 10247 push(@Subs, $SubSubId); 10248 } 10249 } 10250 push(@Subs, $SubId); 10251 } 10252 return @Subs; 10253} 10254 10255sub get_base_classes($$$) 10256{ 10257 my ($ClassId, $LibVersion, $Recursive) = @_; 10258 my %ClassType = get_Type($ClassId, $LibVersion); 10259 return () if(not defined $ClassType{"Base"}); 10260 my @Bases = (); 10261 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})} 10262 keys(%{$ClassType{"Base"}})) 10263 { 10264 if($Recursive) 10265 { 10266 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) { 10267 push(@Bases, $SubBaseId); 10268 } 10269 } 10270 push(@Bases, $BaseId); 10271 } 10272 return @Bases; 10273} 10274 10275sub getVTable_Model($$) 10276{ # return an ordered list of v-table elements 10277 my ($ClassId, $LibVersion) = @_; 10278 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10279 my @Elements = (); 10280 foreach my $BaseId (@Bases, $ClassId) 10281 { 10282 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10283 { 10284 if(defined $VirtualTable{$LibVersion}{$BName}) 10285 { 10286 my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}}); 10287 if($UsedDump{$LibVersion}{"DWARF"}) { 10288 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs; 10289 } 10290 else { 10291 @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs; 10292 } 10293 foreach my $VFunc (@VFuncs) { 10294 push(@Elements, $VFunc); 10295 } 10296 } 10297 } 10298 } 10299 return @Elements; 10300} 10301 10302sub getVShift($$) 10303{ 10304 my ($ClassId, $LibVersion) = @_; 10305 my @Bases = get_base_classes($ClassId, $LibVersion, 1); 10306 my $VShift = 0; 10307 foreach my $BaseId (@Bases) 10308 { 10309 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) 10310 { 10311 if(defined $VirtualTable{$LibVersion}{$BName}) { 10312 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}}); 10313 } 10314 } 10315 } 10316 return $VShift; 10317} 10318 10319sub getShift($$) 10320{ 10321 my ($ClassId, $LibVersion) = @_; 10322 my @Bases = get_base_classes($ClassId, $LibVersion, 0); 10323 my $Shift = 0; 10324 foreach my $BaseId (@Bases) 10325 { 10326 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"}) 10327 { 10328 if($Size!=1) 10329 { # not empty base class 10330 $Shift+=$Size; 10331 } 10332 } 10333 } 10334 return $Shift; 10335} 10336 10337sub getVTable_Size($$) 10338{ # number of v-table elements 10339 my ($ClassName, $LibVersion) = @_; 10340 my $Size = 0; 10341 # three approaches 10342 if(not $Size) 10343 { # real size 10344 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) { 10345 $Size = keys(%VTable); 10346 } 10347 } 10348 if(not $Size) 10349 { # shared library symbol size 10350 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) { 10351 $Size /= $WORD_SIZE{$LibVersion}; 10352 } 10353 } 10354 if(not $Size) 10355 { # model size 10356 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) { 10357 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2; 10358 } 10359 } 10360 return $Size; 10361} 10362 10363sub isCopyingClass($$) 10364{ 10365 my ($TypeId, $LibVersion) = @_; 10366 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"}; 10367} 10368 10369sub isLeafClass($$) 10370{ 10371 my ($ClassId, $LibVersion) = @_; 10372 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})); 10373} 10374 10375sub havePubFields($) 10376{ # check structured type for public fields 10377 return isAccessible($_[0], {}, 0, -1); 10378} 10379 10380sub isAccessible($$$$) 10381{ # check interval in structured type for public fields 10382 my ($TypePtr, $Skip, $Start, $End) = @_; 10383 return 0 if(not $TypePtr); 10384 if($End==-1) { 10385 $End = keys(%{$TypePtr->{"Memb"}})-1; 10386 } 10387 foreach my $MemPos (sort {int($a)<=>int($b)} keys(%{$TypePtr->{"Memb"}})) 10388 { 10389 if($Skip and $Skip->{$MemPos}) 10390 { # skip removed/added fields 10391 next; 10392 } 10393 if(int($MemPos)>=$Start and int($MemPos)<=$End) 10394 { 10395 if(isPublic($TypePtr, $MemPos)) { 10396 return ($MemPos+1); 10397 } 10398 } 10399 } 10400 return 0; 10401} 10402 10403sub isReserved($) 10404{ # reserved fields == private 10405 my $MName = $_[0]; 10406 if($MName=~/reserved|padding|f_spare/i) { 10407 return 1; 10408 } 10409 if($MName=~/\A[_]*(spare|pad|unused|dummy)[_\d]*\Z/i) { 10410 return 1; 10411 } 10412 if($MName=~/(pad\d+)/i) { 10413 return 1; 10414 } 10415 return 0; 10416} 10417 10418sub isPublic($$) 10419{ 10420 my ($TypePtr, $FieldPos) = @_; 10421 return 0 if(not $TypePtr); 10422 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}); 10423 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"}); 10424 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"}) 10425 { # by name in C language 10426 # FIXME: add other methods to detect private members 10427 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"}; 10428 if($MName=~/priv|abidata|parent_object/i) 10429 { # C-styled private data 10430 return 0; 10431 } 10432 if(lc($MName) eq "abi") 10433 { # ABI information/reserved field 10434 return 0; 10435 } 10436 if(isReserved($MName)) 10437 { # reserved fields 10438 return 0; 10439 } 10440 return 1; 10441 } 10442 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private") 10443 { # by access in C++ language 10444 return 1; 10445 } 10446 return 0; 10447} 10448 10449sub getVTable_Real($$) 10450{ 10451 my ($ClassName, $LibVersion) = @_; 10452 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) 10453 { 10454 my %Type = get_Type($ClassId, $LibVersion); 10455 if(defined $Type{"VTable"}) { 10456 return %{$Type{"VTable"}}; 10457 } 10458 } 10459 return (); 10460} 10461 10462sub cmpVTables($) 10463{ 10464 my $ClassName = $_[0]; 10465 my $Res = cmpVTables_Real($ClassName, 1); 10466 if($Res==-1) { 10467 $Res = cmpVTables_Model($ClassName); 10468 } 10469 return $Res; 10470} 10471 10472sub cmpVTables_Model($) 10473{ 10474 my $ClassName = $_[0]; 10475 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}})) 10476 { 10477 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) { 10478 return 1; 10479 } 10480 } 10481 return 0; 10482} 10483 10484sub cmpVTables_Real($$) 10485{ 10486 my ($ClassName, $Strong) = @_; 10487 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) { 10488 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}; 10489 } 10490 my %VTable_Old = getVTable_Real($ClassName, 1); 10491 my %VTable_New = getVTable_Real($ClassName, 2); 10492 if(not %VTable_Old or not %VTable_New) 10493 { # old ABI dumps 10494 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1); 10495 } 10496 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New)); 10497 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes)) 10498 { 10499 if(not defined $VTable_Old{$Offset}) 10500 { # v-table v.1 < v-table v.2 10501 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong); 10502 } 10503 my $Entry1 = $VTable_Old{$Offset}; 10504 if(not defined $VTable_New{$Offset}) 10505 { # v-table v.1 > v-table v.2 10506 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/)); 10507 } 10508 my $Entry2 = $VTable_New{$Offset}; 10509 10510 $Entry1 = simpleVEntry($Entry1); 10511 $Entry2 = simpleVEntry($Entry2); 10512 10513 if($Entry1=~/ 0x/ or $Entry2=~/ 0x/) 10514 { # NOTE: problem with vtable-dumper 10515 next; 10516 } 10517 10518 if($Entry1 ne $Entry2) 10519 { # register as changed 10520 if($Entry1=~/::([^:]+)\Z/) 10521 { 10522 my $M1 = $1; 10523 if($Entry2=~/::([^:]+)\Z/) 10524 { 10525 my $M2 = $1; 10526 if($M1 eq $M2) 10527 { # overridden 10528 next; 10529 } 10530 } 10531 } 10532 if(differentDumps("G")) 10533 { 10534 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/) 10535 { 10536 # GCC 4.6.1: -0x00000000000000010 10537 # GCC 4.7.0: -16 10538 next; 10539 } 10540 } 10541 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1); 10542 } 10543 } 10544 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0); 10545} 10546 10547sub mergeVTables($) 10548{ # merging v-tables without diagnostics 10549 my $Level = $_[0]; 10550 foreach my $ClassName (keys(%{$VirtualTable{1}})) 10551 { 10552 my $ClassId = $TName_Tid{1}{$ClassName}; 10553 if(isPrivateABI($ClassId, 1)) { 10554 next; 10555 } 10556 10557 if($VTableChanged_M{$ClassName}) 10558 { # already registered 10559 next; 10560 } 10561 if(cmpVTables_Real($ClassName, 0)==1) 10562 { 10563 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10564 foreach my $Symbol (@Affected) 10565 { 10566 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=( 10567 "Type_Name"=>$ClassName, 10568 "Target"=>$ClassName); 10569 } 10570 } 10571 } 10572} 10573 10574sub mergeBases($) 10575{ 10576 my $Level = $_[0]; 10577 foreach my $ClassName (keys(%{$ClassNames{1}})) 10578 { # detect added and removed virtual functions 10579 my $ClassId = $TName_Tid{1}{$ClassName}; 10580 next if(not $ClassId); 10581 10582 if(isPrivateABI($ClassId, 1)) { 10583 next; 10584 } 10585 10586 if(defined $VirtualTable{2}{$ClassName}) 10587 { 10588 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}})) 10589 { 10590 if($TName_Tid{1}{$ClassName} 10591 and not defined $VirtualTable{1}{$ClassName}{$Symbol}) 10592 { # added to v-table 10593 if(defined $CompleteSignature{1}{$Symbol} 10594 and $CompleteSignature{1}{$Symbol}{"Virt"}) 10595 { # override some method in v.1 10596 next; 10597 } 10598 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10599 } 10600 } 10601 } 10602 if(defined $VirtualTable{1}{$ClassName}) 10603 { 10604 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}})) 10605 { 10606 if($TName_Tid{2}{$ClassName} 10607 and not defined $VirtualTable{2}{$ClassName}{$Symbol}) 10608 { # removed from v-table 10609 if(defined $CompleteSignature{2}{$Symbol} 10610 and $CompleteSignature{2}{$Symbol}{"Virt"}) 10611 { # override some method in v.2 10612 next; 10613 } 10614 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; 10615 } 10616 } 10617 } 10618 if($Level eq "Binary") 10619 { # Binary-level 10620 my %Class_Type = get_Type($ClassId, 1); 10621 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}})) 10622 { # check replacements, including pure virtual methods 10623 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc}; 10624 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}})) 10625 { 10626 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc}; 10627 if($AddedPos==$RemovedPos) 10628 { 10629 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc; 10630 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc; 10631 last; # other methods will be reported as "added" or "removed" 10632 } 10633 } 10634 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc}) 10635 { 10636 if(lc($AddedVFunc) eq lc($RemovedVFunc)) 10637 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0) 10638 next; 10639 } 10640 my $ProblemType = "Virtual_Replacement"; 10641 my @Affected = ($RemovedVFunc); 10642 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 10643 { # pure methods 10644 if(not isUsedClass($ClassId, 1, $Level)) 10645 { # not a parameter of some exported method 10646 next; 10647 } 10648 $ProblemType = "Pure_Virtual_Replacement"; 10649 10650 # affected all methods (both virtual and non-virtual ones) 10651 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); 10652 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}})); 10653 } 10654 $VTableChanged_M{$ClassName}=1; 10655 foreach my $AffectedInt (@Affected) 10656 { 10657 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"}) 10658 { # affected exported methods only 10659 next; 10660 } 10661 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) { 10662 next; 10663 } 10664 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 10665 "Type_Name"=>$Class_Type{"Name"}, 10666 "Target"=>get_Signature($AddedVFunc, 2), 10667 "Old_Value"=>get_Signature($RemovedVFunc, 1)); 10668 } 10669 } 10670 } 10671 } 10672 } 10673 if(not checkDump(1, "2.0") 10674 or not checkDump(2, "2.0")) 10675 { # support for old ABI dumps 10676 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format) 10677 return; 10678 } 10679 foreach my $ClassName (sort keys(%{$ClassNames{1}})) 10680 { 10681 my $ClassId_Old = $TName_Tid{1}{$ClassName}; 10682 next if(not $ClassId_Old); 10683 10684 if(isPrivateABI($ClassId_Old, 1)) { 10685 next; 10686 } 10687 10688 if(not isCreatable($ClassId_Old, 1)) 10689 { # skip classes without public constructors (including auto-generated) 10690 # example: class has only a private exported or private inline constructor 10691 next; 10692 } 10693 if($ClassName=~/>/) 10694 { # skip affected template instances 10695 next; 10696 } 10697 my %Class_Old = get_Type($ClassId_Old, 1); 10698 my $ClassId_New = $TName_Tid{2}{$ClassName}; 10699 if(not $ClassId_New) { 10700 next; 10701 } 10702 my %Class_New = get_Type($ClassId_New, 2); 10703 if($Class_New{"Type"}!~/Class|Struct/) 10704 { # became typedef 10705 if($Level eq "Binary") { 10706 next; 10707 } 10708 if($Level eq "Source") 10709 { 10710 %Class_New = get_PureType($ClassId_New, $TypeInfo{2}); 10711 if($Class_New{"Type"}!~/Class|Struct/) { 10712 next; 10713 } 10714 $ClassId_New = $Class_New{"Tid"}; 10715 } 10716 } 10717 10718 if(not $Class_New{"Size"} or not $Class_Old{"Size"}) 10719 { # incomplete info in the ABI dump 10720 next; 10721 } 10722 10723 10724 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}}); 10725 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}}); 10726 10727 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old; 10728 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New; 10729 10730 my ($BNum1, $BNum2) = (1, 1); 10731 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old; 10732 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New; 10733 my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old; 10734 my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New; 10735 my $Shift_Old = getShift($ClassId_Old, 1); 10736 my $Shift_New = getShift($ClassId_New, 2); 10737 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New; 10738 my ($Added, $Removed) = (0, 0); 10739 my @StableBases_Old = (); 10740 foreach my $BaseId (@Bases_Old) 10741 { 10742 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10743 if($BasePos_New{$Tr_Old{$BaseName}}) { 10744 push(@StableBases_Old, $BaseId); 10745 } 10746 elsif(not $ShortBase_New{$Tr_Old{$BaseName}} 10747 and not $ShortBase_New{get_ShortClass($BaseId, 1)}) 10748 { # removed base 10749 # excluding namespace::SomeClass to SomeClass renaming 10750 my $ProblemKind = "Removed_Base_Class"; 10751 if($Level eq "Binary") 10752 { # Binary-level 10753 if($Shift_Old ne $Shift_New) 10754 { # affected fields 10755 if(havePubFields(\%Class_Old)) { 10756 $ProblemKind .= "_And_Shift"; 10757 } 10758 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10759 $ProblemKind .= "_And_Size"; 10760 } 10761 } 10762 if(keys(%{$VirtualTable_Model{1}{$BaseName}}) 10763 and cmpVTables($ClassName)==1) 10764 { # affected v-table 10765 $ProblemKind .= "_And_VTable"; 10766 $VTableChanged_M{$ClassName}=1; 10767 } 10768 } 10769 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10770 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10771 { 10772 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10773 { 10774 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10775 if($ProblemKind=~/VTable/) { 10776 $VTableChanged_M{$SubName}=1; 10777 } 10778 } 10779 } 10780 foreach my $Interface (@Affected) 10781 { 10782 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10783 next; 10784 } 10785 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10786 "Type_Name"=>$ClassName, 10787 "Target"=>$BaseName, 10788 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10789 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10790 "Shift"=>abs($Shift_New-$Shift_Old) ); 10791 } 10792 $Removed+=1; 10793 } 10794 } 10795 my @StableBases_New = (); 10796 foreach my $BaseId (@Bases_New) 10797 { 10798 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"}; 10799 if($BasePos_Old{$Tr_New{$BaseName}}) { 10800 push(@StableBases_New, $BaseId); 10801 } 10802 elsif(not $ShortBase_Old{$Tr_New{$BaseName}} 10803 and not $ShortBase_Old{get_ShortClass($BaseId, 2)}) 10804 { # added base 10805 # excluding namespace::SomeClass to SomeClass renaming 10806 my $ProblemKind = "Added_Base_Class"; 10807 if($Level eq "Binary") 10808 { # Binary-level 10809 if($Shift_Old ne $Shift_New) 10810 { # affected fields 10811 if(havePubFields(\%Class_Old)) { 10812 $ProblemKind .= "_And_Shift"; 10813 } 10814 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { 10815 $ProblemKind .= "_And_Size"; 10816 } 10817 } 10818 if(keys(%{$VirtualTable_Model{2}{$BaseName}}) 10819 and cmpVTables($ClassName)==1) 10820 { # affected v-table 10821 $ProblemKind .= "_And_VTable"; 10822 $VTableChanged_M{$ClassName}=1; 10823 } 10824 } 10825 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); 10826 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) 10827 { 10828 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) 10829 { 10830 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); 10831 if($ProblemKind=~/VTable/) { 10832 $VTableChanged_M{$SubName}=1; 10833 } 10834 } 10835 } 10836 foreach my $Interface (@Affected) 10837 { 10838 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10839 next; 10840 } 10841 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( 10842 "Type_Name"=>$ClassName, 10843 "Target"=>$BaseName, 10844 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, 10845 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, 10846 "Shift"=>abs($Shift_New-$Shift_Old) ); 10847 } 10848 $Added+=1; 10849 } 10850 } 10851 if($Level eq "Binary") 10852 { # Binary-level 10853 ($BNum1, $BNum2) = (1, 1); 10854 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old; 10855 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New; 10856 foreach my $BaseId (@Bases_Old) 10857 { 10858 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; 10859 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}}) 10860 { 10861 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}}; 10862 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}}; 10863 if($NewPos!=$OldPos) 10864 { # changed position of the base class 10865 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10866 { 10867 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10868 next; 10869 } 10870 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=( 10871 "Type_Name"=>$ClassName, 10872 "Target"=>$BaseName, 10873 "Old_Value"=>$OldPos-1, 10874 "New_Value"=>$NewPos-1 ); 10875 } 10876 } 10877 if($Class_Old{"Base"}{$BaseId}{"virtual"} 10878 and not $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10879 { # became non-virtual base 10880 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10881 { 10882 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10883 next; 10884 } 10885 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=( 10886 "Type_Name"=>$ClassName, 10887 "Target"=>$BaseName ); 10888 } 10889 } 10890 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"} 10891 and $Class_New{"Base"}{$BaseNewId}{"virtual"}) 10892 { # became virtual base 10893 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10894 { 10895 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10896 next; 10897 } 10898 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=( 10899 "Type_Name"=>$ClassName, 10900 "Target"=>$BaseName ); 10901 } 10902 } 10903 } 10904 } 10905 # detect size changes in base classes 10906 if($Shift_Old!=$Shift_New) 10907 { # size of allocable class 10908 foreach my $BaseId (@StableBases_Old) 10909 { # search for changed base 10910 my %BaseType = get_Type($BaseId, 1); 10911 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"}; 10912 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"}; 10913 if($Size_Old ne $Size_New 10914 and $Size_Old and $Size_New) 10915 { 10916 my $ProblemType = undef; 10917 if(isCopyingClass($BaseId, 1)) { 10918 $ProblemType = "Size_Of_Copying_Class"; 10919 } 10920 elsif($AllocableClass{1}{$BaseType{"Name"}}) 10921 { 10922 if($Size_New>$Size_Old) 10923 { # increased size 10924 $ProblemType = "Size_Of_Allocable_Class_Increased"; 10925 } 10926 else 10927 { # decreased size 10928 $ProblemType = "Size_Of_Allocable_Class_Decreased"; 10929 if(not havePubFields(\%Class_Old)) 10930 { # affected class has no public members 10931 next; 10932 } 10933 } 10934 } 10935 next if(not $ProblemType); 10936 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) 10937 { # base class size changes affecting current class 10938 if(not symbolFilter($Interface, 1, "Affected", $Level)) { 10939 next; 10940 } 10941 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=( 10942 "Type_Name"=>$BaseType{"Name"}, 10943 "Target"=>$BaseType{"Name"}, 10944 "Old_Size"=>$Size_Old*$BYTE_SIZE, 10945 "New_Size"=>$Size_New*$BYTE_SIZE ); 10946 } 10947 } 10948 } 10949 } 10950 if(defined $VirtualTable_Model{1}{$ClassName} 10951 and cmpVTables_Real($ClassName, 1)==1 10952 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}})) 10953 { # compare virtual tables size in base classes 10954 my $VShift_Old = getVShift($ClassId_Old, 1); 10955 my $VShift_New = getVShift($ClassId_New, 2); 10956 if($VShift_Old ne $VShift_New) 10957 { # changes in the base class or changes in the list of base classes 10958 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1); 10959 my @AllBases_New = get_base_classes($ClassId_New, 2, 1); 10960 ($BNum1, $BNum2) = (1, 1); 10961 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New; 10962 foreach my $BaseId (@AllBases_Old) 10963 { 10964 my %BaseType = get_Type($BaseId, 1); 10965 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}}) 10966 { # lost base 10967 next; 10968 } 10969 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1); 10970 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2); 10971 if($VSize_Old!=$VSize_New) 10972 { 10973 foreach my $Symbol (@VFunctions) 10974 { # TODO: affected non-virtual methods? 10975 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) 10976 { # Removed_Virtual_Method, will be registered in mergeVirtualTables() 10977 next; 10978 } 10979 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0) 10980 { # skip interfaces that have not changed the absolute virtual position 10981 next; 10982 } 10983 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 10984 next; 10985 } 10986 $VTableChanged_M{$BaseType{"Name"}} = 1; 10987 $VTableChanged_M{$ClassName} = 1; 10988 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}})) 10989 { # the reason of the layout change: added virtual functions 10990 next if($VirtualReplacement{$VirtFunc}); 10991 my $ProblemType = "Added_Virtual_Method"; 10992 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) { 10993 $ProblemType = "Added_Pure_Virtual_Method"; 10994 } 10995 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=( 10996 "Type_Name"=>$BaseType{"Name"}, 10997 "Target"=>get_Signature($VirtFunc, 2) ); 10998 } 10999 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}})) 11000 { # the reason of the layout change: removed virtual functions 11001 next if($VirtualReplacement{$VirtFunc}); 11002 my $ProblemType = "Removed_Virtual_Method"; 11003 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) { 11004 $ProblemType = "Removed_Pure_Virtual_Method"; 11005 } 11006 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=( 11007 "Type_Name"=>$BaseType{"Name"}, 11008 "Target"=>get_Signature($VirtFunc, 1) ); 11009 } 11010 } 11011 } 11012 } 11013 } 11014 } 11015 } 11016 } 11017} 11018 11019sub isCreatable($$) 11020{ 11021 my ($ClassId, $LibVersion) = @_; 11022 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}} 11023 or isCopyingClass($ClassId, $LibVersion)) { 11024 return 1; 11025 } 11026 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) 11027 { # Fix for incomplete data: if this class has 11028 # a base class then it should also has a constructor 11029 return 1; 11030 } 11031 if($ReturnedClass{$LibVersion}{$ClassId}) 11032 { # returned by some method of this class 11033 # or any other class 11034 return 1; 11035 } 11036 return 0; 11037} 11038 11039sub isUsedClass($$$) 11040{ 11041 my ($ClassId, $LibVersion, $Level) = @_; 11042 if(keys(%{$ParamClass{$LibVersion}{$ClassId}})) 11043 { # parameter of some exported method 11044 return 1; 11045 } 11046 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 11047 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}})) 11048 { # method from target class 11049 return 1; 11050 } 11051 return 0; 11052} 11053 11054sub mergeVirtualTables($$) 11055{ # check for changes in the virtual table 11056 my ($Interface, $Level) = @_; 11057 # affected methods: 11058 # - virtual 11059 # - pure-virtual 11060 # - non-virtual 11061 if($CompleteSignature{1}{$Interface}{"Data"}) 11062 { # global data is not affected 11063 return; 11064 } 11065 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"}; 11066 if(not $Class_Id) { 11067 return; 11068 } 11069 my $CName = $TypeInfo{1}{$Class_Id}{"Name"}; 11070 if(cmpVTables_Real($CName, 1)==0) 11071 { # no changes 11072 return; 11073 } 11074 $CheckedTypes{$Level}{$CName} = 1; 11075 if($Level eq "Binary") 11076 { # Binary-level 11077 if($CompleteSignature{1}{$Interface}{"PureVirt"} 11078 and not isUsedClass($Class_Id, 1, $Level)) 11079 { # pure virtuals should not be affected 11080 # if there are no exported methods using this class 11081 return; 11082 } 11083 } 11084 foreach my $Func (keys(%{$VirtualTable{1}{$CName}})) 11085 { 11086 if(defined $VirtualTable{2}{$CName}{$Func} 11087 and defined $CompleteSignature{2}{$Func}) 11088 { 11089 if(not $CompleteSignature{1}{$Func}{"PureVirt"} 11090 and $CompleteSignature{2}{$Func}{"PureVirt"}) 11091 { # became pure virtual 11092 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=( 11093 "Type_Name"=>$CName, 11094 "Target"=>get_Signature_M($Func, 1) ); 11095 $VTableChanged_M{$CName} = 1; 11096 } 11097 elsif($CompleteSignature{1}{$Func}{"PureVirt"} 11098 and not $CompleteSignature{2}{$Func}{"PureVirt"}) 11099 { # became non-pure virtual 11100 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=( 11101 "Type_Name"=>$CName, 11102 "Target"=>get_Signature_M($Func, 1) ); 11103 $VTableChanged_M{$CName} = 1; 11104 } 11105 } 11106 } 11107 if($Level eq "Binary") 11108 { # Binary-level 11109 # check virtual table structure 11110 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11111 { 11112 next if($Interface eq $AddedVFunc); 11113 next if($VirtualReplacement{$AddedVFunc}); 11114 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc}; 11115 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11116 { # pure virtual methods affect all others (virtual and non-virtual) 11117 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11118 "Type_Name"=>$CName, 11119 "Target"=>get_Signature($AddedVFunc, 2) ); 11120 $VTableChanged_M{$CName} = 1; 11121 } 11122 elsif(not defined $VirtualTable{1}{$CName} 11123 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}})) 11124 { # added virtual function at the end of v-table 11125 if(not keys(%{$VirtualTable_Model{1}{$CName}})) 11126 { # became polymorphous class, added v-table pointer 11127 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11128 "Type_Name"=>$CName, 11129 "Target"=>get_Signature($AddedVFunc, 2) ); 11130 $VTableChanged_M{$CName} = 1; 11131 } 11132 else 11133 { 11134 my $VSize_Old = getVTable_Size($CName, 1); 11135 my $VSize_New = getVTable_Size($CName, 2); 11136 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method 11137 if(isCopyingClass($Class_Id, 1)) 11138 { # class has no constructors and v-table will be copied by applications, this may affect all methods 11139 my $ProblemType = "Added_Virtual_Method"; 11140 if(isLeafClass($Class_Id, 1)) { 11141 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class"; 11142 } 11143 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11144 "Type_Name"=>$CName, 11145 "Target"=>get_Signature($AddedVFunc, 2) ); 11146 $VTableChanged_M{$CName} = 1; 11147 } 11148 else 11149 { 11150 my $ProblemType = "Added_Virtual_Method"; 11151 if(isLeafClass($Class_Id, 1)) { 11152 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class"; 11153 } 11154 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( 11155 "Type_Name"=>$CName, 11156 "Target"=>get_Signature($AddedVFunc, 2) ); 11157 $VTableChanged_M{$CName} = 1; 11158 } 11159 } 11160 } 11161 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11162 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11163 { 11164 if(defined $VirtualTable{1}{$CName} 11165 and defined $VirtualTable{2}{$CName}) 11166 { 11167 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11168 my $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11169 11170 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New) 11171 { 11172 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11173 foreach my $ASymbol (@Affected) 11174 { 11175 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11176 { 11177 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11178 next; 11179 } 11180 } 11181 $CheckedSymbols{$Level}{$ASymbol} = 1; 11182 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11183 "Type_Name"=>$CName, 11184 "Target"=>get_Signature($AddedVFunc, 2) ); 11185 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11186 } 11187 } 11188 } 11189 } 11190 else { 11191 # safe 11192 } 11193 } 11194 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11195 { 11196 next if($VirtualReplacement{$RemovedVFunc}); 11197 if($RemovedVFunc eq $Interface 11198 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11199 { # This case is for removed virtual methods 11200 # implemented in both versions of a library 11201 next; 11202 } 11203 if(not keys(%{$VirtualTable_Model{2}{$CName}})) 11204 { # became non-polymorphous class, removed v-table pointer 11205 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11206 "Type_Name"=>$CName, 11207 "Target"=>get_Signature($RemovedVFunc, 1) ); 11208 $VTableChanged_M{$CName} = 1; 11209 } 11210 elsif($CompleteSignature{1}{$Interface}{"Virt"} 11211 or $CompleteSignature{1}{$Interface}{"PureVirt"}) 11212 { 11213 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName}) 11214 { 11215 if(not defined $VirtualTable{1}{$CName}{$Interface}) { 11216 next; 11217 } 11218 my $VPos_New = -1; 11219 if(defined $VirtualTable{2}{$CName}{$Interface}) 11220 { 11221 $VPos_New = $VirtualTable{2}{$CName}{$Interface}; 11222 } 11223 else 11224 { 11225 if($Interface ne $RemovedVFunc) { 11226 next; 11227 } 11228 } 11229 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc}; 11230 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; 11231 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New) 11232 { 11233 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); 11234 foreach my $ASymbol (@Affected) 11235 { 11236 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) 11237 { 11238 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 11239 next; 11240 } 11241 } 11242 my $ProblemType = "Removed_Virtual_Method"; 11243 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { 11244 $ProblemType = "Removed_Pure_Virtual_Method"; 11245 } 11246 $CheckedSymbols{$Level}{$ASymbol} = 1; 11247 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=( 11248 "Type_Name"=>$CName, 11249 "Target"=>get_Signature($RemovedVFunc, 1) ); 11250 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; 11251 } 11252 } 11253 } 11254 } 11255 } 11256 } 11257 else 11258 { # Source-level 11259 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) 11260 { 11261 next if($Interface eq $AddedVFunc); 11262 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) 11263 { 11264 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( 11265 "Type_Name"=>$CName, 11266 "Target"=>get_Signature($AddedVFunc, 2) ); 11267 } 11268 } 11269 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) 11270 { 11271 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) 11272 { 11273 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( 11274 "Type_Name"=>$CName, 11275 "Target"=>get_Signature($RemovedVFunc, 1) ); 11276 } 11277 } 11278 } 11279} 11280 11281sub find_MemberPair_Pos_byName($$) 11282{ 11283 my ($Member_Name, $Pair_Type) = @_; 11284 $Member_Name=~s/\A[_]+|[_]+\Z//g; 11285 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11286 { 11287 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}) 11288 { 11289 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"}; 11290 $Name=~s/\A[_]+|[_]+\Z//g; 11291 if($Name eq $Member_Name) { 11292 return $MemberPair_Pos; 11293 } 11294 } 11295 } 11296 return "lost"; 11297} 11298 11299sub find_MemberPair_Pos_byVal($$) 11300{ 11301 my ($Member_Value, $Pair_Type) = @_; 11302 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) 11303 { 11304 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos} 11305 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) { 11306 return $MemberPair_Pos; 11307 } 11308 } 11309 return "lost"; 11310} 11311 11312sub isRecurType($$$) 11313{ 11314 foreach (@{$_[2]}) 11315 { 11316 if( $_->{"T1"} eq $_[0] 11317 and $_->{"T2"} eq $_[1] ) 11318 { 11319 return 1; 11320 } 11321 } 11322 return 0; 11323} 11324 11325sub pushType($$$) 11326{ 11327 my %IDs = ( 11328 "T1" => $_[0], 11329 "T2" => $_[1] 11330 ); 11331 push(@{$_[2]}, \%IDs); 11332} 11333 11334sub isRenamed($$$$$) 11335{ 11336 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_; 11337 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"}; 11338 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"}; 11339 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1}); 11340 if(not defined $Type2->{"Memb"}{$MemPos}) { 11341 return ""; 11342 } 11343 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"}; 11344 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2}); 11345 11346 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"}; 11347 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1); 11348 if($MemberPair_Pos_Rev eq "lost") 11349 { 11350 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"}) 11351 { # base type match 11352 return $Pair_Name; 11353 } 11354 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"}) 11355 { # exact type match 11356 return $Pair_Name; 11357 } 11358 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"}) 11359 { # size match 11360 return $Pair_Name; 11361 } 11362 if(isReserved($Pair_Name)) 11363 { # reserved fields 11364 return $Pair_Name; 11365 } 11366 } 11367 return ""; 11368} 11369 11370sub isLastElem($$) 11371{ 11372 my ($Pos, $TypeRef) = @_; 11373 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"}; 11374 if($Name=~/last|count|max|total/i) 11375 { # GST_LEVEL_COUNT, GST_RTSP_ELAST 11376 return 1; 11377 } 11378 elsif($Name=~/END|NLIMITS\Z/) 11379 { # __RLIMIT_NLIMITS 11380 return 1; 11381 } 11382 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/ 11383 and $Pos+1==keys(%{$TypeRef->{"Memb"}})) 11384 { # NImageFormats, NColorRoles 11385 return 1; 11386 } 11387 return 0; 11388} 11389 11390sub nonComparable($$) 11391{ 11392 my ($T1, $T2) = @_; 11393 11394 my $N1 = $T1->{"Name"}; 11395 my $N2 = $T2->{"Name"}; 11396 11397 $N1=~s/\A(struct|union|enum) //; 11398 $N2=~s/\A(struct|union|enum) //; 11399 11400 if($N1 ne $N2 11401 and not isAnon($N1) 11402 and not isAnon($N2)) 11403 { # different names 11404 if($T1->{"Type"} ne "Pointer" 11405 or $T2->{"Type"} ne "Pointer") 11406 { # compare base types 11407 return 1; 11408 } 11409 if($N1!~/\Avoid\s*\*/ 11410 and $N2=~/\Avoid\s*\*/) 11411 { 11412 return 1; 11413 } 11414 } 11415 elsif($T1->{"Type"} ne $T2->{"Type"}) 11416 { # different types 11417 if($T1->{"Type"} eq "Class" 11418 and $T2->{"Type"} eq "Struct") 11419 { # "class" to "struct" 11420 return 0; 11421 } 11422 elsif($T2->{"Type"} eq "Class" 11423 and $T1->{"Type"} eq "Struct") 11424 { # "struct" to "class" 11425 return 0; 11426 } 11427 else 11428 { # "class" to "enum" 11429 # "union" to "class" 11430 # ... 11431 return 1; 11432 } 11433 } 11434 return 0; 11435} 11436 11437sub isOpaque($) 11438{ 11439 my $T = $_[0]; 11440 if(not defined $T->{"Memb"}) 11441 { 11442 return 1; 11443 } 11444 return 0; 11445} 11446 11447sub removeVPtr($) 11448{ # support for old ABI dumps 11449 my $TPtr = $_[0]; 11450 my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}}); 11451 if($#Pos>=1) 11452 { 11453 foreach my $Pos (0 .. $#Pos-1) 11454 { 11455 %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}}; 11456 } 11457 delete($TPtr->{"Memb"}{$#Pos}); 11458 } 11459} 11460 11461sub isPrivateABI($$) 11462{ 11463 my ($TypeId, $LibVersion) = @_; 11464 11465 if($CheckPrivateABI) { 11466 return 0; 11467 } 11468 11469 if(defined $TypeInfo{$LibVersion}{$TypeId}{"PrivateABI"}) { 11470 return 1; 11471 } 11472 11473 return 0; 11474} 11475 11476sub mergeTypes($$$) 11477{ 11478 my ($Type1_Id, $Type2_Id, $Level) = @_; 11479 return {} if(not $Type1_Id or not $Type2_Id); 11480 11481 if(defined $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}) 11482 { # already merged 11483 return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}; 11484 } 11485 11486 my %Type1 = get_Type($Type1_Id, 1); 11487 my %Type2 = get_Type($Type2_Id, 2); 11488 if(not $Type1{"Name"} or not $Type2{"Name"}) { 11489 return {}; 11490 } 11491 11492 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 11493 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 11494 11495 if(defined $UsedDump{1}{"DWARF"}) 11496 { 11497 if($Type1_Pure{"Name"} eq "__unknown__" 11498 or $Type2_Pure{"Name"} eq "__unknown__") 11499 { # Error ABI dump 11500 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = {}); 11501 } 11502 } 11503 11504 if(isPrivateABI($Type1_Id, 1)) { 11505 return {}; 11506 } 11507 11508 $CheckedTypes{$Level}{$Type1{"Name"}} = 1; 11509 $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1; 11510 11511 my %SubProblems = (); 11512 11513 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 11514 { 11515 if($Type1_Pure{"Type"}=~/Struct|Union/ 11516 and $Type2_Pure{"Type"}=~/Struct|Union/) 11517 { 11518 if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure)) 11519 { 11520 if(not defined $UsedDump{1}{"DWARF"} 11521 and not defined $UsedDump{2}{"DWARF"}) 11522 { 11523 %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=( 11524 "Target"=>$Type1_Pure{"Name"}, 11525 "Type_Name"=>$Type1_Pure{"Name"} ); 11526 } 11527 11528 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11529 } 11530 } 11531 } 11532 11533 if(not $Type1_Pure{"Size"} 11534 or not $Type2_Pure{"Size"}) 11535 { # including a case when "class Class { ... };" changed to "class Class;" 11536 if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"} 11537 or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1) 11538 { # NOTE: template instances have no size 11539 return {}; 11540 } 11541 } 11542 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes)) 11543 { # skip recursive declarations 11544 return {}; 11545 } 11546 return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); 11547 return {} if($SkipTypes{1}{$Type1_Pure{"Name"}}); 11548 return {} if($SkipTypes{1}{$Type1{"Name"}}); 11549 11550 if(not isTargetType($Type1_Pure{"Tid"}, 1)) { 11551 return {}; 11552 } 11553 11554 if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/) 11555 { # support for old ABI dumps 11556 # _vptr field added in 3.0 11557 if(not checkDump(1, "3.0") and checkDump(2, "3.0")) 11558 { 11559 if(defined $Type2_Pure{"Memb"} 11560 and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr") 11561 { 11562 if(keys(%{$Type2_Pure{"Memb"}})==1) { 11563 delete($Type2_Pure{"Memb"}{0}); 11564 } 11565 else { 11566 removeVPtr(\%Type2_Pure); 11567 } 11568 } 11569 } 11570 if(checkDump(1, "3.0") and not checkDump(2, "3.0")) 11571 { 11572 if(defined $Type1_Pure{"Memb"} 11573 and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr") 11574 { 11575 if(keys(%{$Type1_Pure{"Memb"}})==1) { 11576 delete($Type1_Pure{"Memb"}{0}); 11577 } 11578 else { 11579 removeVPtr(\%Type1_Pure); 11580 } 11581 } 11582 } 11583 } 11584 11585 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 11586 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 11587 11588 if(%Typedef_1 and %Typedef_2 11589 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef" 11590 and $Typedef_1{"Name"} eq $Typedef_2{"Name"}) 11591 { 11592 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1}); 11593 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2}); 11594 if($Base_1{"Name"} ne $Base_2{"Name"}) 11595 { 11596 if(differentDumps("G") 11597 or differentDumps("V")) 11598 { # different GCC versions or different dumps 11599 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1); 11600 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2); 11601 # std::__va_list and __va_list 11602 $Base_1{"Name"}=~s/\A(\w+::)+//; 11603 $Base_2{"Name"}=~s/\A(\w+::)+//; 11604 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T"); 11605 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T"); 11606 } 11607 } 11608 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/ 11609 and $Base_1{"Name"} ne $Base_2{"Name"}) 11610 { 11611 if($Level eq "Binary" 11612 and $Type1{"Size"} and $Type2{"Size"} 11613 and $Type1{"Size"} ne $Type2{"Size"}) 11614 { 11615 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=( 11616 "Target"=>$Typedef_1{"Name"}, 11617 "Type_Name"=>$Typedef_1{"Name"}, 11618 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 11619 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE ); 11620 } 11621 my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1}); 11622 my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2}); 11623 11624 if(defined $UsedDump{1}{"DWARF"}) 11625 { 11626 if($Base1_Pure{"Name"}=~/\b__unknown__\b/ 11627 or $Base2_Pure{"Name"}=~/\b__unknown__\b/) 11628 { # Error ABI dump 11629 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = {}); 11630 } 11631 } 11632 11633 if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"})) 11634 { 11635 if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level)) 11636 { 11637 %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=( 11638 "Target"=>$Typedef_1{"Name"}, 11639 "Type_Name"=>$Typedef_1{"Name"}, 11640 "Old_Value"=>$Base_1{"Name"}, 11641 "New_Value"=>$Base_2{"Name"} ); 11642 } 11643 else 11644 { 11645 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=( 11646 "Target"=>$Typedef_1{"Name"}, 11647 "Type_Name"=>$Typedef_1{"Name"}, 11648 "Old_Value"=>$Base_1{"Name"}, 11649 "New_Value"=>$Base_2{"Name"} ); 11650 } 11651 } 11652 } 11653 } 11654 if(nonComparable(\%Type1_Pure, \%Type2_Pure)) 11655 { # different types (reported in detectTypeChange(...)) 11656 my $TT1 = $Type1_Pure{"Type"}; 11657 my $TT2 = $Type2_Pure{"Type"}; 11658 11659 if($TT1 ne $TT2 11660 and $TT1!~/Intrinsic|Pointer|Ref|Typedef/) 11661 { # different type of the type 11662 my $Short1 = $Type1_Pure{"Name"}; 11663 my $Short2 = $Type2_Pure{"Name"}; 11664 11665 $Short1=~s/\A\Q$TT1\E //ig; 11666 $Short2=~s/\A\Q$TT2\E //ig; 11667 11668 if($Short1 eq $Short2) 11669 { 11670 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=( 11671 "Target"=>$Type1_Pure{"Name"}, 11672 "Type_Name"=>$Type1_Pure{"Name"}, 11673 "Old_Value"=>lc($Type1_Pure{"Type"}), 11674 "New_Value"=>lc($Type2_Pure{"Type"}) ); 11675 } 11676 } 11677 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 11678 } 11679 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes); 11680 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"} 11681 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"}))) 11682 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11683 { # checking size 11684 if($Level eq "Binary" 11685 and $Type1_Pure{"Size"} and $Type2_Pure{"Size"} 11686 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11687 { 11688 my $ProblemKind = "DataType_Size"; 11689 if($Type1_Pure{"Type"} eq "Class" 11690 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}})) 11691 { 11692 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) { 11693 $ProblemKind = "Size_Of_Copying_Class"; 11694 } 11695 elsif($AllocableClass{1}{$Type1_Pure{"Name"}}) 11696 { 11697 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) { 11698 $ProblemKind = "Size_Of_Allocable_Class_Increased"; 11699 } 11700 else 11701 { 11702 # descreased size of allocable class 11703 # it has no special effects 11704 } 11705 } 11706 } 11707 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=( 11708 "Target"=>$Type1_Pure{"Name"}, 11709 "Type_Name"=>$Type1_Pure{"Name"}, 11710 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE, 11711 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE); 11712 } 11713 } 11714 if(defined $Type1_Pure{"BaseType"} 11715 and defined $Type2_Pure{"BaseType"}) 11716 { # checking base types 11717 my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); 11718 foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) 11719 { 11720 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { 11721 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 11722 } 11723 } 11724 } 11725 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = (); 11726 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}}); 11727 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}}); 11728 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11729 { # detect removed and renamed fields 11730 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11731 next if(not $Member_Name); 11732 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); 11733 if($MemberPair_Pos eq "lost") 11734 { 11735 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11736 { 11737 if(isUnnamed($Member_Name)) 11738 { # support for old-version dumps 11739 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11740 if(not checkDump(2, "2.1")) { 11741 next; 11742 } 11743 } 11744 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2)) 11745 { # renamed 11746 $RenamedField{$Member_Pos} = $RenamedTo; 11747 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11748 } 11749 else 11750 { # removed 11751 $RemovedField{$Member_Pos} = 1; 11752 } 11753 } 11754 elsif($Type1_Pure{"Type"} eq "Enum") 11755 { 11756 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 11757 next if($Member_Value1 eq ""); 11758 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure); 11759 if($MemberPair_Pos ne "lost") 11760 { # renamed 11761 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"}; 11762 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure); 11763 if($MemberPair_Pos_Rev eq "lost") 11764 { 11765 $RenamedField{$Member_Pos} = $RenamedTo; 11766 $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; 11767 } 11768 else { 11769 $RemovedField{$Member_Pos} = 1; 11770 } 11771 } 11772 else 11773 { # removed 11774 $RemovedField{$Member_Pos} = 1; 11775 } 11776 } 11777 } 11778 else 11779 { # related 11780 $RelatedField{$Member_Pos} = $MemberPair_Pos; 11781 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos; 11782 } 11783 } 11784 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11785 { # detect added fields 11786 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11787 next if(not $Member_Name); 11788 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); 11789 if($MemberPair_Pos eq "lost") 11790 { 11791 if(isUnnamed($Member_Name)) 11792 { # support for old-version dumps 11793 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) 11794 if(not checkDump(1, "2.1")) { 11795 next; 11796 } 11797 } 11798 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/) 11799 { 11800 if(not $RenamedField_Rev{$Member_Pos}) 11801 { # added 11802 $AddedField{$Member_Pos}=1; 11803 } 11804 } 11805 } 11806 } 11807 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 11808 { # detect moved fields 11809 my (%RelPos, %RelPosName, %AbsPos) = (); 11810 my $Pos = 0; 11811 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11812 { # relative positions in 1st version 11813 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11814 next if(not $Member_Name); 11815 if(not $RemovedField{$Member_Pos}) 11816 { # old type without removed fields 11817 $RelPos{1}{$Member_Name} = $Pos; 11818 $RelPosName{1}{$Pos} = $Member_Name; 11819 $AbsPos{1}{$Pos++} = $Member_Pos; 11820 } 11821 } 11822 $Pos = 0; 11823 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 11824 { # relative positions in 2nd version 11825 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 11826 next if(not $Member_Name); 11827 if(not $AddedField{$Member_Pos}) 11828 { # new type without added fields 11829 $RelPos{2}{$Member_Name} = $Pos; 11830 $RelPosName{2}{$Pos} = $Member_Name; 11831 $AbsPos{2}{$Pos++} = $Member_Pos; 11832 } 11833 } 11834 foreach my $Member_Name (keys(%{$RelPos{1}})) 11835 { 11836 my $RPos1 = $RelPos{1}{$Member_Name}; 11837 my $AbsPos1 = $NameToPosA{$Member_Name}; 11838 my $Member_Name2 = $Member_Name; 11839 if(my $RenamedTo = $RenamedField{$AbsPos1}) 11840 { # renamed 11841 $Member_Name2 = $RenamedTo; 11842 } 11843 my $RPos2 = $RelPos{2}{$Member_Name2}; 11844 if($RPos2 ne "" and $RPos1 ne $RPos2) 11845 { # different relative positions 11846 my $AbsPos2 = $NameToPosB{$Member_Name2}; 11847 if($AbsPos1 ne $AbsPos2) 11848 { # different absolute positions 11849 my $ProblemType = "Moved_Field"; 11850 if(not isPublic(\%Type1_Pure, $AbsPos1)) 11851 { # may change layout and size of type 11852 if($Level eq "Source") { 11853 next; 11854 } 11855 $ProblemType = "Moved_Private_Field"; 11856 } 11857 if($Level eq "Binary" 11858 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11859 { # affected size 11860 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"}; 11861 my $MovedAbsPos = $AbsPos{1}{$RPos2}; 11862 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"}; 11863 if($MemSize1 ne $MemSize2) { 11864 $ProblemType .= "_And_Size"; 11865 } 11866 } 11867 if($ProblemType eq "Moved_Private_Field") { 11868 next; 11869 } 11870 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11871 "Target"=>$Member_Name, 11872 "Type_Name"=>$Type1_Pure{"Name"}, 11873 "Old_Value"=>$RPos1, 11874 "New_Value"=>$RPos2 ); 11875 } 11876 } 11877 } 11878 } 11879 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) 11880 { # check older fields, public and private 11881 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; 11882 next if(not $Member_Name); 11883 next if($Member_Name eq "_vptr"); 11884 if(my $RenamedTo = $RenamedField{$Member_Pos}) 11885 { # renamed 11886 if(defined $Constants{2}{$Member_Name}) 11887 { 11888 if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo) 11889 { # define OLD NEW 11890 next; # Safe 11891 } 11892 } 11893 11894 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 11895 { 11896 if(isPublic(\%Type1_Pure, $Member_Pos)) 11897 { 11898 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=( 11899 "Target"=>$Member_Name, 11900 "Type_Name"=>$Type1_Pure{"Name"}, 11901 "Old_Value"=>$Member_Name, 11902 "New_Value"=>$RenamedTo ); 11903 } 11904 elsif(isReserved($Member_Name)) 11905 { 11906 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=( 11907 "Target"=>$Member_Name, 11908 "Type_Name"=>$Type1_Pure{"Name"}, 11909 "Old_Value"=>$Member_Name, 11910 "New_Value"=>$RenamedTo ); 11911 } 11912 } 11913 elsif($Type1_Pure{"Type"} eq "Enum") 11914 { 11915 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=( 11916 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"}, 11917 "Type_Name"=>$Type1_Pure{"Name"}, 11918 "Old_Value"=>$Member_Name, 11919 "New_Value"=>$RenamedTo ); 11920 } 11921 } 11922 elsif($RemovedField{$Member_Pos}) 11923 { # removed 11924 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 11925 { 11926 my $ProblemType = "Removed_Field"; 11927 if(not isPublic(\%Type1_Pure, $Member_Pos) 11928 or isUnnamed($Member_Name)) 11929 { 11930 if($Level eq "Source") { 11931 next; 11932 } 11933 $ProblemType = "Removed_Private_Field"; 11934 } 11935 if($Level eq "Binary" 11936 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 11937 { 11938 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 11939 { # affected fields 11940 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})) 11941 { # changed offset 11942 $ProblemType .= "_And_Layout"; 11943 } 11944 } 11945 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11946 { # affected size 11947 $ProblemType .= "_And_Size"; 11948 } 11949 } 11950 if($ProblemType eq "Removed_Private_Field") { 11951 next; 11952 } 11953 %{$SubProblems{$ProblemType}{$Member_Name}}=( 11954 "Target"=>$Member_Name, 11955 "Type_Name"=>$Type1_Pure{"Name"} ); 11956 } 11957 elsif($Type2_Pure{"Type"} eq "Union") 11958 { 11959 if($Level eq "Binary" 11960 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 11961 { 11962 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=( 11963 "Target"=>$Member_Name, 11964 "Type_Name"=>$Type1_Pure{"Name"} ); 11965 } 11966 else 11967 { 11968 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=( 11969 "Target"=>$Member_Name, 11970 "Type_Name"=>$Type1_Pure{"Name"} ); 11971 } 11972 } 11973 elsif($Type1_Pure{"Type"} eq "Enum") 11974 { 11975 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=( 11976 "Target"=>$Member_Name, 11977 "Type_Name"=>$Type1_Pure{"Name"}, 11978 "Old_Value"=>$Member_Name ); 11979 } 11980 } 11981 else 11982 { # changed 11983 my $MemberPair_Pos = $RelatedField{$Member_Pos}; 11984 if($Type1_Pure{"Type"} eq "Enum") 11985 { 11986 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; 11987 next if($Member_Value1 eq ""); 11988 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"}; 11989 next if($Member_Value2 eq ""); 11990 if($Member_Value1 ne $Member_Value2) 11991 { 11992 my $ProblemType = "Enum_Member_Value"; 11993 if(isLastElem($Member_Pos, \%Type1_Pure)) { 11994 $ProblemType = "Enum_Last_Member_Value"; 11995 } 11996 if($SkipConstants{1}{$Member_Name}) { 11997 $ProblemType = "Enum_Private_Member_Value"; 11998 } 11999 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12000 "Target"=>$Member_Name, 12001 "Type_Name"=>$Type1_Pure{"Name"}, 12002 "Old_Value"=>$Member_Value1, 12003 "New_Value"=>$Member_Value2 ); 12004 } 12005 } 12006 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) 12007 { 12008 my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"}; 12009 my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"}; 12010 12011 if($Access1 ne "private" 12012 and $Access2 eq "private") 12013 { 12014 %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=( 12015 "Target"=>$Member_Name, 12016 "Type_Name"=>$Type1_Pure{"Name"}); 12017 } 12018 elsif($Access1 ne "protected" 12019 and $Access1 ne "private" 12020 and $Access2 eq "protected") 12021 { 12022 %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=( 12023 "Target"=>$Member_Name, 12024 "Type_Name"=>$Type1_Pure{"Name"}); 12025 } 12026 12027 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"}; 12028 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"}; 12029 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE; 12030 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) { 12031 $SizeV1 = $BSize1; 12032 } 12033 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE; 12034 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) { 12035 $SizeV2 = $BSize2; 12036 } 12037 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"}; 12038 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"}; 12039 if($Level eq "Binary" 12040 and $SizeV1 and $SizeV2 12041 and $SizeV1 ne $SizeV2) 12042 { 12043 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name)) 12044 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})) 12045 { # field size change (including anon-structures and unions) 12046 # - same types 12047 # - unnamed types 12048 # - bitfields 12049 my $ProblemType = "Field_Size"; 12050 if(not isPublic(\%Type1_Pure, $Member_Pos) 12051 or isUnnamed($Member_Name)) 12052 { # should not be accessed by applications, goes to "Low Severity" 12053 # example: "abidata" members in GStreamer types 12054 $ProblemType = "Private_".$ProblemType; 12055 } 12056 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12057 { # check an effect 12058 if($Type2_Pure{"Type"} ne "Union" 12059 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12060 { # public fields after the current 12061 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})) 12062 { # changed offset 12063 $ProblemType .= "_And_Layout"; 12064 } 12065 } 12066 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12067 $ProblemType .= "_And_Type_Size"; 12068 } 12069 } 12070 if($ProblemType eq "Private_Field_Size") 12071 { # private field size with no effect 12072 } 12073 if($ProblemType eq "Field_Size") 12074 { 12075 if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2) 12076 { # Low severity 12077 $ProblemType = "Struct_Field_Size_Increased"; 12078 } 12079 } 12080 if($ProblemType) 12081 { # register a problem 12082 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12083 "Target"=>$Member_Name, 12084 "Type_Name"=>$Type1_Pure{"Name"}, 12085 "Old_Size"=>$SizeV1, 12086 "New_Size"=>$SizeV2); 12087 } 12088 } 12089 } 12090 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} 12091 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) 12092 { # do NOT check bitfield type changes 12093 next; 12094 } 12095 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 12096 { 12097 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12098 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12099 { 12100 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=( 12101 "Target"=>$Member_Name, 12102 "Type_Name"=>$Type1_Pure{"Name"}); 12103 } 12104 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} 12105 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) 12106 { 12107 %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=( 12108 "Target"=>$Member_Name, 12109 "Type_Name"=>$Type1_Pure{"Name"}); 12110 } 12111 } 12112 my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); 12113 foreach my $ProblemType (keys(%Sub_SubChanges)) 12114 { 12115 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12116 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12117 12118 # quals 12119 if($ProblemType eq "Field_Type" 12120 or $ProblemType eq "Field_Type_And_Size" 12121 or $ProblemType eq "Field_Type_Format") 12122 { 12123 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 12124 { 12125 if(addedQual($Old_Value, $New_Value, "volatile")) { 12126 %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12127 } 12128 elsif(removedQual($Old_Value, $New_Value, "volatile")) { 12129 %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; 12130 } 12131 } 12132 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 12133 { 12134 if($RA==2) { 12135 %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12136 } 12137 else { 12138 %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12139 } 12140 } 12141 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 12142 { 12143 if($RR==2) { 12144 %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12145 } 12146 else { 12147 %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}}; 12148 } 12149 } 12150 } 12151 } 12152 12153 if($Level eq "Source") 12154 { 12155 foreach my $ProblemType (keys(%Sub_SubChanges)) 12156 { 12157 my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; 12158 my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; 12159 12160 if($ProblemType eq "Field_Type") 12161 { 12162 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 12163 delete($Sub_SubChanges{$ProblemType}); 12164 } 12165 } 12166 } 12167 } 12168 12169 foreach my $ProblemType (keys(%Sub_SubChanges)) 12170 { 12171 my $ProblemType_Init = $ProblemType; 12172 if($ProblemType eq "Field_Type_And_Size") 12173 { # Binary 12174 if(not isPublic(\%Type1_Pure, $Member_Pos) 12175 or isUnnamed($Member_Name)) { 12176 $ProblemType = "Private_".$ProblemType; 12177 } 12178 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) 12179 { # check an effect 12180 if($Type2_Pure{"Type"} ne "Union" 12181 and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) 12182 { # public fields after the current 12183 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})) 12184 { # changed offset 12185 $ProblemType .= "_And_Layout"; 12186 } 12187 } 12188 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12189 $ProblemType .= "_And_Type_Size"; 12190 } 12191 } 12192 } 12193 else 12194 { 12195 # TODO: Private_Field_Type rule? 12196 12197 if(not isPublic(\%Type1_Pure, $Member_Pos) 12198 or isUnnamed($Member_Name)) { 12199 next; 12200 } 12201 } 12202 if($ProblemType eq "Private_Field_Type_And_Size") 12203 { # private field change with no effect 12204 } 12205 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12206 "Target"=>$Member_Name, 12207 "Type_Name"=>$Type1_Pure{"Name"}); 12208 12209 foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}})) 12210 { # other properties 12211 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr}; 12212 } 12213 } 12214 if(not isPublic(\%Type1_Pure, $Member_Pos)) 12215 { # do NOT check internal type changes 12216 next; 12217 } 12218 if($MemberType1_Id and $MemberType2_Id) 12219 { # checking member type changes 12220 my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); 12221 12222 my %DupProblems = (); 12223 12224 foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) 12225 { 12226 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) 12227 { 12228 if(not defined $AllAffected) 12229 { 12230 if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) { 12231 next; 12232 } 12233 } 12234 12235 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; 12236 $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; 12237 12238 if(not defined $AllAffected) 12239 { 12240 $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1; 12241 } 12242 } 12243 } 12244 12245 %DupProblems = (); 12246 } 12247 } 12248 } 12249 } 12250 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) 12251 { # checking added members, public and private 12252 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; 12253 next if(not $Member_Name); 12254 next if($Member_Name eq "_vptr"); 12255 if($AddedField{$Member_Pos}) 12256 { # added 12257 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) 12258 { 12259 my $ProblemType = "Added_Field"; 12260 if(not isPublic(\%Type2_Pure, $Member_Pos) 12261 or isUnnamed($Member_Name)) 12262 { 12263 if($Level eq "Source") { 12264 next; 12265 } 12266 $ProblemType = "Added_Private_Field"; 12267 } 12268 if($Level eq "Binary" 12269 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) 12270 { 12271 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1)) 12272 { # public fields after the current 12273 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})) 12274 { # changed offset 12275 $ProblemType .= "_And_Layout"; 12276 } 12277 } 12278 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { 12279 $ProblemType .= "_And_Size"; 12280 } 12281 } 12282 if($ProblemType eq "Added_Private_Field") 12283 { # skip added private fields 12284 next; 12285 } 12286 %{$SubProblems{$ProblemType}{$Member_Name}}=( 12287 "Target"=>$Member_Name, 12288 "Type_Name"=>$Type1_Pure{"Name"}); 12289 } 12290 elsif($Type2_Pure{"Type"} eq "Union") 12291 { 12292 if($Level eq "Binary" 12293 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) 12294 { 12295 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=( 12296 "Target"=>$Member_Name, 12297 "Type_Name"=>$Type1_Pure{"Name"}); 12298 } 12299 else 12300 { 12301 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=( 12302 "Target"=>$Member_Name, 12303 "Type_Name"=>$Type1_Pure{"Name"}); 12304 } 12305 } 12306 elsif($Type2_Pure{"Type"} eq "Enum") 12307 { 12308 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"}; 12309 next if($Member_Value eq ""); 12310 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=( 12311 "Target"=>$Member_Name, 12312 "Type_Name"=>$Type2_Pure{"Name"}, 12313 "New_Value"=>$Member_Value); 12314 } 12315 } 12316 } 12317 12318 if($Type1_Pure{"Type"} eq "FuncPtr") 12319 { 12320 foreach my $PPos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Param"}})) 12321 { 12322 if(not defined $Type2_Pure{"Param"}{$PPos}) { 12323 next; 12324 } 12325 12326 my $PT1 = $Type1_Pure{"Param"}{$PPos}{"type"}; 12327 my $PT2 = $Type2_Pure{"Param"}{$PPos}{"type"}; 12328 12329 my $PName = "p".$PPos; 12330 12331 my $FP_SubProblems = mergeTypes($PT1, $PT2, $Level); 12332 my %DupProblems = (); 12333 12334 foreach my $FP_SubProblemType (keys(%{$FP_SubProblems})) 12335 { 12336 foreach my $FP_SubLocation (keys(%{$FP_SubProblems->{$FP_SubProblemType}})) 12337 { 12338 if(not defined $AllAffected) 12339 { 12340 if(defined $DupProblems{$FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}}) { 12341 next; 12342 } 12343 } 12344 12345 my $NewLocation = ($FP_SubLocation)?$PName."->".$FP_SubLocation:$PName; 12346 $SubProblems{$FP_SubProblemType}{$NewLocation} = $FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}; 12347 12348 if(not defined $AllAffected) 12349 { 12350 $DupProblems{$FP_SubProblems->{$FP_SubProblemType}{$FP_SubLocation}} = 1; 12351 } 12352 } 12353 } 12354 12355 %DupProblems = (); 12356 } 12357 } 12358 12359 pop(@RecurTypes); 12360 return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); 12361} 12362 12363sub isUnnamed($) { 12364 return $_[0]=~/\Aunnamed\d+\Z/; 12365} 12366 12367sub get_ShortClass($$) 12368{ 12369 my ($TypeId, $LibVersion) = @_; 12370 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 12371 if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) { 12372 $TypeName = uncover_typedefs($TypeName, $LibVersion); 12373 } 12374 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) { 12375 $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g; 12376 } 12377 return $TypeName; 12378} 12379 12380sub goToFirst($$$) 12381{ 12382 my ($TypeId, $LibVersion, $Type_Type) = @_; 12383 return () if(not $TypeId); 12384 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) { 12385 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}}; 12386 } 12387 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12388 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12389 return () if(not $Type{"Type"}); 12390 if($Type{"Type"} ne $Type_Type) 12391 { 12392 return () if(not $Type{"BaseType"}); 12393 %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type); 12394 } 12395 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type; 12396 return %Type; 12397} 12398 12399my %TypeSpecAttributes = ( 12400 "Const" => 1, 12401 "Volatile" => 1, 12402 "ConstVolatile" => 1, 12403 "Restrict" => 1, 12404 "Typedef" => 1 12405); 12406 12407sub get_PureType($$) 12408{ 12409 my ($TypeId, $Info) = @_; 12410 if(not $TypeId or not $Info 12411 or not $Info->{$TypeId}) { 12412 return (); 12413 } 12414 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) { 12415 return %{$Cache{"get_PureType"}{$TypeId}{$Info}}; 12416 } 12417 my %Type = %{$Info->{$TypeId}}; 12418 return %Type if(not $Type{"BaseType"}); 12419 if($TypeSpecAttributes{$Type{"Type"}}) { 12420 %Type = get_PureType($Type{"BaseType"}, $Info); 12421 } 12422 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type; 12423 return %Type; 12424} 12425 12426sub get_PLevel($$) 12427{ 12428 my ($TypeId, $LibVersion) = @_; 12429 return 0 if(not $TypeId); 12430 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) { 12431 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion}; 12432 } 12433 return 0 if(not $TypeInfo{$LibVersion}{$TypeId}); 12434 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12435 return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/); 12436 my $PLevel = 0; 12437 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) { 12438 $PLevel += 1; 12439 } 12440 return $PLevel if(not $Type{"BaseType"}); 12441 $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion); 12442 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel; 12443 return $PLevel; 12444} 12445 12446sub get_BaseType($$) 12447{ 12448 my ($TypeId, $LibVersion) = @_; 12449 return () if(not $TypeId); 12450 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) { 12451 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}}; 12452 } 12453 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12454 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12455 return %Type if(not $Type{"BaseType"}); 12456 %Type = get_BaseType($Type{"BaseType"}, $LibVersion); 12457 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type; 12458 return %Type; 12459} 12460 12461sub get_BaseTypeQual($$) 12462{ 12463 my ($TypeId, $LibVersion) = @_; 12464 return "" if(not $TypeId); 12465 return "" if(not $TypeInfo{$LibVersion}{$TypeId}); 12466 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; 12467 return "" if(not $Type{"BaseType"}); 12468 my $Qual = ""; 12469 if($Type{"Type"} eq "Pointer") { 12470 $Qual .= "*"; 12471 } 12472 elsif($Type{"Type"} eq "Ref") { 12473 $Qual .= "&"; 12474 } 12475 elsif($Type{"Type"} eq "ConstVolatile") { 12476 $Qual .= "const volatile"; 12477 } 12478 elsif($Type{"Type"} eq "Const" 12479 or $Type{"Type"} eq "Volatile" 12480 or $Type{"Type"} eq "Restrict") { 12481 $Qual .= lc($Type{"Type"}); 12482 } 12483 my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion); 12484 return $BQual.$Qual; 12485} 12486 12487sub get_OneStep_BaseType($$) 12488{ 12489 my ($TypeId, $Info) = @_; 12490 if(not $TypeId or not $Info 12491 or not $Info->{$TypeId}) { 12492 return (); 12493 } 12494 my %Type = %{$Info->{$TypeId}}; 12495 return %Type if(not $Type{"BaseType"}); 12496 if(my $BTid = $Type{"BaseType"}) 12497 { 12498 if($Info->{$BTid}) { 12499 return %{$Info->{$BTid}}; 12500 } 12501 else { # something is going wrong 12502 return (); 12503 } 12504 } 12505 else { 12506 return %Type; 12507 } 12508} 12509 12510sub get_Type($$) 12511{ 12512 my ($TypeId, $LibVersion) = @_; 12513 return () if(not $TypeId); 12514 return () if(not $TypeInfo{$LibVersion}{$TypeId}); 12515 return %{$TypeInfo{$LibVersion}{$TypeId}}; 12516} 12517 12518sub isPrivateData($) 12519{ # non-public global data 12520 my $Symbol = $_[0]; 12521 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/); 12522} 12523 12524sub isInLineInst($$) { 12525 return (isTemplateInstance(@_) and not isTemplateSpec(@_)); 12526} 12527 12528sub isTemplateInstance($$) 12529{ 12530 my ($SInfo, $LibVersion) = @_; 12531 12532 if(my $ClassId = $SInfo->{"Class"}) 12533 { 12534 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}) 12535 { 12536 if(index($ClassName,"<")!=-1) { 12537 return 1; 12538 } 12539 } 12540 } 12541 if(my $ShortName = $SInfo->{"ShortName"}) 12542 { 12543 if(index($ShortName,"<")!=-1 12544 and index($ShortName,">")!=-1) { 12545 return 1; 12546 } 12547 } 12548 12549 return 0; 12550} 12551 12552sub isTemplateSpec($$) 12553{ 12554 my ($SInfo, $LibVersion) = @_; 12555 if(my $ClassId = $SInfo->{"Class"}) 12556 { 12557 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"}) 12558 { # class specialization 12559 return 1; 12560 } 12561 elsif($SInfo->{"Spec"}) 12562 { # method specialization 12563 return 1; 12564 } 12565 } 12566 return 0; 12567} 12568 12569sub symbolFilter($$$$) 12570{ # some special cases when the symbol cannot be imported 12571 my ($Symbol, $LibVersion, $Type, $Level) = @_; 12572 12573 if(isPrivateData($Symbol)) 12574 { # non-public global data 12575 return 0; 12576 } 12577 12578 if(defined $SkipInternalSymbols) 12579 { 12580 return 0 if($Symbol=~/($SkipInternalSymbols)/); 12581 } 12582 12583 if($Symbol=~/\A_Z/) 12584 { 12585 if($Symbol=~/[CD][3-4]E/) { 12586 return 0; 12587 } 12588 } 12589 12590 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7")) 12591 { # support for old ABI dumps in --headers-only mode 12592 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 12593 { 12594 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}) 12595 { 12596 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"}; 12597 if(not $PType or $PType eq "Unknown") { 12598 return 0; 12599 } 12600 } 12601 } 12602 } 12603 if($Type=~/Affected/) 12604 { 12605 my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"}; 12606 12607 if($SkipSymbols{$LibVersion}{$Symbol}) 12608 { # user defined symbols to ignore 12609 return 0; 12610 } 12611 12612 if($SymbolsListPath and not $SymbolsList{$Symbol}) 12613 { # user defined symbols 12614 if(not $TargetHeadersPath or not $Header 12615 or not is_target_header($Header, 1)) 12616 { # -symbols-list | -headers-list 12617 return 0; 12618 } 12619 } 12620 12621 if($AppPath and not $SymbolsList_App{$Symbol}) 12622 { # user defined symbols (in application) 12623 return 0; 12624 } 12625 12626 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}; 12627 12628 if($ClassId) 12629 { 12630 if(not isTargetType($ClassId, $LibVersion)) { 12631 return 0; 12632 } 12633 } 12634 12635 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; 12636 if(not $NameSpace and $ClassId) 12637 { # class methods have no "NameSpace" attribute 12638 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}; 12639 } 12640 if($NameSpace) 12641 { # user defined namespaces to ignore 12642 if($SkipNameSpaces{$LibVersion}{$NameSpace}) { 12643 return 0; 12644 } 12645 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}})) 12646 { # nested namespaces 12647 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) { 12648 return 0; 12649 } 12650 } 12651 } 12652 if($Header) 12653 { 12654 if(my $Skip = skipHeader($Header, $LibVersion)) 12655 { # --skip-headers or <skip_headers> (not <skip_including>) 12656 if($Skip==1) { 12657 return 0; 12658 } 12659 } 12660 } 12661 if($TypesListPath and $ClassId) 12662 { # user defined types 12663 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; 12664 12665 if(not $TypesList{$CName}) 12666 { 12667 if(my $NS = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}) 12668 { 12669 $CName=~s/\A\Q$NS\E\:\://g; 12670 } 12671 12672 if(not $TypesList{$CName}) 12673 { 12674 my $Found = 0; 12675 12676 while($CName=~s/\:\:.+?\Z//) 12677 { 12678 if($TypesList{$CName}) 12679 { 12680 $Found = 1; 12681 last; 12682 } 12683 } 12684 12685 if(not $Found) { 12686 return 0; 12687 } 12688 } 12689 } 12690 } 12691 12692 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion)) 12693 { # non-target symbols 12694 return 0; 12695 } 12696 if($Level eq "Binary") 12697 { 12698 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"} 12699 or isInLineInst($CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) 12700 { 12701 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) 12702 { # inline virtual methods 12703 if($Type=~/InlineVirt/) { 12704 return 1; 12705 } 12706 my $Allocable = (not isCopyingClass($ClassId, $LibVersion)); 12707 if(not $Allocable) 12708 { # check bases 12709 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1)) 12710 { 12711 if(not isCopyingClass($DCId, $LibVersion)) 12712 { # exists a derived class without default c-tor 12713 $Allocable=1; 12714 last; 12715 } 12716 } 12717 } 12718 if(not $Allocable) { 12719 return 0; 12720 } 12721 } 12722 else 12723 { # inline non-virtual methods 12724 return 0; 12725 } 12726 } 12727 } 12728 } 12729 return 1; 12730} 12731 12732sub detectAdded($) 12733{ 12734 my $Level = $_[0]; 12735 foreach my $Symbol (keys(%{$Symbol_Library{2}})) 12736 { 12737 if(link_symbol($Symbol, 1, "+Deps")) 12738 { # linker can find a new symbol 12739 # in the old-version library 12740 # So, it's not a new symbol 12741 next; 12742 } 12743 if(my $VSym = $SymVer{2}{$Symbol} 12744 and index($Symbol,"\@")==-1) { 12745 next; 12746 } 12747 $AddedInt{$Level}{$Symbol} = 1; 12748 } 12749} 12750 12751sub detectRemoved($) 12752{ 12753 my $Level = $_[0]; 12754 foreach my $Symbol (keys(%{$Symbol_Library{1}})) 12755 { 12756 if(link_symbol($Symbol, 2, "+Deps")) 12757 { # linker can find an old symbol 12758 # in the new-version library 12759 next; 12760 } 12761 if(my $VSym = $SymVer{1}{$Symbol} 12762 and index($Symbol,"\@")==-1) { 12763 next; 12764 } 12765 $RemovedInt{$Level}{$Symbol} = 1; 12766 } 12767} 12768 12769sub mergeLibs($) 12770{ 12771 my $Level = $_[0]; 12772 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 12773 { # checking added symbols 12774 next if($CompleteSignature{2}{$Symbol}{"Private"}); 12775 next if(not $CompleteSignature{2}{$Symbol}{"Header"}); 12776 next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level)); 12777 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 12778 } 12779 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 12780 { # checking removed symbols 12781 next if($CompleteSignature{1}{$Symbol}{"Private"}); 12782 next if(not $CompleteSignature{1}{$Symbol}{"Header"}); 12783 if(index($Symbol, "_ZTV")==0) 12784 { # skip v-tables for templates, that should not be imported by applications 12785 next if($tr_name{$Symbol}=~/</); 12786 if(my $CName = $VTableClass{$Symbol}) 12787 { 12788 if(not keys(%{$ClassMethods{$Level}{1}{$CName}})) 12789 { # vtables for "private" classes 12790 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol 12791 next; 12792 } 12793 } 12794 12795 if($SkipSymbols{1}{$Symbol}) 12796 { # user defined symbols to ignore 12797 next; 12798 } 12799 } 12800 else { 12801 next if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)); 12802 } 12803 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) 12804 { # symbols for pure virtual methods cannot be called by clients 12805 next; 12806 } 12807 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 12808 } 12809} 12810 12811sub checkDump($$) 12812{ 12813 my ($LibVersion, $V) = @_; 12814 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) { 12815 return $Cache{"checkDump"}{$LibVersion}{$V}; 12816 } 12817 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0)); 12818} 12819 12820sub detectAdded_H($) 12821{ 12822 my $Level = $_[0]; 12823 foreach my $Symbol (sort keys(%{$CompleteSignature{2}})) 12824 { 12825 if($Level eq "Source") 12826 { # remove symbol version 12827 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12828 $Symbol=$SN; 12829 12830 if($CompleteSignature{2}{$Symbol}{"Artificial"}) 12831 { # skip artificial constructors 12832 next; 12833 } 12834 } 12835 if(not $CompleteSignature{2}{$Symbol}{"Header"} 12836 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) { 12837 next; 12838 } 12839 if($ExtendedSymbols{$Symbol}) { 12840 next; 12841 } 12842 if(not defined $CompleteSignature{1}{$Symbol} 12843 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) 12844 { 12845 if($UsedDump{2}{"SrcBin"}) 12846 { 12847 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11")) 12848 { # support for old and different (!) ABI dumps 12849 if(not $CompleteSignature{2}{$Symbol}{"Virt"} 12850 and not $CompleteSignature{2}{$Symbol}{"PureVirt"}) 12851 { 12852 if($CheckHeadersOnly) 12853 { 12854 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"}) 12855 { 12856 if($Lang eq "C") 12857 { # support for old ABI dumps: missed extern "C" functions 12858 next; 12859 } 12860 } 12861 } 12862 else 12863 { 12864 if(not link_symbol($Symbol, 2, "-Deps")) 12865 { # skip added inline symbols and const global data 12866 next; 12867 } 12868 } 12869 } 12870 } 12871 } 12872 $AddedInt{$Level}{$Symbol} = 1; 12873 } 12874 } 12875} 12876 12877sub detectRemoved_H($) 12878{ 12879 my $Level = $_[0]; 12880 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 12881 { 12882 if($Level eq "Source") 12883 { # remove symbol version 12884 my ($SN, $SS, $SV) = separate_symbol($Symbol); 12885 $Symbol=$SN; 12886 } 12887 if(not $CompleteSignature{1}{$Symbol}{"Header"} 12888 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) { 12889 next; 12890 } 12891 if($ExtendedSymbols{$Symbol}) { 12892 next; 12893 } 12894 if(not defined $CompleteSignature{2}{$Symbol} 12895 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) 12896 { 12897 if($UsedDump{1}{"SrcBin"}) 12898 { 12899 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11")) 12900 { # support for old and different (!) ABI dumps 12901 if(not $CompleteSignature{1}{$Symbol}{"Virt"} 12902 and not $CompleteSignature{1}{$Symbol}{"PureVirt"}) 12903 { 12904 if($CheckHeadersOnly) 12905 { # skip all removed symbols 12906 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"}) 12907 { 12908 if($Lang eq "C") 12909 { # support for old ABI dumps: missed extern "C" functions 12910 next; 12911 } 12912 } 12913 } 12914 else 12915 { 12916 if(not link_symbol($Symbol, 1, "-Deps")) 12917 { # skip removed inline symbols 12918 next; 12919 } 12920 } 12921 } 12922 } 12923 } 12924 if(not checkDump(1, "2.15")) 12925 { 12926 if($Symbol=~/_IT_E\Z/) 12927 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E 12928 next; 12929 } 12930 } 12931 if(not $CompleteSignature{1}{$Symbol}{"Class"}) 12932 { 12933 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"}) 12934 { 12935 if(defined $Constants{2}{$Short}) 12936 { 12937 my $Val = $Constants{2}{$Short}{"Value"}; 12938 if(defined $Func_ShortName{2}{$Val}) 12939 { # old name defined to new 12940 next; 12941 } 12942 } 12943 } 12944 12945 } 12946 $RemovedInt{$Level}{$Symbol} = 1; 12947 if($Level eq "Source") 12948 { # search for a source-compatible equivalent 12949 setAlternative($Symbol, $Level); 12950 } 12951 } 12952 } 12953} 12954 12955sub mergeHeaders($) 12956{ 12957 my $Level = $_[0]; 12958 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 12959 { # checking added symbols 12960 next if($CompleteSignature{2}{$Symbol}{"PureVirt"}); 12961 next if($CompleteSignature{2}{$Symbol}{"Private"}); 12962 next if(not symbolFilter($Symbol, 2, "Affected", $Level)); 12963 if($Level eq "Binary") 12964 { 12965 if($CompleteSignature{2}{$Symbol}{"InLine"}) 12966 { 12967 if(not $CompleteSignature{2}{$Symbol}{"Virt"}) 12968 { # skip inline non-virtual functions 12969 next; 12970 } 12971 } 12972 } 12973 else 12974 { # Source 12975 if($SourceAlternative_B{$Symbol}) { 12976 next; 12977 } 12978 } 12979 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); 12980 } 12981 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 12982 { # checking removed symbols 12983 next if($CompleteSignature{1}{$Symbol}{"PureVirt"}); 12984 next if($CompleteSignature{1}{$Symbol}{"Private"}); 12985 next if(not symbolFilter($Symbol, 1, "Affected", $Level)); 12986 if($Level eq "Binary") 12987 { 12988 if($CompleteSignature{1}{$Symbol}{"InLine"}) 12989 { 12990 if(not $CompleteSignature{1}{$Symbol}{"Virt"}) 12991 { # skip inline non-virtual functions 12992 next; 12993 } 12994 } 12995 } 12996 else 12997 { # Source 12998 if(my $Alt = $SourceAlternative{$Symbol}) 12999 { 13000 if(defined $CompleteSignature{1}{$Alt} 13001 and $CompleteSignature{1}{$Symbol}{"Const"}) 13002 { 13003 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 13004 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=( 13005 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"}, 13006 "Target"=>get_Signature($Alt, 1)); 13007 } 13008 else 13009 { # do NOT show removed symbol 13010 next; 13011 } 13012 } 13013 } 13014 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); 13015 } 13016} 13017 13018sub addParamNames($) 13019{ 13020 my $LibraryVersion = $_[0]; 13021 return if(not keys(%AddIntParams)); 13022 my $SecondVersion = $LibraryVersion==1?2:1; 13023 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}})) 13024 { 13025 next if(not keys(%{$AddIntParams{$Interface}})); 13026 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}})) 13027 { # add absent parameter names 13028 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"}; 13029 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos}) 13030 { # names from the external file 13031 if(defined $CompleteSignature{$SecondVersion}{$Interface} 13032 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}) 13033 { 13034 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) { 13035 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 13036 } 13037 } 13038 else { 13039 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; 13040 } 13041 } 13042 } 13043 } 13044} 13045 13046sub detectChangedTypedefs() 13047{ # detect changed typedefs to show 13048 # correct function signatures 13049 foreach my $Typedef (keys(%{$Typedef_BaseName{1}})) 13050 { 13051 next if(not $Typedef); 13052 my $BName1 = $Typedef_BaseName{1}{$Typedef}; 13053 if(not $BName1 or isAnon($BName1)) { 13054 next; 13055 } 13056 my $BName2 = $Typedef_BaseName{2}{$Typedef}; 13057 if(not $BName2 or isAnon($BName2)) { 13058 next; 13059 } 13060 if($BName1 ne $BName2) { 13061 $ChangedTypedef{$Typedef} = 1; 13062 } 13063 } 13064} 13065 13066sub get_symbol_suffix($$) 13067{ 13068 my ($Symbol, $Full) = @_; 13069 my ($SN, $SO, $SV) = separate_symbol($Symbol); 13070 $Symbol=$SN; # remove version 13071 my $Signature = $tr_name{$Symbol}; 13072 my $Suffix = substr($Signature, find_center($Signature, "(")); 13073 if(not $Full) { 13074 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g; 13075 } 13076 return $Suffix; 13077} 13078 13079sub get_symbol_prefix($$) 13080{ 13081 my ($Symbol, $LibVersion) = @_; 13082 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; 13083 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 13084 { # methods 13085 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName; 13086 } 13087 return $ShortName; 13088} 13089 13090sub setAlternative($) 13091{ 13092 my $Symbol = $_[0]; 13093 my $PSymbol = $Symbol; 13094 if(not defined $CompleteSignature{2}{$PSymbol} 13095 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"} 13096 and not $CompleteSignature{2}{$PSymbol}{"ShortName"})) 13097 { # search for a pair 13098 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"}) 13099 { 13100 if($CompleteSignature{1}{$PSymbol}{"Data"}) 13101 { 13102 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/ 13103 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/) 13104 { 13105 if(defined $CompleteSignature{2}{$PSymbol} 13106 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13107 { 13108 $SourceAlternative{$Symbol} = $PSymbol; 13109 $SourceAlternative_B{$PSymbol} = $Symbol; 13110 if(not defined $CompleteSignature{1}{$PSymbol} 13111 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 13112 $SourceReplacement{$Symbol} = $PSymbol; 13113 } 13114 } 13115 } 13116 } 13117 else 13118 { 13119 foreach my $Sp ("KV", "VK", "K", "V") 13120 { 13121 if($PSymbol=~s/\A_ZN$Sp/_ZN/ 13122 or $PSymbol=~s/\A_ZN/_ZN$Sp/) 13123 { 13124 if(defined $CompleteSignature{2}{$PSymbol} 13125 and $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13126 { 13127 $SourceAlternative{$Symbol} = $PSymbol; 13128 $SourceAlternative_B{$PSymbol} = $Symbol; 13129 if(not defined $CompleteSignature{1}{$PSymbol} 13130 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { 13131 $SourceReplacement{$Symbol} = $PSymbol; 13132 } 13133 } 13134 } 13135 $PSymbol = $Symbol; 13136 } 13137 } 13138 } 13139 } 13140 return ""; 13141} 13142 13143sub getSymKind($$) 13144{ 13145 my ($Symbol, $LibVersion) = @_; 13146 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}) 13147 { 13148 return "Global_Data"; 13149 } 13150 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 13151 { 13152 return "Method"; 13153 } 13154 return "Function"; 13155} 13156 13157sub mergeSymbols($) 13158{ 13159 my $Level = $_[0]; 13160 my %SubProblems = (); 13161 13162 mergeBases($Level); 13163 13164 my %AddedOverloads = (); 13165 foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) 13166 { # check all added exported symbols 13167 if(not $CompleteSignature{2}{$Symbol}{"Header"}) { 13168 next; 13169 } 13170 if(defined $CompleteSignature{1}{$Symbol} 13171 and $CompleteSignature{1}{$Symbol}{"Header"}) 13172 { # double-check added symbol 13173 next; 13174 } 13175 if(not symbolFilter($Symbol, 2, "Affected", $Level)) { 13176 next; 13177 } 13178 if($Symbol=~/\A(_Z|\?)/) 13179 { # C++ 13180 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol; 13181 } 13182 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"}) 13183 { # register virtual overridings 13184 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"}; 13185 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"}; 13186 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} 13187 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"}) 13188 { 13189 if($TName_Tid{1}{$AffectedClass_Name}) 13190 { # class should exist in previous version 13191 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1)) 13192 { # old v-table is NOT copied by old applications 13193 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=( 13194 "Type_Name"=>$AffectedClass_Name, 13195 "Target"=>get_Signature($Symbol, 2), 13196 "Old_Value"=>get_Signature($OverriddenMethod, 2), 13197 "New_Value"=>get_Signature($Symbol, 2)); 13198 } 13199 } 13200 } 13201 } 13202 } 13203 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) 13204 { # check all removed exported symbols 13205 if(not $CompleteSignature{1}{$Symbol}{"Header"}) { 13206 next; 13207 } 13208 if(defined $CompleteSignature{2}{$Symbol} 13209 and $CompleteSignature{2}{$Symbol}{"Header"}) 13210 { # double-check removed symbol 13211 next; 13212 } 13213 if($CompleteSignature{1}{$Symbol}{"Private"}) 13214 { # skip private methods 13215 next; 13216 } 13217 if(not symbolFilter($Symbol, 1, "Affected", $Level)) { 13218 next; 13219 } 13220 $CheckedSymbols{$Level}{$Symbol} = 1; 13221 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"}) 13222 { # register virtual overridings 13223 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; 13224 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"}; 13225 if(defined $CompleteSignature{2}{$OverriddenMethod} 13226 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"}) 13227 { 13228 if($TName_Tid{2}{$AffectedClass_Name}) 13229 { # class should exist in newer version 13230 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1)) 13231 { # old v-table is NOT copied by old applications 13232 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=( 13233 "Type_Name"=>$AffectedClass_Name, 13234 "Target"=>get_Signature($OverriddenMethod, 1), 13235 "Old_Value"=>get_Signature($Symbol, 1), 13236 "New_Value"=>get_Signature($OverriddenMethod, 1)); 13237 } 13238 } 13239 } 13240 } 13241 if($Level eq "Binary" 13242 and $OStarget eq "windows") 13243 { # register the reason of symbol name change 13244 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}}) 13245 { 13246 if($AddedInt{$Level}{$NewSym}) 13247 { 13248 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"}) 13249 { 13250 if($CompleteSignature{2}{$NewSym}{"Static"}) 13251 { 13252 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=( 13253 "Target"=>$tr_name{$Symbol}, 13254 "Old_Value"=>$Symbol, 13255 "New_Value"=>$NewSym ); 13256 } 13257 else 13258 { 13259 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=( 13260 "Target"=>$tr_name{$Symbol}, 13261 "Old_Value"=>$Symbol, 13262 "New_Value"=>$NewSym ); 13263 } 13264 } 13265 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"}) 13266 { 13267 if($CompleteSignature{2}{$NewSym}{"Virt"}) 13268 { 13269 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=( 13270 "Target"=>$tr_name{$Symbol}, 13271 "Old_Value"=>$Symbol, 13272 "New_Value"=>$NewSym ); 13273 } 13274 else 13275 { 13276 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=( 13277 "Target"=>$tr_name{$Symbol}, 13278 "Old_Value"=>$Symbol, 13279 "New_Value"=>$NewSym ); 13280 } 13281 } 13282 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"}; 13283 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"}; 13284 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"}; 13285 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"}; 13286 if($RTName1 ne $RTName2) 13287 { 13288 my $ProblemType = "Symbol_Changed_Return"; 13289 if($CompleteSignature{1}{$Symbol}{"Data"}) { 13290 $ProblemType = "Global_Data_Symbol_Changed_Type"; 13291 } 13292 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=( 13293 "Target"=>$tr_name{$Symbol}, 13294 "Old_Type"=>$RTName1, 13295 "New_Type"=>$RTName2, 13296 "Old_Value"=>$Symbol, 13297 "New_Value"=>$NewSym ); 13298 } 13299 } 13300 } 13301 } 13302 if($Symbol=~/\A(_Z|\?)/) 13303 { # C++ 13304 my $Prefix = get_symbol_prefix($Symbol, 1); 13305 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}}) 13306 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)}) 13307 { # changed signature: params, "const"-qualifier 13308 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]}; 13309 if($CompleteSignature{1}{$Symbol}{"Constructor"}) 13310 { 13311 if($Symbol=~/(C[1-2][EI])/) 13312 { 13313 my $CtorType = $1; 13314 $NewSym=~s/(C[1-2][EI])/$CtorType/g; 13315 } 13316 } 13317 elsif($CompleteSignature{1}{$Symbol}{"Destructor"}) 13318 { 13319 if($Symbol=~/(D[0-2][EI])/) 13320 { 13321 my $DtorType = $1; 13322 $NewSym=~s/(D[0-2][EI])/$DtorType/g; 13323 } 13324 } 13325 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"}; 13326 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"}; 13327 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2)) 13328 { # from the same class and namespace 13329 if($CompleteSignature{1}{$Symbol}{"Const"} 13330 and not $CompleteSignature{2}{$NewSym}{"Const"}) 13331 { # "const" to non-"const" 13332 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=( 13333 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"}, 13334 "Target"=>$tr_name{$Symbol}, 13335 "New_Signature"=>get_Signature($NewSym, 2), 13336 "Old_Value"=>$Symbol, 13337 "New_Value"=>$NewSym ); 13338 } 13339 elsif(not $CompleteSignature{1}{$Symbol}{"Const"} 13340 and $CompleteSignature{2}{$NewSym}{"Const"}) 13341 { # non-"const" to "const" 13342 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=( 13343 "Target"=>$tr_name{$Symbol}, 13344 "New_Signature"=>get_Signature($NewSym, 2), 13345 "Old_Value"=>$Symbol, 13346 "New_Value"=>$NewSym ); 13347 } 13348 if($CompleteSignature{1}{$Symbol}{"Volatile"} 13349 and not $CompleteSignature{2}{$NewSym}{"Volatile"}) 13350 { # "volatile" to non-"volatile" 13351 13352 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=( 13353 "Target"=>$tr_name{$Symbol}, 13354 "New_Signature"=>get_Signature($NewSym, 2), 13355 "Old_Value"=>$Symbol, 13356 "New_Value"=>$NewSym ); 13357 } 13358 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"} 13359 and $CompleteSignature{2}{$NewSym}{"Volatile"}) 13360 { # non-"volatile" to "volatile" 13361 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=( 13362 "Target"=>$tr_name{$Symbol}, 13363 "New_Signature"=>get_Signature($NewSym, 2), 13364 "Old_Value"=>$Symbol, 13365 "New_Value"=>$NewSym ); 13366 } 13367 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0)) 13368 { # params list 13369 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=( 13370 "Target"=>$tr_name{$Symbol}, 13371 "New_Signature"=>get_Signature($NewSym, 2), 13372 "Old_Value"=>$Symbol, 13373 "New_Value"=>$NewSym ); 13374 } 13375 } 13376 } 13377 } 13378 } 13379 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 13380 { # checking symbols 13381 $CurrentSymbol = $Symbol; 13382 13383 my ($SN, $SS, $SV) = separate_symbol($Symbol); 13384 if($Level eq "Source") 13385 { # remove symbol version 13386 $Symbol=$SN; 13387 } 13388 else 13389 { # Binary 13390 if(not $SV) 13391 { # symbol without version 13392 if(my $VSym = $SymVer{1}{$Symbol}) 13393 { # the symbol is linked with versioned symbol 13394 if($CompleteSignature{2}{$VSym}{"MnglName"}) 13395 { # show report for symbol@ver only 13396 next; 13397 } 13398 elsif(not link_symbol($VSym, 2, "-Deps")) 13399 { # changed version: sym@v1 to sym@v2 13400 # do NOT show report for symbol 13401 next; 13402 } 13403 } 13404 } 13405 } 13406 my $PSymbol = $Symbol; 13407 if($Level eq "Source" 13408 and my $S = $SourceReplacement{$Symbol}) 13409 { # take a source-compatible replacement function 13410 $PSymbol = $S; 13411 } 13412 if($CompleteSignature{1}{$Symbol}{"Private"}) 13413 { # private symbols 13414 next; 13415 } 13416 if(not defined $CompleteSignature{1}{$Symbol} 13417 or not defined $CompleteSignature{2}{$PSymbol}) 13418 { # no info 13419 next; 13420 } 13421 if(not $CompleteSignature{1}{$Symbol}{"MnglName"} 13422 or not $CompleteSignature{2}{$PSymbol}{"MnglName"}) 13423 { # no mangled name 13424 next; 13425 } 13426 if(not $CompleteSignature{1}{$Symbol}{"Header"} 13427 or not $CompleteSignature{2}{$PSymbol}{"Header"}) 13428 { # without a header 13429 next; 13430 } 13431 13432 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} 13433 and $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13434 { # became pure 13435 next; 13436 } 13437 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13438 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13439 { # became non-pure 13440 next; 13441 } 13442 13443 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)) 13444 { # exported, target, inline virtual and pure virtual 13445 next; 13446 } 13447 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level)) 13448 { # exported, target, inline virtual and pure virtual 13449 next; 13450 } 13451 13452 if(checkDump(1, "2.13") and checkDump(2, "2.13")) 13453 { 13454 if($CompleteSignature{1}{$Symbol}{"Data"} 13455 and $CompleteSignature{2}{$PSymbol}{"Data"}) 13456 { 13457 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"}; 13458 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"}; 13459 if(defined $Value1) 13460 { 13461 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1); 13462 if(defined $Value2) 13463 { 13464 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2); 13465 if($Value1 ne $Value2) 13466 { 13467 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=( 13468 "Old_Value"=>$Value1, 13469 "New_Value"=>$Value2, 13470 "Target"=>get_Signature($Symbol, 1) ); 13471 } 13472 } 13473 } 13474 } 13475 } 13476 13477 if($CompleteSignature{2}{$PSymbol}{"Private"}) 13478 { 13479 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=( 13480 "Target"=>get_Signature_M($PSymbol, 2) ); 13481 } 13482 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"} 13483 and $CompleteSignature{2}{$PSymbol}{"Protected"}) 13484 { 13485 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=( 13486 "Target"=>get_Signature_M($PSymbol, 2) ); 13487 } 13488 elsif($CompleteSignature{1}{$Symbol}{"Protected"} 13489 and not $CompleteSignature{2}{$PSymbol}{"Protected"}) 13490 { 13491 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=( 13492 "Target"=>get_Signature_M($PSymbol, 2) ); 13493 } 13494 13495 # checking virtual table 13496 mergeVirtualTables($Symbol, $Level); 13497 13498 if($COMPILE_ERRORS) 13499 { # if some errors occurred at the compiling stage 13500 # then some false positives can be skipped here 13501 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"} 13502 and not $GlobalDataObject{2}{$Symbol}) 13503 { # missed information about parameters in newer version 13504 next; 13505 } 13506 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol} 13507 and not $CompleteSignature{2}{$PSymbol}{"Data"}) 13508 { # missed information about parameters in older version 13509 next; 13510 } 13511 } 13512 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); 13513 # checking attributes 13514 if($CompleteSignature{2}{$PSymbol}{"Static"} 13515 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13516 { 13517 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=( 13518 "Target"=>get_Signature($Symbol, 1) 13519 ); 13520 } 13521 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"} 13522 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) 13523 { 13524 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=( 13525 "Target"=>get_Signature($Symbol, 1) 13526 ); 13527 } 13528 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"}) 13529 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"})) 13530 { # relative position of virtual and pure virtual methods 13531 if($Level eq "Binary") 13532 { 13533 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"} 13534 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"}) 13535 { # top-level virtual methods only 13536 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"}; 13537 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"}; 13538 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name} 13539 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol}) 13540 { # check the absolute position of virtual method (including added and removed methods) 13541 my %Class_Type = get_Type($Class_Id, 1); 13542 my $ProblemType = "Virtual_Method_Position"; 13543 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) { 13544 $ProblemType = "Pure_Virtual_Method_Position"; 13545 } 13546 if(isUsedClass($Class_Id, 1, $Level)) 13547 { 13548 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}})); 13549 foreach my $ASymbol (@Affected) 13550 { 13551 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { 13552 next; 13553 } 13554 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=( 13555 "Type_Name"=>$Class_Type{"Name"}, 13556 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"}, 13557 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"}, 13558 "Target"=>get_Signature($Symbol, 1)); 13559 } 13560 $VTableChanged_M{$Class_Type{"Name"}} = 1; 13561 } 13562 } 13563 } 13564 } 13565 } 13566 if($CompleteSignature{1}{$Symbol}{"PureVirt"} 13567 or $CompleteSignature{2}{$PSymbol}{"PureVirt"}) 13568 { # do NOT check type changes in pure virtuals 13569 next; 13570 } 13571 $CheckedSymbols{$Level}{$Symbol} = 1; 13572 if($Symbol=~/\A(_Z|\?)/ 13573 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13574 { # C/C++: changes in parameters 13575 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13576 { # checking parameters 13577 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1); 13578 } 13579 } 13580 else 13581 { # C: added/removed parameters 13582 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) 13583 { # checking added parameters 13584 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13585 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"}; 13586 last if($PType2_Name eq "..."); 13587 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13588 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:""; 13589 my $ParamPos_Prev = "-1"; 13590 if($PName=~/\Ap\d+\Z/i) 13591 { # added unnamed parameter ( pN ) 13592 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1); 13593 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2); 13594 if($#Positions1==-1 or $#Positions2>$#Positions1) { 13595 $ParamPos_Prev = "lost"; 13596 } 13597 } 13598 else { 13599 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1); 13600 } 13601 if($ParamPos_Prev eq "lost") 13602 { 13603 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13604 { 13605 my $ProblemType = "Added_Parameter"; 13606 if($PName=~/\Ap\d+\Z/) { 13607 $ProblemType = "Added_Unnamed_Parameter"; 13608 } 13609 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13610 "Target"=>$PName, 13611 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13612 "Param_Type"=>$PType2_Name, 13613 "New_Signature"=>get_Signature($Symbol, 2) ); 13614 } 13615 else 13616 { 13617 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2}); 13618 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13619 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1}); 13620 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"}) 13621 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost") 13622 { 13623 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13624 { 13625 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13626 "Target"=>$PName_Old, 13627 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13628 "Param_Type"=>$PType2_Name, 13629 "Old_Value"=>$PName_Old, 13630 "New_Value"=>$PName, 13631 "New_Signature"=>get_Signature($Symbol, 2) ); 13632 } 13633 } 13634 else 13635 { 13636 my $ProblemType = "Added_Middle_Parameter"; 13637 if($PName=~/\Ap\d+\Z/) { 13638 $ProblemType = "Added_Middle_Unnamed_Parameter"; 13639 } 13640 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13641 "Target"=>$PName, 13642 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13643 "Param_Type"=>$PType2_Name, 13644 "New_Signature"=>get_Signature($Symbol, 2) ); 13645 } 13646 } 13647 } 13648 } 13649 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13650 { # check relevant parameters 13651 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13652 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13653 # FIXME: find relevant parameter by name 13654 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}) 13655 { 13656 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13657 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; 13658 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"} 13659 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) { 13660 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0); 13661 } 13662 } 13663 } 13664 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13665 { # checking removed parameters 13666 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; 13667 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"}; 13668 last if($PType1_Name eq "..."); 13669 my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; 13670 my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:""; 13671 my $ParamPos_New = "-1"; 13672 if($PName=~/\Ap\d+\Z/i) 13673 { # removed unnamed parameter ( pN ) 13674 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1); 13675 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2); 13676 if($#Positions2==-1 or $#Positions2<$#Positions1) { 13677 $ParamPos_New = "lost"; 13678 } 13679 } 13680 else { 13681 $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2); 13682 } 13683 if($ParamPos_New eq "lost") 13684 { 13685 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1) 13686 { 13687 my $ProblemType = "Removed_Parameter"; 13688 if($PName=~/\Ap\d+\Z/) { 13689 $ProblemType = "Removed_Unnamed_Parameter"; 13690 } 13691 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13692 "Target"=>$PName, 13693 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13694 "Param_Type"=>$PType1_Name, 13695 "New_Signature"=>get_Signature($Symbol, 2) ); 13696 } 13697 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) 13698 { 13699 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1}); 13700 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; 13701 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2}); 13702 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"}) 13703 and find_ParamPair_Pos_byName($PName_New, $Symbol, 1) eq "lost") 13704 { 13705 if($PName_New!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) 13706 { 13707 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( 13708 "Target"=>$PName, 13709 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13710 "Param_Type"=>$PType1_Name, 13711 "Old_Value"=>$PName, 13712 "New_Value"=>$PName_New, 13713 "New_Signature"=>get_Signature($Symbol, 2) ); 13714 } 13715 } 13716 else 13717 { 13718 my $ProblemType = "Removed_Middle_Parameter"; 13719 if($PName=~/\Ap\d+\Z/) { 13720 $ProblemType = "Removed_Middle_Unnamed_Parameter"; 13721 } 13722 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( 13723 "Target"=>$PName, 13724 "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), 13725 "Param_Type"=>$PType1_Name, 13726 "New_Signature"=>get_Signature($Symbol, 2) ); 13727 } 13728 } 13729 } 13730 } 13731 } 13732 # checking return type 13733 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"}; 13734 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"}; 13735 my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); 13736 13737 foreach my $SubProblemType (keys(%RC_SubProblems)) 13738 { 13739 my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"}; 13740 my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"}; 13741 my %ProblemTypes = (); 13742 13743 if($CompleteSignature{1}{$Symbol}{"Data"}) 13744 { 13745 if($SubProblemType eq "Return_Type_And_Size") { 13746 $ProblemTypes{"Global_Data_Type_And_Size"} = 1; 13747 } 13748 elsif($SubProblemType eq "Return_Type_Format") { 13749 $ProblemTypes{"Global_Data_Type_Format"} = 1; 13750 } 13751 else { 13752 $ProblemTypes{"Global_Data_Type"} = 1; 13753 } 13754 13755 # quals 13756 if($SubProblemType eq "Return_Type" 13757 or $SubProblemType eq "Return_Type_And_Size" 13758 or $SubProblemType eq "Return_Type_Format") 13759 { 13760 if(my $RR = removedQual($Old_Value, $New_Value, "const")) 13761 { # const to non-const 13762 if($RR==2) { 13763 $ProblemTypes{"Global_Data_Removed_Const"} = 1; 13764 } 13765 else { 13766 $ProblemTypes{"Global_Data_Became_Non_Const"} = 1; 13767 } 13768 $ProblemTypes{"Global_Data_Type"} = 1; 13769 } 13770 elsif(my $RA = addedQual($Old_Value, $New_Value, "const")) 13771 { # non-const to const 13772 if($RA==2) { 13773 $ProblemTypes{"Global_Data_Added_Const"} = 1; 13774 } 13775 else { 13776 $ProblemTypes{"Global_Data_Became_Const"} = 1; 13777 } 13778 $ProblemTypes{"Global_Data_Type"} = 1; 13779 } 13780 } 13781 } 13782 else 13783 { 13784 # quals 13785 if($SubProblemType eq "Return_Type" 13786 or $SubProblemType eq "Return_Type_And_Size" 13787 or $SubProblemType eq "Return_Type_Format") 13788 { 13789 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 13790 { 13791 if(addedQual($Old_Value, $New_Value, "volatile")) 13792 { 13793 $ProblemTypes{"Return_Value_Became_Volatile"} = 1; 13794 if($Level ne "Source" 13795 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13796 $ProblemTypes{"Return_Type"} = 1; 13797 } 13798 } 13799 } 13800 if(my $RA = addedQual($Old_Value, $New_Value, "const")) 13801 { 13802 if($RA==2) { 13803 $ProblemTypes{"Return_Type_Added_Const"} = 1; 13804 } 13805 else { 13806 $ProblemTypes{"Return_Type_Became_Const"} = 1; 13807 } 13808 if($Level ne "Source" 13809 or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { 13810 $ProblemTypes{"Return_Type"} = 1; 13811 } 13812 } 13813 } 13814 } 13815 if($Level eq "Binary" 13816 and not $CompleteSignature{1}{$Symbol}{"Data"}) 13817 { 13818 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 13819 if($Arch1 eq "unknown" or $Arch2 eq "unknown") 13820 { # if one of the architectures is unknown 13821 # then set other arhitecture to unknown too 13822 ($Arch1, $Arch2) = ("unknown", "unknown"); 13823 } 13824 my (%Conv1, %Conv2) = (); 13825 if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"}) 13826 { 13827 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol}); 13828 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol}); 13829 } 13830 else 13831 { 13832 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 13833 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 13834 } 13835 13836 if($SubProblemType eq "Return_Type_Became_Void") 13837 { 13838 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13839 { # parameters stack has been affected 13840 if($Conv1{"Method"} eq "stack") { 13841 $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1; 13842 } 13843 elsif($Conv1{"Hidden"}) { 13844 $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1; 13845 } 13846 } 13847 } 13848 elsif($SubProblemType eq "Return_Type_From_Void") 13849 { 13850 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) 13851 { # parameters stack has been affected 13852 if($Conv2{"Method"} eq "stack") { 13853 $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1; 13854 } 13855 elsif($Conv2{"Hidden"}) { 13856 $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1; 13857 } 13858 } 13859 } 13860 elsif($SubProblemType eq "Return_Type" 13861 or $SubProblemType eq "Return_Type_And_Size" 13862 or $SubProblemType eq "Return_Type_Format") 13863 { 13864 if($Conv1{"Method"} ne $Conv2{"Method"}) 13865 { 13866 if($Conv1{"Method"} eq "stack") 13867 { # returns in a register instead of a hidden first parameter 13868 $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1; 13869 } 13870 else { 13871 $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1; 13872 } 13873 } 13874 else 13875 { 13876 if($Conv1{"Method"} eq "reg") 13877 { 13878 if($Conv1{"Registers"} ne $Conv2{"Registers"}) 13879 { 13880 if($Conv1{"Hidden"}) { 13881 $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1; 13882 } 13883 elsif($Conv2{"Hidden"}) { 13884 $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1; 13885 } 13886 else { 13887 $ProblemTypes{"Return_Type_And_Register"} = 1; 13888 } 13889 } 13890 } 13891 } 13892 } 13893 } 13894 13895 if(not keys(%ProblemTypes)) 13896 { # default 13897 $ProblemTypes{$SubProblemType} = 1; 13898 } 13899 13900 foreach my $ProblemType (keys(%ProblemTypes)) 13901 { # additional 13902 $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType}; 13903 } 13904 } 13905 if($ReturnType1_Id and $ReturnType2_Id) 13906 { 13907 @RecurTypes = (); 13908 my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); 13909 13910 my $AddProblems = {}; 13911 13912 if($CompleteSignature{1}{$Symbol}{"Data"}) 13913 { 13914 if($Level eq "Binary") 13915 { 13916 if(get_PLevel($ReturnType1_Id, 1)==0) 13917 { 13918 if(defined $Sub_SubProblems->{"DataType_Size"}) 13919 { # add "Global_Data_Size" problem 13920 13921 foreach my $Loc (keys(%{$Sub_SubProblems->{"DataType_Size"}})) 13922 { 13923 if(index($Loc,"->")==-1) 13924 { 13925 if($Loc eq $Sub_SubProblems->{"DataType_Size"}{$Loc}{"Type_Name"}) 13926 { 13927 $AddProblems->{"Global_Data_Size"}{$Loc} = $Sub_SubProblems->{"DataType_Size"}{$Loc}; # add a new problem 13928 last; 13929 } 13930 } 13931 } 13932 } 13933 } 13934 if(not defined $AddProblems->{"Global_Data_Size"}) 13935 { 13936 if(defined $GlobalDataObject{1}{$Symbol} 13937 and defined $GlobalDataObject{2}{$Symbol}) 13938 { 13939 my $Old_Size = $GlobalDataObject{1}{$Symbol}; 13940 my $New_Size = $GlobalDataObject{2}{$Symbol}; 13941 if($Old_Size!=$New_Size) 13942 { 13943 $AddProblems->{"Global_Data_Size"}{"retval"} = { 13944 "Old_Size"=>$Old_Size*$BYTE_SIZE, 13945 "New_Size"=>$New_Size*$BYTE_SIZE }; 13946 } 13947 } 13948 } 13949 } 13950 } 13951 13952 foreach my $SubProblemType (keys(%{$AddProblems})) 13953 { 13954 foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}})) 13955 { 13956 my $NewLocation = "retval"; 13957 if($SubLocation and $SubLocation ne "retval") { 13958 $NewLocation = "retval->".$SubLocation; 13959 } 13960 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation}; 13961 } 13962 } 13963 13964 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 13965 { 13966 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 13967 { 13968 my $NewLocation = "retval"; 13969 if($SubLocation and $SubLocation ne "retval") { 13970 $NewLocation = "retval->".$SubLocation; 13971 } 13972 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 13973 } 13974 } 13975 } 13976 13977 # checking object type 13978 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"}; 13979 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"}; 13980 if($ObjTId1 and $ObjTId2 13981 and not $CompleteSignature{1}{$Symbol}{"Static"}) 13982 { 13983 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1); 13984 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2); 13985 if($ThisPtr1_Id and $ThisPtr2_Id) 13986 { 13987 @RecurTypes = (); 13988 my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); 13989 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 13990 { 13991 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 13992 { 13993 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this"; 13994 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 13995 } 13996 } 13997 } 13998 } 13999 } 14000 if($Level eq "Binary") { 14001 mergeVTables($Level); 14002 } 14003 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) { 14004 $CheckedSymbols{$Level}{$Symbol} = 1; 14005 } 14006} 14007 14008sub rmQuals($$) 14009{ 14010 my ($Value, $Qual) = @_; 14011 if(not $Qual) { 14012 return $Value; 14013 } 14014 if($Qual eq "all") 14015 { # all quals 14016 $Qual = "const|volatile|restrict"; 14017 } 14018 while($Value=~s/\b$Qual\b//) { 14019 $Value = formatName($Value, "T"); 14020 } 14021 return $Value; 14022} 14023 14024sub cmpBTypes($$$$) 14025{ 14026 my ($T1, $T2, $V1, $V2) = @_; 14027 $T1 = uncover_typedefs($T1, $V1); 14028 $T2 = uncover_typedefs($T2, $V2); 14029 return (rmQuals($T1, "all") eq rmQuals($T2, "all")); 14030} 14031 14032sub addedQual($$$) 14033{ 14034 my ($Old_Value, $New_Value, $Qual) = @_; 14035 return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual); 14036} 14037 14038sub removedQual($$$) 14039{ 14040 my ($Old_Value, $New_Value, $Qual) = @_; 14041 return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual); 14042} 14043 14044sub removedQual_I($$$$$) 14045{ 14046 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_; 14047 $Old_Value = uncover_typedefs($Old_Value, $V1); 14048 $New_Value = uncover_typedefs($New_Value, $V2); 14049 if($Old_Value eq $New_Value) 14050 { # equal types 14051 return 0; 14052 } 14053 if($Old_Value!~/\b$Qual\b/) 14054 { # without a qual 14055 return 0; 14056 } 14057 elsif($New_Value!~/\b$Qual\b/) 14058 { # became non-qual 14059 return 1; 14060 } 14061 else 14062 { 14063 my @BQ1 = getQualModel($Old_Value, $Qual); 14064 my @BQ2 = getQualModel($New_Value, $Qual); 14065 foreach (0 .. $#BQ1) 14066 { # removed qual 14067 if($BQ1[$_]==1 14068 and $BQ2[$_]!=1) 14069 { 14070 return 2; 14071 } 14072 } 14073 } 14074 return 0; 14075} 14076 14077sub getQualModel($$) 14078{ 14079 my ($Value, $Qual) = @_; 14080 if(not $Qual) { 14081 return $Value; 14082 } 14083 14084 # cleaning 14085 while($Value=~/(\w+)/ and $1 ne $Qual) { 14086 $Value=~s/\b$1\b//g; 14087 } 14088 $Value=~s/[^\*\&\w]+//g; 14089 14090 # modeling 14091 # int*const*const == 011 14092 # int**const == 001 14093 my @Model = (); 14094 my @Elems = split(/[\*\&]/, $Value); 14095 if(not @Elems) { 14096 return (0); 14097 } 14098 foreach (@Elems) 14099 { 14100 if($_ eq $Qual) { 14101 push(@Model, 1); 14102 } 14103 else { 14104 push(@Model, 0); 14105 } 14106 } 14107 14108 return @Model; 14109} 14110 14111my %StringTypes = map {$_=>1} ( 14112 "char*", 14113 "char const*" 14114); 14115 14116my %CharTypes = map {$_=>1} ( 14117 "char", 14118 "char const" 14119); 14120 14121sub showVal($$$) 14122{ 14123 my ($Value, $TypeId, $LibVersion) = @_; 14124 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); 14125 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion); 14126 if(substr($Value, 0, 2) eq "_Z") 14127 { 14128 if(my $Unmangled = $tr_name{$Value}) { 14129 return $Unmangled; 14130 } 14131 } 14132 elsif(defined $StringTypes{$TName} or $TName=~/string/i) 14133 { # strings 14134 return "\"$Value\""; 14135 } 14136 elsif(defined $CharTypes{$TName}) 14137 { # characters 14138 return "\'$Value\'"; 14139 } 14140 if($Value eq "") 14141 { # other 14142 return "\'\'"; 14143 } 14144 return $Value; 14145} 14146 14147sub getRegs($$$) 14148{ 14149 my ($LibVersion, $Symbol, $Pos) = @_; 14150 14151 if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"}) 14152 { 14153 my %Regs = (); 14154 foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}})) 14155 { 14156 if($Elem=~/\A$Pos([\.\+]|\Z)/) { 14157 $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1; 14158 } 14159 } 14160 14161 return join(", ", sort keys(%Regs)); 14162 } 14163 elsif(defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"} 14164 and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{0} 14165 and not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{0}{"offset"}) 14166 { 14167 return "unknown"; 14168 } 14169 14170 return undef; 14171} 14172 14173sub mergeParameters($$$$$$) 14174{ 14175 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_; 14176 if(not $Symbol) { 14177 return; 14178 } 14179 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"}; 14180 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"}; 14181 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"}; 14182 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"}; 14183 if(not $PType1_Id 14184 or not $PType2_Id) { 14185 return; 14186 } 14187 14188 if($Symbol=~/\A(_Z|\?)/) 14189 { # do not merge "this" 14190 if($PName1 eq "this" or $PName2 eq "this") { 14191 return; 14192 } 14193 } 14194 14195 my %Type1 = get_Type($PType1_Id, 1); 14196 my %Type2 = get_Type($PType2_Id, 2); 14197 14198 my %PureType1 = get_PureType($PType1_Id, $TypeInfo{1}); 14199 14200 my %BaseType1 = get_BaseType($PType1_Id, 1); 14201 my %BaseType2 = get_BaseType($PType2_Id, 2); 14202 14203 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter"; 14204 14205 if($Level eq "Binary") 14206 { 14207 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1")) 14208 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format) 14209 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14210 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14211 { 14212 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=( 14213 "Target"=>$PName1, 14214 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14215 } 14216 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} 14217 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) 14218 { 14219 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=( 14220 "Target"=>$PName1, 14221 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); 14222 } 14223 } 14224 14225 if(defined $UsedDump{1}{"DWARF"} 14226 and defined $UsedDump{2}{"DWARF"}) 14227 { 14228 if(checkDump(1, "3.0") and checkDump(2, "3.0")) 14229 { 14230 my $Old_Regs = getRegs(1, $Symbol, $ParamPos1); 14231 my $New_Regs = getRegs(2, $PSymbol, $ParamPos2); 14232 14233 if($Old_Regs ne "unknown" 14234 and $New_Regs ne "unknown") 14235 { 14236 if($Old_Regs and $New_Regs) 14237 { 14238 if($Old_Regs ne $New_Regs) 14239 { 14240 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=( 14241 "Target"=>$PName1, 14242 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14243 "Old_Value"=>$Old_Regs, 14244 "New_Value"=>$New_Regs ); 14245 } 14246 } 14247 elsif($Old_Regs and not $New_Regs) 14248 { 14249 %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=( 14250 "Target"=>$PName1, 14251 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14252 "Old_Value"=>$Old_Regs ); 14253 } 14254 elsif(not $Old_Regs and $New_Regs) 14255 { 14256 %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=( 14257 "Target"=>$PName1, 14258 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14259 "New_Value"=>$New_Regs ); 14260 } 14261 } 14262 14263 if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne "" 14264 and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "") 14265 { 14266 if($Old_Offset ne $New_Offset) 14267 { 14268 my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"}; 14269 my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"}; 14270 14271 $Old_Offset = $Old_Offset - $Start1; 14272 $New_Offset = $New_Offset - $Start2; 14273 14274 if($Old_Offset ne $New_Offset) 14275 { 14276 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( 14277 "Target"=>$PName1, 14278 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14279 "Old_Value"=>$Old_Offset, 14280 "New_Value"=>$New_Offset ); 14281 } 14282 } 14283 } 14284 } 14285 } 14286 } 14287 if(checkDump(1, "2.0") and checkDump(2, "2.0") 14288 and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1") 14289 { # "default" attribute added in ACC 1.22 (dump 2.0 format) 14290 # broken in 3.1, fixed in 3.2 14291 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"}; 14292 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"}; 14293 if(not checkDump(1, "2.13") 14294 and checkDump(2, "2.13")) 14295 { # support for old ABI dumps 14296 if(defined $Value_Old and defined $Value_New) 14297 { 14298 if($PureType1{"Name"} eq "bool" 14299 and $Value_Old eq "false" and $Value_New eq "0") 14300 { # int class::method ( bool p = 0 ); 14301 # old ABI dumps: "false" 14302 # new ABI dumps: "0" 14303 $Value_Old = "0"; 14304 } 14305 } 14306 } 14307 if(not checkDump(1, "2.18") 14308 and checkDump(2, "2.18")) 14309 { # support for old ABI dumps 14310 if(not defined $Value_Old 14311 and substr($Value_New, 0, 2) eq "_Z") { 14312 $Value_Old = $Value_New; 14313 } 14314 } 14315 if(defined $Value_Old) 14316 { 14317 $Value_Old = showVal($Value_Old, $PType1_Id, 1); 14318 if(defined $Value_New) 14319 { 14320 $Value_New = showVal($Value_New, $PType2_Id, 2); 14321 if($Value_Old ne $Value_New) 14322 { # FIXME: how to distinguish "0" and 0 (NULL) 14323 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=( 14324 "Target"=>$PName1, 14325 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14326 "Old_Value"=>$Value_Old, 14327 "New_Value"=>$Value_New ); 14328 } 14329 } 14330 else 14331 { 14332 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=( 14333 "Target"=>$PName1, 14334 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14335 "Old_Value"=>$Value_Old ); 14336 } 14337 } 14338 elsif(defined $Value_New) 14339 { 14340 $Value_New = showVal($Value_New, $PType2_Id, 2); 14341 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=( 14342 "Target"=>$PName1, 14343 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14344 "New_Value"=>$Value_New ); 14345 } 14346 } 14347 14348 if($ChkRnmd) 14349 { 14350 if($PName1 and $PName2 and $PName1 ne $PName2 14351 and $PType1_Id!=-1 and $PType2_Id!=-1 14352 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/) 14353 { # except unnamed "..." value list (Id=-1) 14354 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=( 14355 "Target"=>$PName1, 14356 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14357 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, 14358 "Old_Value"=>$PName1, 14359 "New_Value"=>$PName2, 14360 "New_Signature"=>get_Signature($Symbol, 2) ); 14361 } 14362 } 14363 14364 # checking type change (replace) 14365 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level); 14366 14367 foreach my $SubProblemType (keys(%SubProblems)) 14368 { # add new problems, remove false alarms 14369 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14370 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14371 14372 # quals 14373 if($SubProblemType eq "Parameter_Type" 14374 or $SubProblemType eq "Parameter_Type_And_Size" 14375 or $SubProblemType eq "Parameter_Type_Format") 14376 { 14377 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14378 { 14379 if(addedQual($Old_Value, $New_Value, "restrict")) { 14380 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14381 } 14382 elsif(removedQual($Old_Value, $New_Value, "restrict")) { 14383 %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}}; 14384 } 14385 } 14386 if(checkDump(1, "2.6") and checkDump(2, "2.6")) 14387 { 14388 if(removedQual($Old_Value, $New_Value, "volatile")) { 14389 %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}}; 14390 } 14391 } 14392 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"} 14393 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14394 { # int to "int const" 14395 delete($SubProblems{$SubProblemType}); 14396 } 14397 elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"} 14398 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) 14399 { # "int const" to int 14400 delete($SubProblems{$SubProblemType}); 14401 } 14402 elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) 14403 { # "const" to non-"const" 14404 if($RR==2) { 14405 %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}}; 14406 } 14407 else { 14408 %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}}; 14409 } 14410 } 14411 } 14412 } 14413 14414 if($Level eq "Source") 14415 { 14416 foreach my $SubProblemType (keys(%SubProblems)) 14417 { 14418 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14419 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14420 14421 if($SubProblemType eq "Parameter_Type") 14422 { 14423 if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { 14424 delete($SubProblems{$SubProblemType}); 14425 } 14426 } 14427 } 14428 } 14429 14430 foreach my $SubProblemType (keys(%SubProblems)) 14431 { # modify/register problems 14432 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; 14433 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; 14434 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"}; 14435 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"}; 14436 14437 my $NewProblemType = $SubProblemType; 14438 if($Old_Value eq "..." and $New_Value ne "...") 14439 { # change from "..." to "int" 14440 if($ParamPos1==0) 14441 { # ISO C requires a named argument before "..." 14442 next; 14443 } 14444 $NewProblemType = "Parameter_Became_Non_VaList"; 14445 } 14446 elsif($New_Value eq "..." and $Old_Value ne "...") 14447 { # change from "int" to "..." 14448 if($ParamPos2==0) 14449 { # ISO C requires a named argument before "..." 14450 next; 14451 } 14452 $NewProblemType = "Parameter_Became_VaList"; 14453 } 14454 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size" 14455 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format")) 14456 { 14457 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 14458 if($Arch1 eq "unknown" 14459 or $Arch2 eq "unknown") 14460 { # if one of the architectures is unknown 14461 # then set other arhitecture to unknown too 14462 ($Arch1, $Arch2) = ("unknown", "unknown"); 14463 } 14464 my (%Conv1, %Conv2) = (); 14465 if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"}) 14466 { # real 14467 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1); 14468 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2); 14469 } 14470 else 14471 { # model 14472 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); 14473 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); 14474 } 14475 if($Conv1{"Method"} eq $Conv2{"Method"}) 14476 { 14477 if($Conv1{"Method"} eq "stack") 14478 { 14479 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset 14480 $NewProblemType = "Parameter_Type_And_Stack"; 14481 } 14482 } 14483 elsif($Conv1{"Method"} eq "reg") 14484 { 14485 if($Conv1{"Registers"} ne $Conv2{"Registers"}) { 14486 $NewProblemType = "Parameter_Type_And_Register"; 14487 } 14488 } 14489 } 14490 elsif($Conv1{"Method"} ne "unknown" 14491 and $Conv2{"Method"} ne "unknown") 14492 { 14493 if($Conv1{"Method"} eq "stack") { 14494 $NewProblemType = "Parameter_Type_From_Stack_To_Register"; 14495 } 14496 elsif($Conv1{"Method"} eq "register") { 14497 $NewProblemType = "Parameter_Type_From_Register_To_Stack"; 14498 } 14499 } 14500 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"}; 14501 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"}; 14502 } 14503 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=( 14504 "Target"=>$PName1, 14505 "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), 14506 "New_Signature"=>get_Signature($Symbol, 2) ); 14507 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; 14508 } 14509 14510 @RecurTypes = (); 14511 14512 # checking type definition changes 14513 my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level); 14514 foreach my $SubProblemType (keys(%{$Sub_SubProblems})) 14515 { 14516 foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) 14517 { 14518 my $NewProblemType = $SubProblemType; 14519 if($SubProblemType eq "DataType_Size") 14520 { 14521 if($PureType1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) 14522 { # stack has been affected 14523 $NewProblemType = "DataType_Size_And_Stack"; 14524 } 14525 } 14526 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location; 14527 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; 14528 } 14529 } 14530} 14531 14532sub find_ParamPair_Pos_byName($$$) 14533{ 14534 my ($Name, $Symbol, $LibVersion) = @_; 14535 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14536 { 14537 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14538 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name) 14539 { 14540 return $ParamPos; 14541 } 14542 } 14543 return "lost"; 14544} 14545 14546sub find_ParamPair_Pos_byTypeAndPos($$$$$) 14547{ 14548 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_; 14549 my @Positions = (); 14550 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) 14551 { 14552 next if($Order eq "backward" and $ParamPos>$MediumPos); 14553 next if($Order eq "forward" and $ParamPos<$MediumPos); 14554 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); 14555 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"}; 14556 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) { 14557 push(@Positions, $ParamPos); 14558 } 14559 } 14560 return @Positions; 14561} 14562 14563sub getTypeIdByName($$) 14564{ 14565 my ($TypeName, $LibVersion) = @_; 14566 return $TName_Tid{$LibVersion}{formatName($TypeName, "T")}; 14567} 14568 14569sub diffTypes($$$) 14570{ 14571 if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) { 14572 return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}; 14573 } 14574 if(isRecurType($_[0], $_[1], \@RecurTypes_Diff)) 14575 { # skip recursive declarations 14576 return 0; 14577 } 14578 14579 pushType($_[0], $_[1], \@RecurTypes_Diff); 14580 my $Diff = diffTypes_I(@_); 14581 pop(@RecurTypes_Diff); 14582 14583 return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff); 14584} 14585 14586sub diffTypes_I($$$) 14587{ 14588 my ($Type1_Id, $Type2_Id, $Level) = @_; 14589 14590 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14591 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14592 14593 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) 14594 { # equal types 14595 return 0; 14596 } 14597 if($Type1_Pure{"Name"} eq "void") 14598 { # from void* to something 14599 return 0; 14600 } 14601 if($Type1_Pure{"Name"}=~/\*/ 14602 or $Type2_Pure{"Name"}=~/\*/) 14603 { # compared in detectTypeChange() 14604 return 0; 14605 } 14606 14607 my %FloatType = map {$_=>1} ( 14608 "float", 14609 "double", 14610 "long double" 14611 ); 14612 14613 my $T1 = $Type1_Pure{"Type"}; 14614 my $T2 = $Type2_Pure{"Type"}; 14615 14616 if($T1 eq "Struct" 14617 and $T2 eq "Class") 14618 { # compare as data structures 14619 $T2 = "Struct"; 14620 } 14621 14622 if($T1 eq "Class" 14623 and $T2 eq "Struct") 14624 { # compare as data structures 14625 $T1 = "Struct"; 14626 } 14627 14628 if($T1 ne $T2) 14629 { # different types 14630 if($T1 eq "Intrinsic" 14631 and $T2 eq "Enum") 14632 { # "int" to "enum" 14633 return 0; 14634 } 14635 elsif($T2 eq "Intrinsic" 14636 and $T1 eq "Enum") 14637 { # "enum" to "int" 14638 return 0; 14639 } 14640 else 14641 { # union to struct 14642 # ... 14643 return 1; 14644 } 14645 } 14646 else 14647 { 14648 if($T1 eq "Intrinsic") 14649 { 14650 if($FloatType{$Type1_Pure{"Name"}} 14651 or $FloatType{$Type2_Pure{"Name"}}) 14652 { # "float" to "double" 14653 # "float" to "int" 14654 if($Level eq "Source") 14655 { # Safe 14656 return 0; 14657 } 14658 else { 14659 return 1; 14660 } 14661 } 14662 } 14663 elsif($T1=~/Class|Struct|Union|Enum/) 14664 { 14665 my @Membs1 = keys(%{$Type1_Pure{"Memb"}}); 14666 my @Membs2 = keys(%{$Type2_Pure{"Memb"}}); 14667 if(not @Membs1 14668 or not @Membs2) 14669 { # private 14670 return 0; 14671 } 14672 if($#Membs1!=$#Membs2) 14673 { # different number of elements 14674 return 1; 14675 } 14676 if($T1 eq "Enum") 14677 { 14678 foreach my $Pos (@Membs1) 14679 { # compare elements by name and value 14680 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"} 14681 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"}) 14682 { # different names 14683 return 1; 14684 } 14685 } 14686 } 14687 else 14688 { 14689 foreach my $Pos (@Membs1) 14690 { 14691 if($Level eq "Source") 14692 { 14693 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}) 14694 { # different names 14695 return 1; 14696 } 14697 } 14698 14699 my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}}; 14700 my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}}; 14701 14702 if($MT1{"Name"} ne $MT2{"Name"} 14703 or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"})) 14704 { 14705 my $PL1 = get_PLevel($MT1{"Tid"}, 1); 14706 my $PL2 = get_PLevel($MT2{"Tid"}, 2); 14707 14708 if($PL1 ne $PL2) 14709 { # different pointer level 14710 return 1; 14711 } 14712 14713 # compare base types 14714 my %BT1 = get_BaseType($MT1{"Tid"}, 1); 14715 my %BT2 = get_BaseType($MT2{"Tid"}, 2); 14716 14717 if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level)) 14718 { # different types 14719 return 1; 14720 } 14721 } 14722 } 14723 } 14724 } 14725 else 14726 { 14727 # TODO: arrays, etc. 14728 } 14729 } 14730 return 0; 14731} 14732 14733sub detectTypeChange($$$$) 14734{ 14735 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_; 14736 if(not $Type1_Id or not $Type2_Id) { 14737 return (); 14738 } 14739 my %LocalProblems = (); 14740 my %Type1 = get_Type($Type1_Id, 1); 14741 my %Type2 = get_Type($Type2_Id, 2); 14742 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); 14743 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); 14744 14745 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1); 14746 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2); 14747 14748 if(defined $UsedDump{1}{"DWARF"}) 14749 { 14750 if($Type1_Pure{"Name"} eq "__unknown__" 14751 or $Type2_Pure{"Name"} eq "__unknown__" 14752 or $Type1_Base{"Name"} eq "__unknown__" 14753 or $Type2_Base{"Name"} eq "__unknown__") 14754 { # Error ABI dump 14755 return (); 14756 } 14757 } 14758 14759 my $Type1_PLevel = get_PLevel($Type1_Id, 1); 14760 my $Type2_PLevel = get_PLevel($Type2_Id, 2); 14761 return () if(not $Type1{"Name"} or not $Type2{"Name"}); 14762 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"}); 14763 return () if($Type1_PLevel eq "" or $Type2_PLevel eq ""); 14764 if($Type1_Base{"Name"} ne $Type2_Base{"Name"} 14765 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel 14766 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void"))) 14767 { # base type change 14768 if($Type1{"Name"} eq $Type2{"Name"}) 14769 { 14770 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef") 14771 { # will be reported in mergeTypes() as typedef problem 14772 return (); 14773 } 14774 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); 14775 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); 14776 if(%Typedef_1 and %Typedef_2) 14777 { 14778 if($Typedef_1{"Name"} eq $Typedef_2{"Name"} 14779 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef") 14780 { # const Typedef 14781 return (); 14782 } 14783 } 14784 } 14785 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/) 14786 { 14787 if($Level eq "Binary" 14788 and $Type1_Base{"Size"} and $Type2_Base{"Size"} 14789 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}) 14790 { 14791 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=( 14792 "Old_Value"=>$Type1_Base{"Name"}, 14793 "New_Value"=>$Type2_Base{"Name"}, 14794 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14795 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14796 } 14797 else 14798 { 14799 if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level)) 14800 { # format change 14801 %{$LocalProblems{$Prefix."_BaseType_Format"}}=( 14802 "Old_Value"=>$Type1_Base{"Name"}, 14803 "New_Value"=>$Type2_Base{"Name"}, 14804 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14805 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14806 } 14807 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"})) 14808 { 14809 %{$LocalProblems{$Prefix."_BaseType"}}=( 14810 "Old_Value"=>$Type1_Base{"Name"}, 14811 "New_Value"=>$Type2_Base{"Name"}, 14812 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, 14813 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); 14814 } 14815 } 14816 } 14817 } 14818 elsif($Type1{"Name"} ne $Type2{"Name"}) 14819 { # type change 14820 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/) 14821 { 14822 if($Prefix eq "Return" 14823 and $Type1_Pure{"Name"} eq "void") 14824 { 14825 %{$LocalProblems{"Return_Type_From_Void"}}=( 14826 "New_Value"=>$Type2{"Name"}, 14827 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14828 } 14829 elsif($Prefix eq "Return" 14830 and $Type2_Pure{"Name"} eq "void") 14831 { 14832 %{$LocalProblems{"Return_Type_Became_Void"}}=( 14833 "Old_Value"=>$Type1{"Name"}, 14834 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE); 14835 } 14836 else 14837 { 14838 if($Level eq "Binary" 14839 and $Type1{"Size"} and $Type2{"Size"} 14840 and $Type1{"Size"} ne $Type2{"Size"}) 14841 { 14842 %{$LocalProblems{$Prefix."_Type_And_Size"}}=( 14843 "Old_Value"=>$Type1{"Name"}, 14844 "New_Value"=>$Type2{"Name"}, 14845 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14846 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14847 } 14848 else 14849 { 14850 if(diffTypes($Type1_Id, $Type2_Id, $Level)) 14851 { # format change 14852 %{$LocalProblems{$Prefix."_Type_Format"}}=( 14853 "Old_Value"=>$Type1{"Name"}, 14854 "New_Value"=>$Type2{"Name"}, 14855 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14856 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14857 } 14858 elsif(tNameLock($Type1_Id, $Type2_Id)) 14859 { # FIXME: correct this condition 14860 %{$LocalProblems{$Prefix."_Type"}}=( 14861 "Old_Value"=>$Type1{"Name"}, 14862 "New_Value"=>$Type2{"Name"}, 14863 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, 14864 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); 14865 } 14866 } 14867 } 14868 } 14869 } 14870 if($Type1_PLevel!=$Type2_PLevel) 14871 { 14872 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..." 14873 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...") 14874 { 14875 if($Level eq "Source") 14876 { 14877 %{$LocalProblems{$Prefix."_PointerLevel"}}=( 14878 "Old_Value"=>$Type1_PLevel, 14879 "New_Value"=>$Type2_PLevel); 14880 } 14881 else 14882 { 14883 if($Type2_PLevel>$Type1_PLevel) 14884 { 14885 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=( 14886 "Old_Value"=>$Type1_PLevel, 14887 "New_Value"=>$Type2_PLevel); 14888 } 14889 else 14890 { 14891 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=( 14892 "Old_Value"=>$Type1_PLevel, 14893 "New_Value"=>$Type2_PLevel); 14894 } 14895 } 14896 } 14897 } 14898 if($Type1_Pure{"Type"} eq "Array" 14899 and $Type1_Pure{"BaseType"}) 14900 { # base_type[N] -> base_type[N] 14901 # base_type: older_structure -> typedef to newer_structure 14902 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level); 14903 foreach my $SubProblemType (keys(%SubProblems)) 14904 { 14905 $SubProblemType=~s/_Type/_BaseType/g; 14906 next if(defined $LocalProblems{$SubProblemType}); 14907 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) { 14908 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr}; 14909 } 14910 } 14911 } 14912 return %LocalProblems; 14913} 14914 14915sub tNameLock($$) 14916{ 14917 my ($Tid1, $Tid2) = @_; 14918 my $Changed = 0; 14919 if(differentDumps("G")) 14920 { # different GCC versions 14921 $Changed = 1; 14922 } 14923 elsif(differentDumps("V")) 14924 { # different versions of ABI dumps 14925 if(not checkDump(1, "2.20") 14926 or not checkDump(2, "2.20")) 14927 { # latest names update 14928 # 2.6: added restrict qualifier 14929 # 2.13: added missed typedefs to qualified types 14930 # 2.20: prefix for struct, union and enum types 14931 $Changed = 1; 14932 } 14933 } 14934 14935 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"}; 14936 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"}; 14937 14938 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"}; 14939 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"}; 14940 14941 if($Changed) 14942 { # different formats 14943 my %Base1 = get_Type($Tid1, 1); 14944 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") { 14945 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1}); 14946 } 14947 my %Base2 = get_Type($Tid2, 2); 14948 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") { 14949 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2}); 14950 } 14951 my $BName1 = uncover_typedefs($Base1{"Name"}, 1); 14952 my $BName2 = uncover_typedefs($Base2{"Name"}, 2); 14953 if($BName1 eq $BName2) 14954 { # equal base types 14955 return 0; 14956 } 14957 14958 if(not checkDump(1, "2.13") 14959 or not checkDump(2, "2.13")) 14960 { # broken array names in ABI dumps < 2.13 14961 if($TT1 eq "Array" 14962 and $TT2 eq "Array") { 14963 return 0; 14964 } 14965 } 14966 14967 if(not checkDump(1, "2.6") 14968 or not checkDump(2, "2.6")) 14969 { # added restrict attribute in 2.6 14970 if($TN1!~/\brestrict\b/ 14971 and $TN2=~/\brestrict\b/) { 14972 return 0; 14973 } 14974 } 14975 14976 if(not checkDump(1, "2.20") 14977 or not checkDump(2, "2.20")) 14978 { # added type prefix in 2.20 14979 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/ 14980 or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 14981 return 0; 14982 } 14983 } 14984 } 14985 else 14986 { 14987 # typedef struct {...} type_t 14988 # typedef struct type_t {...} type_t 14989 if(index($TN1, " ".$TN2)!=-1) 14990 { 14991 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) { 14992 return 0; 14993 } 14994 } 14995 if(index($TN2, " ".$TN1)!=-1) 14996 { 14997 if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { 14998 return 0; 14999 } 15000 } 15001 15002 if($TT1 eq "FuncPtr" 15003 and $TT2 eq "FuncPtr") 15004 { 15005 my $TN1_C = $TN1; 15006 my $TN2_C = $TN2; 15007 15008 $TN1_C=~s/\b(struct|union) //g; 15009 $TN2_C=~s/\b(struct|union) //g; 15010 15011 if($TN1_C eq $TN2_C) { 15012 return 0; 15013 } 15014 } 15015 } 15016 15017 my ($N1, $N2) = ($TN1, $TN2); 15018 $N1=~s/\b(struct|union) //g; 15019 $N2=~s/\b(struct|union) //g; 15020 15021 if($N1 eq $N2) 15022 { # QList<struct QUrl> and QList<QUrl> 15023 return 0; 15024 } 15025 15026 return 1; 15027} 15028 15029sub differentDumps($) 15030{ 15031 my $Check = $_[0]; 15032 if(defined $Cache{"differentDumps"}{$Check}) { 15033 return $Cache{"differentDumps"}{$Check}; 15034 } 15035 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"}) 15036 { 15037 if($Check eq "G") 15038 { 15039 if(getGccVersion(1) ne getGccVersion(2)) 15040 { # different GCC versions 15041 return ($Cache{"differentDumps"}{$Check}=1); 15042 } 15043 } 15044 if($Check eq "V") 15045 { 15046 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2), 15047 formatVersion($UsedDump{2}{"V"}, 2))!=0) 15048 { # different dump versions (skip micro version) 15049 return ($Cache{"differentDumps"}{$Check}=1); 15050 } 15051 } 15052 } 15053 return ($Cache{"differentDumps"}{$Check}=0); 15054} 15055 15056sub formatVersion($$) 15057{ # cut off version digits 15058 my ($V, $Digits) = @_; 15059 my @Elems = split(/\./, $V); 15060 return join(".", splice(@Elems, 0, $Digits)); 15061} 15062 15063sub htmlSpecChars($) 15064{ 15065 my $Str = $_[0]; 15066 if(not $Str) { 15067 return $Str; 15068 } 15069 $Str=~s/\&([^#]|\Z)/&$1/g; 15070 $Str=~s/</</g; 15071 $Str=~s/\-\>/->/g; # − 15072 $Str=~s/>/>/g; 15073 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 15074 $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; 15075 $Str=~s/ / /g; # 15076 $Str=~s/\@SP\@/ /g; 15077 $Str=~s/\n/<br\/>/g; 15078 $Str=~s/\"/"/g; 15079 $Str=~s/\'/'/g; 15080 return $Str; 15081} 15082 15083sub xmlSpecChars($) 15084{ 15085 my $Str = $_[0]; 15086 if(not $Str) { 15087 return $Str; 15088 } 15089 15090 $Str=~s/\&([^#]|\Z)/&$1/g; 15091 $Str=~s/</</g; 15092 $Str=~s/>/>/g; 15093 15094 $Str=~s/\"/"/g; 15095 $Str=~s/\'/'/g; 15096 15097 return $Str; 15098} 15099 15100sub xmlSpecChars_R($) 15101{ 15102 my $Str = $_[0]; 15103 if(not $Str) { 15104 return $Str; 15105 } 15106 15107 $Str=~s/&/&/g; 15108 $Str=~s/</</g; 15109 $Str=~s/>/>/g; 15110 15111 $Str=~s/"/"/g; 15112 $Str=~s/'/'/g; 15113 15114 return $Str; 15115} 15116 15117sub black_name($) 15118{ 15119 my $Name = $_[0]; 15120 return "<span class='iname_b'>".highLight_Signature($Name)."</span>"; 15121} 15122 15123sub highLight_Signature($) 15124{ 15125 my $Signature = $_[0]; 15126 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0); 15127} 15128 15129sub highLight_Signature_Italic_Color($) 15130{ 15131 my $Signature = $_[0]; 15132 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1); 15133} 15134 15135sub separate_symbol($) 15136{ 15137 my $Symbol = $_[0]; 15138 my ($Name, $Spec, $Ver) = ($Symbol, "", ""); 15139 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) { 15140 ($Name, $Spec, $Ver) = ($1, $2, $3); 15141 } 15142 return ($Name, $Spec, $Ver); 15143} 15144 15145sub cut_f_attrs($) 15146{ 15147 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) { 15148 return $2; 15149 } 15150 return ""; 15151} 15152 15153sub highLight_Signature_PPos_Italic($$$$$) 15154{ 15155 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_; 15156 $Param_Pos = "" if(not defined $Param_Pos); 15157 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature); 15158 my $Return = ""; 15159 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) { 15160 $Return = $2; 15161 } 15162 my $SCenter = find_center($Signature, "("); 15163 if(not $SCenter) 15164 { # global data 15165 $Signature = htmlSpecChars($Signature); 15166 $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g; 15167 $Signature .= (($SymbolVersion)?"<span class='sym_ver'> $VersionSpec $SymbolVersion</span>":""); 15168 if($Return and $ShowReturn) { 15169 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15170 } 15171 return $Signature; 15172 } 15173 my ($Begin, $End) = (substr($Signature, 0, $SCenter), ""); 15174 $Begin.=" " if($Begin!~/ \Z/); 15175 $End = cut_f_attrs($Signature); 15176 my @Parts = (); 15177 my ($Short, $Params) = split_Signature($Signature); 15178 my @SParts = separate_Params($Params, 1, 1); 15179 foreach my $Pos (0 .. $#SParts) 15180 { 15181 my $Part = $SParts[$Pos]; 15182 $Part=~s/\A\s+|\s+\Z//g; 15183 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), ""); 15184 if($Part=~/\([\*]+(\w+)\)/i) { 15185 $ParamName = $1;#func-ptr 15186 } 15187 elsif($Part=~/(\w+)[\,\)]*\Z/i) { 15188 $ParamName = $1; 15189 } 15190 if(not $ParamName) 15191 { 15192 push(@Parts, $Part_Styled); 15193 next; 15194 } 15195 if($ItalicParams and not $TName_Tid{1}{$Part} 15196 and not $TName_Tid{2}{$Part}) 15197 { 15198 my $Style = "param"; 15199 if($Param_Pos ne "" 15200 and $Pos==$Param_Pos) { 15201 $Style = "focus_p"; 15202 } 15203 elsif($ColorParams) { 15204 $Style = "color_p"; 15205 } 15206 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig; 15207 } 15208 $Part_Styled=~s/,(\w)/, $1/g; 15209 push(@Parts, $Part_Styled); 15210 } 15211 if(@Parts) 15212 { 15213 foreach my $Num (0 .. $#Parts) 15214 { 15215 if($Num==$#Parts) 15216 { # add ")" to the last parameter 15217 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>"; 15218 } 15219 elsif(length($Parts[$Num])<=45) { 15220 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>"; 15221 } 15222 } 15223 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( ".join(" ", @Parts)."</span>".$End; 15224 } 15225 else { 15226 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>( )</span>".$End; 15227 } 15228 if($Return and $ShowReturn) { 15229 $Signature .= "<span class='sym_p nowrap'>  <b>:</b>  ".htmlSpecChars($Return)."</span>"; 15230 } 15231 $Signature=~s!\[\]![ ]!g; 15232 $Signature=~s!operator=!operator =!g; 15233 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g; 15234 if($SymbolVersion) { 15235 $Signature .= "<span class='sym_ver'> $VersionSpec $SymbolVersion</span>"; 15236 } 15237 return $Signature; 15238} 15239 15240sub split_Signature($) 15241{ 15242 my $Signature = $_[0]; 15243 if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) 15244 { 15245 $Signature=~s/\A\Q$ShortName\E\(//g; 15246 cut_f_attrs($Signature); 15247 $Signature=~s/\)\Z//; 15248 return ($ShortName, $Signature); 15249 } 15250 15251 # error 15252 return ($Signature, ""); 15253} 15254 15255sub separate_Params($$$) 15256{ 15257 my ($Params, $Comma, $Sp) = @_; 15258 my @Parts = (); 15259 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15260 my $Part = 0; 15261 foreach my $Pos (0 .. length($Params) - 1) 15262 { 15263 my $S = substr($Params, $Pos, 1); 15264 if(defined $B{$S}) { 15265 $B{$S} += 1; 15266 } 15267 if($S eq "," and 15268 $B{"("}==$B{")"} and $B{"<"}==$B{">"}) 15269 { 15270 if($Comma) 15271 { # include comma 15272 $Parts[$Part] .= $S; 15273 } 15274 $Part += 1; 15275 } 15276 else { 15277 $Parts[$Part] .= $S; 15278 } 15279 } 15280 if(not $Sp) 15281 { # remove spaces 15282 foreach (@Parts) 15283 { 15284 s/\A //g; 15285 s/ \Z//g; 15286 } 15287 } 15288 return @Parts; 15289} 15290 15291sub find_center($$) 15292{ 15293 my ($Sign, $Target) = @_; 15294 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); 15295 my $Center = 0; 15296 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g) 15297 { # operators 15298 $Center+=length($1); 15299 } 15300 foreach my $Pos (0 .. length($Sign)-1) 15301 { 15302 my $S = substr($Sign, $Pos, 1); 15303 if($S eq $Target) 15304 { 15305 if($B{"("}==$B{")"} 15306 and $B{"<"}==$B{">"}) { 15307 return $Center; 15308 } 15309 } 15310 if(defined $B{$S}) { 15311 $B{$S}+=1; 15312 } 15313 $Center+=1; 15314 } 15315 return 0; 15316} 15317 15318sub appendFile($$) 15319{ 15320 my ($Path, $Content) = @_; 15321 return if(not $Path); 15322 if(my $Dir = get_dirname($Path)) { 15323 mkpath($Dir); 15324 } 15325 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n"); 15326 print FILE $Content; 15327 close(FILE); 15328} 15329 15330sub writeFile($$) 15331{ 15332 my ($Path, $Content) = @_; 15333 return if(not $Path); 15334 if(my $Dir = get_dirname($Path)) { 15335 mkpath($Dir); 15336 } 15337 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n"); 15338 print FILE $Content; 15339 close(FILE); 15340} 15341 15342sub readFile($) 15343{ 15344 my $Path = $_[0]; 15345 return "" if(not $Path or not -f $Path); 15346 open(FILE, $Path); 15347 local $/ = undef; 15348 my $Content = <FILE>; 15349 close(FILE); 15350 if($Path!~/\.(tu|class|abi)\Z/) { 15351 $Content=~s/\r/\n/g; 15352 } 15353 return $Content; 15354} 15355 15356sub get_filename($) 15357{ # much faster than basename() from File::Basename module 15358 if(defined $Cache{"get_filename"}{$_[0]}) { 15359 return $Cache{"get_filename"}{$_[0]}; 15360 } 15361 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) { 15362 return ($Cache{"get_filename"}{$_[0]}=$1); 15363 } 15364 return ($Cache{"get_filename"}{$_[0]}=""); 15365} 15366 15367sub get_dirname($) 15368{ # much faster than dirname() from File::Basename module 15369 if(defined $Cache{"get_dirname"}{$_[0]}) { 15370 return $Cache{"get_dirname"}{$_[0]}; 15371 } 15372 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) { 15373 return ($Cache{"get_dirname"}{$_[0]}=$1); 15374 } 15375 return ($Cache{"get_dirname"}{$_[0]}=""); 15376} 15377 15378sub separate_path($) { 15379 return (get_dirname($_[0]), get_filename($_[0])); 15380} 15381 15382sub esc($) 15383{ 15384 my $Str = $_[0]; 15385 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g; 15386 return $Str; 15387} 15388 15389sub readLineNum($$) 15390{ 15391 my ($Path, $Num) = @_; 15392 return "" if(not $Path or not -f $Path); 15393 open(FILE, $Path); 15394 foreach (1 ... $Num) { 15395 <FILE>; 15396 } 15397 my $Line = <FILE>; 15398 close(FILE); 15399 return $Line; 15400} 15401 15402sub readAttributes($$) 15403{ 15404 my ($Path, $Num) = @_; 15405 return () if(not $Path or not -f $Path); 15406 my %Attributes = (); 15407 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/) 15408 { 15409 foreach my $AttrVal (split(/;/, $1)) 15410 { 15411 if($AttrVal=~/(.+):(.+)/) 15412 { 15413 my ($Name, $Value) = ($1, $2); 15414 $Attributes{$Name} = $Value; 15415 } 15416 } 15417 } 15418 return \%Attributes; 15419} 15420 15421sub is_abs($) { 15422 return ($_[0]=~/\A(\/|\w+:[\/\\])/); 15423} 15424 15425sub get_abs_path($) 15426{ # abs_path() should NOT be called for absolute inputs 15427 # because it can change them 15428 my $Path = $_[0]; 15429 if(not is_abs($Path)) { 15430 $Path = abs_path($Path); 15431 } 15432 return $Path; 15433} 15434 15435sub get_OSgroup() 15436{ 15437 my $N = $Config{"osname"}; 15438 if($N=~/macos|darwin|rhapsody/i) { 15439 return "macos"; 15440 } 15441 elsif($N=~/freebsd|openbsd|netbsd/i) { 15442 return "bsd"; 15443 } 15444 elsif($N=~/haiku|beos/i) { 15445 return "beos"; 15446 } 15447 elsif($N=~/symbian|epoc/i) { 15448 return "symbian"; 15449 } 15450 elsif($N=~/win/i) { 15451 return "windows"; 15452 } 15453 else { 15454 return $N; 15455 } 15456} 15457 15458sub getGccVersion($) 15459{ 15460 my $LibVersion = $_[0]; 15461 if($GCC_VERSION{$LibVersion}) 15462 { # dump version 15463 return $GCC_VERSION{$LibVersion}; 15464 } 15465 elsif($UsedDump{$LibVersion}{"V"}) 15466 { # old-version dumps 15467 return "unknown"; 15468 } 15469 my $GccVersion = get_dumpversion($GCC_PATH); # host version 15470 if(not $GccVersion) { 15471 return "unknown"; 15472 } 15473 return $GccVersion; 15474} 15475 15476sub showArch($) 15477{ 15478 my $Arch = $_[0]; 15479 if($Arch eq "arm" 15480 or $Arch eq "mips") { 15481 return uc($Arch); 15482 } 15483 return $Arch; 15484} 15485 15486sub getArch($) 15487{ 15488 my $LibVersion = $_[0]; 15489 15490 if($TargetArch) { 15491 return $TargetArch; 15492 } 15493 elsif($CPU_ARCH{$LibVersion}) 15494 { # dump 15495 return $CPU_ARCH{$LibVersion}; 15496 } 15497 elsif($UsedDump{$LibVersion}{"V"}) 15498 { # old-version dumps 15499 return "unknown"; 15500 } 15501 15502 return getArch_GCC($LibVersion); 15503} 15504 15505sub get_Report_Title($) 15506{ 15507 my $Level = $_[0]; 15508 15509 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>"; 15510 if(getArch(1) ne getArch(2) 15511 or getArch(1) eq "unknown" 15512 or $Level eq "Source") 15513 { # don't show architecture in the header 15514 $ArchInfo=""; 15515 } 15516 my $Title = ""; 15517 if($Level eq "Source") { 15518 $Title .= "Source compatibility"; 15519 } 15520 elsif($Level eq "Binary") { 15521 $Title .= "Binary compatibility"; 15522 } 15523 else { 15524 $Title .= "API compatibility"; 15525 } 15526 15527 my $V1 = $Descriptor{1}{"Version"}; 15528 my $V2 = $Descriptor{2}{"Version"}; 15529 15530 if($UsedDump{1}{"DWARF"} and $UsedDump{2}{"DWARF"}) 15531 { 15532 my $M1 = $UsedDump{1}{"M"}; 15533 my $M2 = $UsedDump{2}{"M"}; 15534 15535 my $M1S = $M1; 15536 my $M2S = $M2; 15537 15538 $M1S=~s/(\.so|\.ko)\..+/$1/ig; 15539 $M2S=~s/(\.so|\.ko)\..+/$1/ig; 15540 15541 if($M1S eq $M2S 15542 and $V1 ne "X" and $V2 ne "Y") 15543 { 15544 $Title .= " report for the <span style='color:Blue;'>$M1S</span> $TargetComponent"; 15545 $Title .= " between <span style='color:Red;'>".$V1."</span> and <span style='color:Red;'>".$V2."</span> versions"; 15546 } 15547 else 15548 { 15549 $Title .= " report between <span style='color:Blue;'>$M1</span> (<span style='color:Red;'>".$V1."</span>)"; 15550 $Title .= " and <span style='color:Blue;'>$M2</span> (<span style='color:Red;'>".$V2."</span>) objects"; 15551 } 15552 } 15553 else 15554 { 15555 $Title .= " report for the <span style='color:Blue;'>$TargetTitle</span> $TargetComponent"; 15556 $Title .= " between <span style='color:Red;'>".$V1."</span> and <span style='color:Red;'>".$V2."</span> versions"; 15557 } 15558 15559 $Title .= $ArchInfo; 15560 15561 if($AppPath) { 15562 $Title .= " (relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)"; 15563 } 15564 $Title = "<h1>".$Title."</h1>\n"; 15565 return $Title; 15566} 15567 15568sub get_CheckedHeaders($) 15569{ 15570 my $LibVersion = $_[0]; 15571 15572 my @Headers = (); 15573 15574 foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) 15575 { 15576 my $File = get_filename($Path); 15577 15578 if(not is_target_header($File, $LibVersion)) { 15579 next; 15580 } 15581 15582 if(skipHeader($File, $LibVersion)) { 15583 next; 15584 } 15585 15586 push(@Headers, $Path); 15587 } 15588 15589 return @Headers; 15590} 15591 15592sub get_SourceInfo() 15593{ 15594 my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", ""); 15595 15596 if(my @Headers = get_CheckedHeaders(1)) 15597 { 15598 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".($#Headers+1).")</h2><hr/>\n"; 15599 $CheckedHeaders .= "<div class='h_list'>\n"; 15600 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 15601 { 15602 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"}; 15603 my $Name = get_filename($Identity); 15604 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15605 $CheckedHeaders .= $Name.$Comment."<br/>\n"; 15606 } 15607 $CheckedHeaders .= "</div>\n"; 15608 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n"; 15609 } 15610 15611 if(my @Sources = keys(%{$Registered_Sources{1}})) 15612 { 15613 $CheckedSources = "<a name='Sources'></a><h2>Source Files (".($#Sources+1).")</h2><hr/>\n"; 15614 $CheckedSources .= "<div class='h_list'>\n"; 15615 foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 15616 { 15617 my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"}; 15618 my $Name = get_filename($Identity); 15619 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15620 $CheckedSources .= $Name.$Comment."<br/>\n"; 15621 } 15622 $CheckedSources .= "</div>\n"; 15623 $CheckedSources .= "<br/>$TOP_REF<br/>\n"; 15624 } 15625 15626 if(not $CheckHeadersOnly) 15627 { 15628 $CheckedLibs = "<a name='Libs'></a><h2>".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n"; 15629 $CheckedLibs .= "<div class='lib_list'>\n"; 15630 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) 15631 { 15632 # $Library .= " (.$LIB_EXT)" if($Library!~/\.\w+\Z/); 15633 $CheckedLibs .= $Library."<br/>\n"; 15634 } 15635 $CheckedLibs .= "</div>\n"; 15636 $CheckedLibs .= "<br/>$TOP_REF<br/>\n"; 15637 } 15638 15639 return $CheckedHeaders.$CheckedSources.$CheckedLibs; 15640} 15641 15642sub get_ObjTitle() 15643{ 15644 if(defined $UsedDump{1}{"DWARF"}) { 15645 return "Objects"; 15646 } 15647 else { 15648 return ucfirst($SLIB_TYPE)." Libraries"; 15649 } 15650} 15651 15652sub get_TypeProblems_Count($$$) 15653{ 15654 my ($TypeChanges, $TargetPriority, $Level) = @_; 15655 my $Type_Problems_Count = 0; 15656 foreach my $Type_Name (sort keys(%{$TypeChanges})) 15657 { 15658 my %Kinds_Target = (); 15659 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}})) 15660 { 15661 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}})) 15662 { 15663 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"}; 15664 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15665 next if($Severity ne $TargetPriority); 15666 if($Kinds_Target{$Kind}{$Target}) { 15667 next; 15668 } 15669 15670 if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}) 15671 { 15672 if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 15673 { # select a problem with the highest priority 15674 next; 15675 } 15676 } 15677 $Kinds_Target{$Kind}{$Target} = 1; 15678 $Type_Problems_Count += 1; 15679 } 15680 } 15681 } 15682 return $Type_Problems_Count; 15683} 15684 15685sub get_Summary($) 15686{ 15687 my $Level = $_[0]; 15688 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High, 15689 $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); 15690 %{$RESULT{$Level}} = ( 15691 "Problems"=>0, 15692 "Warnings"=>0, 15693 "Affected"=>0 ); 15694 # check rules 15695 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15696 { 15697 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 15698 { 15699 if(not defined $CompatRules{$Level}{$Kind}) 15700 { # unknown rule 15701 if(not $UnknownRules{$Level}{$Kind}) 15702 { # only one warning 15703 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15704 $UnknownRules{$Level}{$Kind}=1; 15705 } 15706 delete($CompatProblems{$Level}{$Interface}{$Kind}); 15707 } 15708 } 15709 } 15710 foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}})) 15711 { 15712 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 15713 { 15714 if(not defined $CompatRules{$Level}{$Kind}) 15715 { # unknown rule 15716 if(not $UnknownRules{$Level}{$Kind}) 15717 { # only one warning 15718 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 15719 $UnknownRules{$Level}{$Kind}=1; 15720 } 15721 delete($CompatProblems_Constants{$Level}{$Constant}{$Kind}); 15722 } 15723 } 15724 } 15725 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15726 { 15727 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 15728 { 15729 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols") 15730 { 15731 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 15732 { 15733 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15734 if($Kind eq "Added_Symbol") { 15735 $Added += 1; 15736 } 15737 elsif($Kind eq "Removed_Symbol") 15738 { 15739 $Removed += 1; 15740 $TotalAffected{$Level}{$Interface} = $Severity; 15741 } 15742 else 15743 { 15744 if($Severity eq "Safe") { 15745 $I_Other += 1; 15746 } 15747 elsif($Severity eq "High") { 15748 $I_Problems_High += 1; 15749 } 15750 elsif($Severity eq "Medium") { 15751 $I_Problems_Medium += 1; 15752 } 15753 elsif($Severity eq "Low") { 15754 $I_Problems_Low += 1; 15755 } 15756 if(($Severity ne "Low" or $StrictCompat) 15757 and $Severity ne "Safe") { 15758 $TotalAffected{$Level}{$Interface} = $Severity; 15759 } 15760 } 15761 } 15762 } 15763 } 15764 } 15765 my %TypeChanges = (); 15766 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 15767 { 15768 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 15769 { 15770 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 15771 { 15772 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 15773 { 15774 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; 15775 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; 15776 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15777 my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}; 15778 15779 if($MaxSeverity and $Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 15780 { # select a problem with the highest priority 15781 next; 15782 } 15783 15784 if(($Severity ne "Low" or $StrictCompat) 15785 and $Severity ne "Safe") 15786 { 15787 if(defined $TotalAffected{$Level}{$Interface}) 15788 { 15789 if($Severity_Val{$Severity}>$Severity_Val{$TotalAffected{$Level}{$Interface}}) { 15790 $TotalAffected{$Level}{$Interface} = $Severity; 15791 } 15792 } 15793 else { 15794 $TotalAffected{$Level}{$Interface} = $Severity; 15795 } 15796 } 15797 15798 $TypeChanges{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; 15799 15800 if($MaxSeverity) 15801 { 15802 if($Severity_Val{$Severity}>$Severity_Val{$MaxSeverity}) { 15803 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; 15804 } 15805 } 15806 else { 15807 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; 15808 } 15809 } 15810 } 15811 } 15812 } 15813 15814 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level); 15815 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level); 15816 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level); 15817 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level); 15818 15819 %TypeChanges = (); # free memory 15820 15821 # changed and removed public symbols 15822 my $SCount = keys(%{$CheckedSymbols{$Level}}); 15823 if($ExtendedCheck) 15824 { # don't count external_func_0 for constants 15825 $SCount-=1; 15826 } 15827 if($SCount) 15828 { 15829 my %Weight = ( 15830 "High" => 100, 15831 "Medium" => 50, 15832 "Low" => 25 15833 ); 15834 foreach (keys(%{$TotalAffected{$Level}})) { 15835 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}}; 15836 } 15837 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount; 15838 } 15839 else { 15840 $RESULT{$Level}{"Affected"} = 0; 15841 } 15842 15843 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"}); 15844 if($RESULT{$Level}{"Affected"}>=100) { 15845 $RESULT{$Level}{"Affected"} = 100; 15846 } 15847 15848 $RESULT{$Level}{"Problems"} += $Removed; 15849 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High; 15850 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium; 15851 if($StrictCompat) { 15852 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low; 15853 } 15854 else { 15855 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low; 15856 } 15857 15858 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 15859 { 15860 foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 15861 { 15862 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 15863 if($Severity eq "Safe") 15864 { 15865 $C_Other+=1; 15866 } 15867 elsif($Severity eq "Low") 15868 { 15869 $C_Problems_Low+=1; 15870 } 15871 } 15872 } 15873 15874 if($C_Problems_Low) 15875 { 15876 if($StrictCompat) { 15877 $RESULT{$Level}{"Problems"} += $C_Problems_Low; 15878 } 15879 else { 15880 $RESULT{$Level}{"Warnings"} += $C_Problems_Low; 15881 } 15882 } 15883 if($RESULT{$Level}{"Problems"} 15884 and $RESULT{$Level}{"Affected"}) { 15885 $RESULT{$Level}{"Verdict"} = "incompatible"; 15886 } 15887 else { 15888 $RESULT{$Level}{"Verdict"} = "compatible"; 15889 } 15890 15891 my $TotalTypes = keys(%{$CheckedTypes{$Level}}); 15892 if(not $TotalTypes) 15893 { # list all the types 15894 $TotalTypes = keys(%{$TName_Tid{1}}); 15895 } 15896 15897 my ($Arch1, $Arch2) = (getArch(1), getArch(2)); 15898 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2)); 15899 15900 my ($TestInfo, $TestResults, $Problem_Summary) = (); 15901 15902 if($ReportFormat eq "xml") 15903 { # XML 15904 # test info 15905 $TestInfo .= " <library>$TargetLibraryName</library>\n"; 15906 $TestInfo .= " <version1>\n"; 15907 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n"; 15908 $TestInfo .= " <arch>$Arch1</arch>\n"; 15909 $TestInfo .= " <gcc>$GccV1</gcc>\n"; 15910 $TestInfo .= " </version1>\n"; 15911 15912 $TestInfo .= " <version2>\n"; 15913 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n"; 15914 $TestInfo .= " <arch>$Arch2</arch>\n"; 15915 $TestInfo .= " <gcc>$GccV2</gcc>\n"; 15916 $TestInfo .= " </version2>\n"; 15917 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n"; 15918 15919 # test results 15920 if(my @Headers = keys(%{$Registered_Headers{1}})) 15921 { 15922 $TestResults .= " <headers>\n"; 15923 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) 15924 { 15925 my $Identity = $Registered_Headers{1}{$Name}{"Identity"}; 15926 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15927 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 15928 } 15929 $TestResults .= " </headers>\n"; 15930 } 15931 15932 if(my @Sources = keys(%{$Registered_Sources{1}})) 15933 { 15934 $TestResults .= " <sources>\n"; 15935 foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) 15936 { 15937 my $Identity = $Registered_Sources{1}{$Name}{"Identity"}; 15938 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; 15939 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n"; 15940 } 15941 $TestResults .= " </sources>\n"; 15942 } 15943 15944 $TestResults .= " <libs>\n"; 15945 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) 15946 { 15947 # $Library .= " (.$LIB_EXT)" if($Library!~/\.\w+\Z/); 15948 $TestResults .= " <name>$Library</name>\n"; 15949 } 15950 $TestResults .= " </libs>\n"; 15951 15952 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n"; 15953 $TestResults .= " <types>".$TotalTypes."</types>\n"; 15954 15955 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n"; 15956 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n"; 15957 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n"; 15958 15959 # problem summary 15960 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n"; 15961 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n"; 15962 15963 $Problem_Summary .= " <problems_with_types>\n"; 15964 $Problem_Summary .= " <high>$T_Problems_High</high>\n"; 15965 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n"; 15966 $Problem_Summary .= " <low>$T_Problems_Low</low>\n"; 15967 $Problem_Summary .= " <safe>$T_Other</safe>\n"; 15968 $Problem_Summary .= " </problems_with_types>\n"; 15969 15970 $Problem_Summary .= " <problems_with_symbols>\n"; 15971 $Problem_Summary .= " <high>$I_Problems_High</high>\n"; 15972 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n"; 15973 $Problem_Summary .= " <low>$I_Problems_Low</low>\n"; 15974 $Problem_Summary .= " <safe>$I_Other</safe>\n"; 15975 $Problem_Summary .= " </problems_with_symbols>\n"; 15976 15977 $Problem_Summary .= " <problems_with_constants>\n"; 15978 $Problem_Summary .= " <low>$C_Problems_Low</low>\n"; 15979 $Problem_Summary .= " </problems_with_constants>\n"; 15980 15981 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n"; 15982 15983 return ($TestInfo.$TestResults.$Problem_Summary, ""); 15984 } 15985 else 15986 { # HTML 15987 # test info 15988 $TestInfo = "<h2>Test Info</h2><hr/>\n"; 15989 $TestInfo .= "<table class='summary'>\n"; 15990 15991 if($TargetComponent eq "library") { 15992 $TestInfo .= "<tr><th>Library Name</th><td>$TargetTitle</td></tr>\n"; 15993 } 15994 else { 15995 $TestInfo .= "<tr><th>Module Name</th><td>$TargetTitle</td></tr>\n"; 15996 } 15997 15998 my (@VInf1, @VInf2, $AddTestInfo) = (); 15999 if($Arch1 ne "unknown" 16000 and $Arch2 ne "unknown") 16001 { # CPU arch 16002 if($Arch1 eq $Arch2) 16003 { # go to the separate section 16004 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n"; 16005 } 16006 else 16007 { # go to the version number 16008 push(@VInf1, showArch($Arch1)); 16009 push(@VInf2, showArch($Arch2)); 16010 } 16011 } 16012 if($GccV1 ne "unknown" 16013 and $GccV2 ne "unknown" 16014 and $OStarget ne "windows") 16015 { # GCC version 16016 if($GccV1 eq $GccV2) 16017 { # go to the separate section 16018 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n"; 16019 } 16020 else 16021 { # go to the version number 16022 push(@VInf1, "gcc ".$GccV1); 16023 push(@VInf2, "gcc ".$GccV2); 16024 } 16025 } 16026 # show long version names with GCC version and CPU architecture name (if different) 16027 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n"; 16028 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n"; 16029 $TestInfo .= $AddTestInfo; 16030 #if($COMMON_LANGUAGE{1}) { 16031 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n"; 16032 #} 16033 if($ExtendedCheck) { 16034 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n"; 16035 } 16036 if($JoinReport) 16037 { 16038 if($Level eq "Binary") { 16039 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time 16040 } 16041 if($Level eq "Source") { 16042 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time 16043 } 16044 } 16045 $TestInfo .= "</table>\n"; 16046 16047 # test results 16048 $TestResults = "<h2>Test Results</h2><hr/>\n"; 16049 $TestResults .= "<table class='summary'>"; 16050 16051 if(my @Headers = get_CheckedHeaders(1)) 16052 { 16053 my $Headers_Link = "<a href='#Headers' style='color:Blue;'>".($#Headers + 1)."</a>"; 16054 $TestResults .= "<tr><th>Total Header Files</th><td>".$Headers_Link."</td></tr>\n"; 16055 } 16056 16057 if(my @Sources = keys(%{$Registered_Sources{1}})) 16058 { 16059 my $Src_Link = "<a href='#Sources' style='color:Blue;'>".($#Sources + 1)."</a>"; 16060 $TestResults .= "<tr><th>Total Source Files</th><td>".$Src_Link."</td></tr>\n"; 16061 } 16062 16063 if(not $ExtendedCheck) 16064 { 16065 my $Libs_Link = "0"; 16066 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0); 16067 $TestResults .= "<tr><th>Total ".get_ObjTitle()."</th><td>".($CheckHeadersOnly?"0 (not analyzed)":$Libs_Link)."</td></tr>\n"; 16068 } 16069 16070 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n"; 16071 16072 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";"; 16073 if($JoinReport) { 16074 $META_DATA = "kind:".lc($Level).";".$META_DATA; 16075 } 16076 $TestResults .= "<tr><th>Verdict</th>"; 16077 if($RESULT{$Level}{"Verdict"} eq "incompatible") { 16078 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>"; 16079 } 16080 else { 16081 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>"; 16082 } 16083 $TestResults .= "</tr>\n"; 16084 $TestResults .= "</table>\n"; 16085 16086 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents 16087 # problem summary 16088 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n"; 16089 $Problem_Summary .= "<table class='summary'>"; 16090 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>"; 16091 16092 my $Added_Link = "0"; 16093 if($Added>0) 16094 { 16095 if($JoinReport) { 16096 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>"; 16097 } 16098 else { 16099 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>"; 16100 } 16101 } 16102 $META_DATA .= "added:$Added;"; 16103 $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n"; 16104 16105 my $Removed_Link = "0"; 16106 if($Removed>0) 16107 { 16108 if($JoinReport) { 16109 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>" 16110 } 16111 else { 16112 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>" 16113 } 16114 } 16115 $META_DATA .= "removed:$Removed;"; 16116 $Problem_Summary .= "<tr><th>Removed Symbols</th>"; 16117 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n"; 16118 16119 my $TH_Link = "0"; 16120 $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0); 16121 $META_DATA .= "type_problems_high:$T_Problems_High;"; 16122 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>"; 16123 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n"; 16124 16125 my $TM_Link = "0"; 16126 $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0); 16127 $META_DATA .= "type_problems_medium:$T_Problems_Medium;"; 16128 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n"; 16129 16130 my $TL_Link = "0"; 16131 $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0); 16132 $META_DATA .= "type_problems_low:$T_Problems_Low;"; 16133 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n"; 16134 16135 my $IH_Link = "0"; 16136 $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0); 16137 $META_DATA .= "interface_problems_high:$I_Problems_High;"; 16138 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>"; 16139 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n"; 16140 16141 my $IM_Link = "0"; 16142 $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0); 16143 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;"; 16144 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n"; 16145 16146 my $IL_Link = "0"; 16147 $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0); 16148 $META_DATA .= "interface_problems_low:$I_Problems_Low;"; 16149 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n"; 16150 16151 my $ChangedConstants_Link = "0"; 16152 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) { 16153 $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>"; 16154 } 16155 $META_DATA .= "changed_constants:$C_Problems_Low;"; 16156 $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n"; 16157 16158 # Safe Changes 16159 if($T_Other) 16160 { 16161 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>"; 16162 $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n"; 16163 $META_DATA .= "type_changes_other:$T_Other;"; 16164 } 16165 16166 if($I_Other) 16167 { 16168 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>"; 16169 $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n"; 16170 $META_DATA .= "interface_changes_other:$I_Other;"; 16171 } 16172 16173 if($C_Other) 16174 { 16175 my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>"; 16176 $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "S", $C_Other).">$CS_Link</td></tr>\n"; 16177 $META_DATA .= "constant_changes_other:$C_Other;"; 16178 } 16179 16180 $META_DATA .= "tool_version:$TOOL_VERSION"; 16181 $Problem_Summary .= "</table>\n"; 16182 # $TestInfo = getLegend().$TestInfo; 16183 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA); 16184 } 16185} 16186 16187sub getStyle($$$) 16188{ 16189 my ($Subj, $Act, $Num) = @_; 16190 my %Style = ( 16191 "A"=>"new", 16192 "R"=>"failed", 16193 "S"=>"passed", 16194 "L"=>"warning", 16195 "M"=>"failed", 16196 "H"=>"failed" 16197 ); 16198 if($Num>0) { 16199 return " class='".$Style{$Act}."'"; 16200 } 16201 return ""; 16202} 16203 16204sub show_number($) 16205{ 16206 if($_[0]) 16207 { 16208 my $Num = cut_off_number($_[0], 2, 0); 16209 if($Num eq "0") 16210 { 16211 foreach my $P (3 .. 7) 16212 { 16213 $Num = cut_off_number($_[0], $P, 1); 16214 if($Num ne "0") { 16215 last; 16216 } 16217 } 16218 } 16219 if($Num eq "0") { 16220 $Num = $_[0]; 16221 } 16222 return $Num; 16223 } 16224 return $_[0]; 16225} 16226 16227sub cut_off_number($$$) 16228{ 16229 my ($num, $digs_to_cut, $z) = @_; 16230 if($num!~/\./) 16231 { 16232 $num .= "."; 16233 foreach (1 .. $digs_to_cut-1) { 16234 $num .= "0"; 16235 } 16236 } 16237 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1) 16238 { 16239 foreach (1 .. $digs_to_cut - 1 - length($1)) { 16240 $num .= "0"; 16241 } 16242 } 16243 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) { 16244 $num=sprintf("%.".($digs_to_cut-1)."f", $num); 16245 } 16246 $num=~s/\.[0]+\Z//g; 16247 if($z) { 16248 $num=~s/(\.[1-9]+)[0]+\Z/$1/g; 16249 } 16250 return $num; 16251} 16252 16253sub get_Report_ChangedConstants($$) 16254{ 16255 my ($TargetSeverity, $Level) = @_; 16256 my $CHANGED_CONSTANTS = ""; 16257 16258 my %ReportMap = (); 16259 foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) 16260 { 16261 my $Header = $Constants{1}{$Constant}{"Header"}; 16262 if(not $Header) 16263 { # added 16264 $Header = $Constants{2}{$Constant}{"Header"} 16265 } 16266 16267 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}})) 16268 { 16269 if(not defined $CompatRules{$Level}{$Kind}) { 16270 next; 16271 } 16272 if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) { 16273 next; 16274 } 16275 $ReportMap{$Header}{$Constant}{$Kind} = 1; 16276 } 16277 } 16278 16279 if($ReportFormat eq "xml") 16280 { # XML 16281 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16282 { 16283 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n"; 16284 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16285 { 16286 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n"; 16287 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16288 { 16289 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16290 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16291 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}; 16292 16293 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n"; 16294 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n"; 16295 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n"; 16296 if($Overcome) { 16297 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n"; 16298 } 16299 $CHANGED_CONSTANTS .= " </problem>\n"; 16300 } 16301 $CHANGED_CONSTANTS .= " </constant>\n"; 16302 } 16303 $CHANGED_CONSTANTS .= " </header>\n"; 16304 } 16305 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n"; 16306 } 16307 else 16308 { # HTML 16309 my $Number = 0; 16310 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16311 { 16312 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n"; 16313 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16314 { 16315 my $Report = ""; 16316 16317 foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) 16318 { 16319 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind}); 16320 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16321 $Report .= "<tr>\n<th>1</th>\n<td align='left' valign='top'>".$Change."</td>\n<td align='left' valign='top'>$Effect</td>\n</tr>\n"; 16322 $Number += 1; 16323 } 16324 if($Report) 16325 { 16326 $Report = $ContentDivStart."<table class='ptable'>\n<tr>\n<th width='2%'></th>\n<th width='47%'>Change</th>\n<th>Effect</th>\n</tr>\n".$Report."</table>\n<br/>\n$ContentDivEnd\n"; 16327 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report; 16328 $Report = insertIDs($Report); 16329 } 16330 $CHANGED_CONSTANTS .= $Report; 16331 } 16332 $CHANGED_CONSTANTS .= "<br/>\n"; 16333 } 16334 if($CHANGED_CONSTANTS) 16335 { 16336 my $Title = "Problems with Constants, $TargetSeverity Severity"; 16337 if($TargetSeverity eq "Safe") 16338 { # Safe Changes 16339 $Title = "Other Changes in Constants"; 16340 } 16341 $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a><h2>$Title ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n"; 16342 } 16343 } 16344 return $CHANGED_CONSTANTS; 16345} 16346 16347sub getTitle($$$) 16348{ 16349 my ($Header, $Library, $NameSpace) = @_; 16350 my $Title = ""; 16351 16352 # if($Library and $Library!~/\.\w+\Z/) { 16353 # $Library .= " (.$LIB_EXT)"; 16354 # } 16355 16356 if($Header and $Library) 16357 { 16358 $Title .= "<span class='h_name'>$Header</span>"; 16359 $Title .= ", <span class='lib_name'>$Library</span><br/>\n"; 16360 } 16361 elsif($Library) { 16362 $Title .= "<span class='lib_name'>$Library</span><br/>\n"; 16363 } 16364 elsif($Header) { 16365 $Title .= "<span class='h_name'>$Header</span><br/>\n"; 16366 } 16367 if($NameSpace) { 16368 $Title .= "<span class='ns'>namespace <b>$NameSpace</b></span><br/>\n"; 16369 } 16370 return $Title; 16371} 16372 16373sub get_Report_Added($) 16374{ 16375 my $Level = $_[0]; 16376 my $ADDED_INTERFACES = ""; 16377 my %ReportMap = (); 16378 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 16379 { 16380 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) 16381 { 16382 if($Kind eq "Added_Symbol") 16383 { 16384 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"}; 16385 my $DyLib = $Symbol_Library{2}{$Interface}; 16386 if($Level eq "Source" and $ReportFormat eq "html") 16387 { # do not show library name in HTML report 16388 $DyLib = ""; 16389 } 16390 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1; 16391 } 16392 } 16393 } 16394 if($ReportFormat eq "xml") 16395 { # XML 16396 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16397 { 16398 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16399 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16400 { 16401 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16402 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16403 $ADDED_INTERFACES .= " <name>$Interface</name>\n"; 16404 } 16405 $ADDED_INTERFACES .= " </library>\n"; 16406 } 16407 $ADDED_INTERFACES .= " </header>\n"; 16408 } 16409 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n"; 16410 } 16411 else 16412 { # HTML 16413 my $Added_Number = 0; 16414 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16415 { 16416 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16417 { 16418 my %NameSpaceSymbols = (); 16419 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16420 $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1; 16421 } 16422 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16423 { 16424 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16425 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16426 foreach my $Interface (@SortedInterfaces) 16427 { 16428 $Added_Number += 1; 16429 my $Signature = get_Signature($Interface, 2); 16430 if($NameSpace) { 16431 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16432 } 16433 if($Interface=~/\A(_Z|\?)/) 16434 { 16435 if($Signature) { 16436 $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>\n<br/>\n<br/>\n".$ContentDivEnd."\n"); 16437 } 16438 else { 16439 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16440 } 16441 } 16442 else 16443 { 16444 if($Signature) { 16445 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16446 } 16447 else { 16448 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n"; 16449 } 16450 } 16451 } 16452 $ADDED_INTERFACES .= "<br/>\n"; 16453 } 16454 } 16455 } 16456 if($ADDED_INTERFACES) 16457 { 16458 my $Anchor = "<a name='Added'></a>"; 16459 if($JoinReport) { 16460 $Anchor = "<a name='".$Level."_Added'></a>"; 16461 } 16462 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n"; 16463 } 16464 } 16465 return $ADDED_INTERFACES; 16466} 16467 16468sub get_Report_Removed($) 16469{ 16470 my $Level = $_[0]; 16471 my $REMOVED_INTERFACES = ""; 16472 my %ReportMap = (); 16473 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16474 { 16475 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16476 { 16477 if($Kind eq "Removed_Symbol") 16478 { 16479 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16480 my $DyLib = $Symbol_Library{1}{$Symbol}; 16481 if($Level eq "Source" and $ReportFormat eq "html") 16482 { # do not show library name in HTML report 16483 $DyLib = ""; 16484 } 16485 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16486 } 16487 } 16488 } 16489 if($ReportFormat eq "xml") 16490 { # XML 16491 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16492 { 16493 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n"; 16494 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16495 { 16496 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n"; 16497 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16498 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n"; 16499 } 16500 $REMOVED_INTERFACES .= " </library>\n"; 16501 } 16502 $REMOVED_INTERFACES .= " </header>\n"; 16503 } 16504 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n"; 16505 } 16506 else 16507 { # HTML 16508 my $Removed_Number = 0; 16509 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16510 { 16511 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16512 { 16513 my %NameSpaceSymbols = (); 16514 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16515 $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1; 16516 } 16517 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16518 { 16519 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); 16520 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}}); 16521 foreach my $Symbol (@SortedInterfaces) 16522 { 16523 $Removed_Number += 1; 16524 my $SubReport = ""; 16525 my $Signature = get_Signature($Symbol, 1); 16526 if($NameSpace) { 16527 $Signature=~s/\b\Q$NameSpace\E::\b//g; 16528 } 16529 if($Symbol=~/\A(_Z|\?)/) 16530 { 16531 if($Signature) { 16532 $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span>\n<br/>\n<br/>\n".$ContentDivEnd."\n"); 16533 } 16534 else { 16535 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16536 } 16537 } 16538 else 16539 { 16540 if($Signature) { 16541 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 16542 } 16543 else { 16544 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n"; 16545 } 16546 } 16547 } 16548 } 16549 $REMOVED_INTERFACES .= "<br/>\n"; 16550 } 16551 } 16552 if($REMOVED_INTERFACES) 16553 { 16554 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>"; 16555 if($JoinReport) { 16556 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>"; 16557 } 16558 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n"; 16559 } 16560 } 16561 return $REMOVED_INTERFACES; 16562} 16563 16564sub getXmlParams($$) 16565{ 16566 my ($Content, $Problem) = @_; 16567 return "" if(not $Content or not $Problem); 16568 my %XMLparams = (); 16569 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16570 { 16571 my $Macro = "\@".lc($Attr); 16572 if($Content=~/\Q$Macro\E/) { 16573 $XMLparams{lc($Attr)} = $Problem->{$Attr}; 16574 } 16575 } 16576 my @PString = (); 16577 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) { 16578 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\""); 16579 } 16580 if(@PString) { 16581 return " ".join(" ", @PString); 16582 } 16583 else { 16584 return ""; 16585 } 16586} 16587 16588sub addMarkup($) 16589{ 16590 my $Content = $_[0]; 16591 # auto-markup 16592 $Content=~s/\n[ ]*//; # spaces 16593 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size) 16594 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list) 16595 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g; 16596 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ... 16597 if($Content=~/\ANOTE:/) 16598 { # notes 16599 $Content=~s!(NOTE):!<b>$1</b>:!g; 16600 } 16601 else { 16602 $Content=~s!(NOTE):!<br/><b>$1</b>:!g; 16603 } 16604 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters 16605 my @Keywords = ( 16606 "void", 16607 "const", 16608 "static", 16609 "restrict", 16610 "volatile", 16611 "register", 16612 "virtual" 16613 ); 16614 my $MKeys = join("|", @Keywords); 16615 foreach (@Keywords) { 16616 $MKeys .= "|non-".$_; 16617 } 16618 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers 16619 16620 # Markdown 16621 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig; 16622 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig; 16623 return $Content; 16624} 16625 16626sub applyMacroses($$$$) 16627{ 16628 my ($Level, $Kind, $Content, $Problem) = @_; 16629 return "" if(not $Content or not $Problem); 16630 $Problem->{"Word_Size"} = $WORD_SIZE{2}; 16631 $Content = addMarkup($Content); 16632 # macros 16633 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) 16634 { 16635 my $Macro = "\@".lc($Attr); 16636 my $Value = $Problem->{$Attr}; 16637 if(not defined $Value 16638 or $Value eq "") { 16639 next; 16640 } 16641 16642 if(index($Content, $Macro)==-1) { 16643 next; 16644 } 16645 16646 if($Kind!~/\A(Changed|Added|Removed)_Constant\Z/ 16647 and $Kind!~/_Type_/ 16648 and $Value=~/\s\(/ and $Value!~/['"]/) 16649 { # functions 16650 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals 16651 $Value=~s/\s[a-z]\w*(\)|,)/$1/ig; # remove parameter names 16652 $Value = black_name($Value); 16653 } 16654 elsif($Value=~/\s/) { 16655 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>"; 16656 } 16657 elsif($Value=~/\A\d+\Z/ 16658 and ($Attr eq "Old_Size" or $Attr eq "New_Size")) 16659 { # bits to bytes 16660 if($Value % $BYTE_SIZE) 16661 { # bits 16662 if($Value==1) { 16663 $Value = "<b>".$Value."</b> bit"; 16664 } 16665 else { 16666 $Value = "<b>".$Value."</b> bits"; 16667 } 16668 } 16669 else 16670 { # bytes 16671 $Value /= $BYTE_SIZE; 16672 if($Value==1) { 16673 $Value = "<b>".$Value."</b> byte"; 16674 } 16675 else { 16676 $Value = "<b>".$Value."</b> bytes"; 16677 } 16678 } 16679 } 16680 else 16681 { 16682 $Value = "<b>".htmlSpecChars($Value)."</b>"; 16683 } 16684 $Content=~s/\Q$Macro\E/$Value/g; 16685 } 16686 16687 if($Content=~/(\A|[^\@\w])\@\w/) 16688 { 16689 if(not $IncompleteRules{$Level}{$Kind}) 16690 { # only one warning 16691 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")"); 16692 $IncompleteRules{$Level}{$Kind} = 1; 16693 } 16694 } 16695 return $Content; 16696} 16697 16698sub get_Report_SymbolProblems($$) 16699{ 16700 my ($TargetSeverity, $Level) = @_; 16701 my $INTERFACE_PROBLEMS = ""; 16702 my (%ReportMap, %SymbolChanges) = (); 16703 16704 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 16705 { 16706 my ($SN, $SS, $SV) = separate_symbol($Symbol); 16707 if($SV and defined $CompatProblems{$Level}{$SN}) { 16708 next; 16709 } 16710 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) 16711 { 16712 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols" 16713 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol") 16714 { 16715 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 16716 my $DyLib = $Symbol_Library{1}{$Symbol}; 16717 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol}) 16718 { # Symbol with Version 16719 $DyLib = $Symbol_Library{1}{$VSym}; 16720 } 16721 if(not $DyLib) 16722 { # const global data 16723 $DyLib = ""; 16724 } 16725 if($Level eq "Source" and $ReportFormat eq "html") 16726 { # do not show library name in HTML report 16727 $DyLib = ""; 16728 } 16729 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}}; 16730 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16731 { 16732 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16733 if($Severity ne $TargetSeverity) { 16734 delete($SymbolChanges{$Symbol}{$Kind}{$Location}); 16735 } 16736 } 16737 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16738 { 16739 delete($SymbolChanges{$Symbol}{$Kind}); 16740 next; 16741 } 16742 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; 16743 } 16744 } 16745 if(not keys(%{$SymbolChanges{$Symbol}})) { 16746 delete($SymbolChanges{$Symbol}); 16747 } 16748 } 16749 16750 if($ReportFormat eq "xml") 16751 { # XML 16752 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16753 { 16754 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 16755 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16756 { 16757 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n"; 16758 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$ReportMap{$HeaderName}{$DyLib}}); 16759 foreach my $Symbol (@SortedInterfaces) 16760 { 16761 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n"; 16762 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}})) 16763 { 16764 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16765 { 16766 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 16767 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 16768 16769 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 16770 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16771 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 16772 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16773 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 16774 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 16775 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 16776 } 16777 $INTERFACE_PROBLEMS .= " </problem>\n"; 16778 } 16779 } 16780 $INTERFACE_PROBLEMS .= " </symbol>\n"; 16781 } 16782 $INTERFACE_PROBLEMS .= " </library>\n"; 16783 } 16784 $INTERFACE_PROBLEMS .= " </header>\n"; 16785 } 16786 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n"; 16787 } 16788 else 16789 { # HTML 16790 my $ProblemsNum = 0; 16791 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16792 { 16793 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) 16794 { 16795 my (%NameSpaceSymbols, %NewSignature) = (); 16796 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { 16797 $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 16798 } 16799 foreach my $NameSpace (sort keys(%NameSpaceSymbols)) 16800 { 16801 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace); 16802 my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} sort keys(%{$NameSpaceSymbols{$NameSpace}}); 16803 foreach my $Symbol (@SortedInterfaces) 16804 { 16805 my $Signature = get_Signature($Symbol, 1); 16806 my $SYMBOL_REPORT = ""; 16807 my $ProblemNum = 1; 16808 foreach my $Kind (sort keys(%{$SymbolChanges{$Symbol}})) 16809 { 16810 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) 16811 { 16812 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; 16813 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); 16814 if($Problem{"New_Signature"}) { 16815 $NewSignature{$Symbol} = $Problem{"New_Signature"}; 16816 } 16817 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 16818 { 16819 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 16820 $SYMBOL_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td align='left' valign='top'>".$Change."</td>\n<td align='left' valign='top'>".$Effect."</td>\n</tr>\n"; 16821 $ProblemNum += 1; 16822 $ProblemsNum += 1; 16823 } 16824 } 16825 } 16826 $ProblemNum -= 1; 16827 if($SYMBOL_REPORT) 16828 { 16829 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> "; 16830 if($Signature) { 16831 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature); 16832 } 16833 else { 16834 $INTERFACE_PROBLEMS .= $Symbol; 16835 } 16836 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n"; 16837 $INTERFACE_PROBLEMS .= $ContentDivStart."\n"; 16838 if($NewSignature{$Symbol}) 16839 { # argument list changed to 16840 $INTERFACE_PROBLEMS .= "\n<span class='new_sign_lbl'>changed to:</span>\n<br/>\n<span class='new_sign'>".highLight_Signature_Italic_Color($NewSignature{$Symbol})."</span><br/>\n"; 16841 } 16842 if($Symbol=~/\A(_Z|\?)/) { 16843 $INTERFACE_PROBLEMS .= "<span class='mangled'>    [symbol: <b>$Symbol</b>]</span><br/>\n"; 16844 } 16845 $INTERFACE_PROBLEMS .= "<table class='ptable'>\n<tr>\n<th width='2%'></th>\n<th width='47%'>Change</th>\n<th>Effect</th>\n</tr>\n$SYMBOL_REPORT</table>\n<br/>\n"; 16846 $INTERFACE_PROBLEMS .= $ContentDivEnd; 16847 if($NameSpace) { 16848 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g; 16849 } 16850 } 16851 } 16852 $INTERFACE_PROBLEMS .= "<br/>\n"; 16853 } 16854 } 16855 } 16856 16857 if($INTERFACE_PROBLEMS) 16858 { 16859 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS); 16860 my $Title = "Problems with Symbols, $TargetSeverity Severity"; 16861 if($TargetSeverity eq "Safe") 16862 { # Safe Changes 16863 $Title = "Other Changes in Symbols"; 16864 } 16865 $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"; 16866 } 16867 } 16868 return $INTERFACE_PROBLEMS; 16869} 16870 16871sub get_Report_TypeProblems($$) 16872{ 16873 my ($TargetSeverity, $Level) = @_; 16874 my $TYPE_PROBLEMS = ""; 16875 my (%ReportMap, %TypeChanges) = (); 16876 16877 foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) 16878 { 16879 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) 16880 { 16881 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 16882 { 16883 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) 16884 { 16885 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; 16886 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; 16887 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16888 16889 if($Severity eq "Safe" 16890 and $TargetSeverity ne "Safe") { 16891 next; 16892 } 16893 16894 if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}) 16895 { 16896 if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) 16897 { # select a problem with the highest priority 16898 next; 16899 } 16900 } 16901 16902 $TypeChanges{$TypeName}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; 16903 } 16904 } 16905 } 16906 } 16907 16908 my %Kinds_Locations = (); 16909 foreach my $TypeName (keys(%TypeChanges)) 16910 { 16911 my %Kind_Target = (); 16912 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}})) 16913 { 16914 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16915 { 16916 my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; 16917 if($Severity ne $TargetSeverity) 16918 { # other priority 16919 delete($TypeChanges{$TypeName}{$Kind}{$Location}); 16920 next; 16921 } 16922 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1; 16923 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"}; 16924 if($Kind_Target{$Kind}{$Target}) 16925 { # duplicate target 16926 delete($TypeChanges{$TypeName}{$Kind}{$Location}); 16927 next; 16928 } 16929 $Kind_Target{$Kind}{$Target} = 1; 16930 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"}; 16931 $ReportMap{$HeaderName}{$TypeName} = 1; 16932 } 16933 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) { 16934 delete($TypeChanges{$TypeName}{$Kind}); 16935 } 16936 } 16937 if(not keys(%{$TypeChanges{$TypeName}})) { 16938 delete($TypeChanges{$TypeName}); 16939 } 16940 } 16941 16942 my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}}); 16943 if($ReportFormat eq "xml") 16944 { # XML 16945 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16946 { 16947 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n"; 16948 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) 16949 { 16950 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n"; 16951 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) 16952 { 16953 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16954 { 16955 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; 16956 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n"; 16957 my $Change = $CompatRules{$Level}{$Kind}{"Change"}; 16958 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n"; 16959 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; 16960 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n"; 16961 if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { 16962 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n"; 16963 } 16964 $TYPE_PROBLEMS .= " </problem>\n"; 16965 } 16966 } 16967 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); 16968 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { 16969 $TYPE_PROBLEMS .= showVTables($TypeName); 16970 } 16971 $TYPE_PROBLEMS .= " </type>\n"; 16972 } 16973 $TYPE_PROBLEMS .= " </header>\n"; 16974 } 16975 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n"; 16976 } 16977 else 16978 { # HTML 16979 my $ProblemsNum = 0; 16980 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) 16981 { 16982 my (%NameSpace_Type) = (); 16983 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) { 16984 $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1; 16985 } 16986 foreach my $NameSpace (sort keys(%NameSpace_Type)) 16987 { 16988 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace); 16989 my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}}); 16990 foreach my $TypeName (@SortedTypes) 16991 { 16992 my $ProblemNum = 1; 16993 my $TYPE_REPORT = ""; 16994 16995 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) 16996 { 16997 foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) 16998 { 16999 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; 17000 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) 17001 { 17002 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); 17003 $TYPE_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td align='left' valign='top'>".$Change."</td>\n<td align='left' valign='top'>$Effect</td>\n</tr>\n"; 17004 $ProblemNum += 1; 17005 $ProblemsNum += 1; 17006 } 17007 } 17008 } 17009 $ProblemNum -= 1; 17010 if($TYPE_REPORT) 17011 { 17012 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); 17013 my $ShowVTables = ""; 17014 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { 17015 $ShowVTables = showVTables($TypeName); 17016 } 17017 17018 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ".show_Type($TypeName, 1, 1)." ($ProblemNum)".$ContentSpanEnd; 17019 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n"; 17020 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n"; 17021 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n"; 17022 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n"; 17023 if($NameSpace) { 17024 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g; 17025 } 17026 } 17027 } 17028 $TYPE_PROBLEMS .= "<br/>\n"; 17029 } 17030 } 17031 17032 if($TYPE_PROBLEMS) 17033 { 17034 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS); 17035 my $Title = "Problems with Data Types, $TargetSeverity Severity"; 17036 if($TargetSeverity eq "Safe") 17037 { # Safe Changes 17038 $Title = "Other Changes in Data Types"; 17039 } 17040 $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n"; 17041 } 17042 } 17043 return $TYPE_PROBLEMS; 17044} 17045 17046sub show_Type($$$) 17047{ 17048 my ($Name, $Html, $LibVersion) = @_; 17049 my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"}; 17050 $TType = lc($TType); 17051 if($TType=~/struct|union|enum/) { 17052 $Name=~s/\A\Q$TType\E //g; 17053 } 17054 if($Html) { 17055 $Name = "<span class='ttype'>".$TType."</span> ".htmlSpecChars($Name); 17056 } 17057 else { 17058 $Name = $TType." ".$Name; 17059 } 17060 return $Name; 17061} 17062 17063sub get_Anchor($$$) 17064{ 17065 my ($Kind, $Level, $Severity) = @_; 17066 if($JoinReport) 17067 { 17068 if($Severity eq "Safe") { 17069 return "Other_".$Level."_Changes_In_".$Kind."s"; 17070 } 17071 else { 17072 return $Kind."_".$Level."_Problems_".$Severity; 17073 } 17074 } 17075 else 17076 { 17077 if($Severity eq "Safe") { 17078 return "Other_Changes_In_".$Kind."s"; 17079 } 17080 else { 17081 return $Kind."_Problems_".$Severity; 17082 } 17083 } 17084} 17085 17086sub showVTables($) 17087{ 17088 my $TypeName = $_[0]; 17089 my $TypeId1 = $TName_Tid{1}{$TypeName}; 17090 my %Type1 = get_Type($TypeId1, 1); 17091 if(defined $Type1{"VTable"} 17092 and keys(%{$Type1{"VTable"}})) 17093 { 17094 my $TypeId2 = $TName_Tid{2}{$TypeName}; 17095 my %Type2 = get_Type($TypeId2, 2); 17096 if(defined $Type2{"VTable"} 17097 and keys(%{$Type2{"VTable"}})) 17098 { 17099 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}})); 17100 my %Entries = (); 17101 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes))) 17102 { 17103 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index}); 17104 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index}); 17105 } 17106 my $VTABLES = ""; 17107 if($ReportFormat eq "xml") 17108 { # XML 17109 $VTABLES .= " <vtable>\n"; 17110 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 17111 { 17112 $VTABLES .= " <entry offset=\"".$Index."\">\n"; 17113 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n"; 17114 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n"; 17115 $VTABLES .= " </entry>\n"; 17116 } 17117 $VTABLES .= " </vtable>\n\n"; 17118 } 17119 else 17120 { # HTML 17121 $VTABLES .= "<table class='vtable'>"; 17122 $VTABLES .= "<tr><th>Offset</th>"; 17123 $VTABLES .= "<th>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>"; 17124 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>"; 17125 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) 17126 { 17127 my ($Color1, $Color2) = ("", ""); 17128 17129 my $E1 = $Entries{$Index}{"E1"}; 17130 my $E2 = $Entries{$Index}{"E2"}; 17131 17132 if($E1 ne $E2 17133 and $E1!~/ 0x/ 17134 and $E2!~/ 0x/) 17135 { 17136 if($Entries{$Index}{"E1"}) 17137 { 17138 $Color1 = " class='failed'"; 17139 $Color2 = " class='failed'"; 17140 } 17141 else { 17142 $Color2 = " class='warning'"; 17143 } 17144 } 17145 $VTABLES .= "<tr><th>".$Index."</th>\n"; 17146 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n"; 17147 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n"; 17148 } 17149 $VTABLES .= "</table><br/>\n"; 17150 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd; 17151 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES; 17152 } 17153 return $VTABLES; 17154 } 17155 } 17156 return ""; 17157} 17158 17159sub simpleVEntry($) 17160{ 17161 my $VEntry = $_[0]; 17162 if(not defined $VEntry 17163 or $VEntry eq "") { 17164 return ""; 17165 } 17166 17167 $VEntry=~s/ \[.+?\]\Z//; # support for ABI Dumper 17168 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks 17169 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo 17170 if($VEntry=~/\A_ZThn.+\Z/) { 17171 $VEntry = "non-virtual thunk"; 17172 } 17173 $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i; 17174 # support for old GCC versions 17175 $VEntry=~s/\A0u\Z/(int (*)(...))0/; 17176 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/; 17177 $VEntry=~s/\A&_Z\Z/& _Z/; 17178 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors 17179 return $VEntry; 17180} 17181 17182sub adjustParamPos($$$) 17183{ 17184 my ($Pos, $Symbol, $LibVersion) = @_; 17185 if(defined $CompleteSignature{$LibVersion}{$Symbol}) 17186 { 17187 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"} 17188 and $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) 17189 { 17190 return $Pos-1; 17191 } 17192 17193 return $Pos; 17194 } 17195 17196 return undef; 17197} 17198 17199sub getParamPos($$$) 17200{ 17201 my ($Name, $Symbol, $LibVersion) = @_; 17202 17203 if(defined $CompleteSignature{$LibVersion}{$Symbol} 17204 and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}) 17205 { 17206 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17207 foreach (keys(%{$Info->{"Param"}})) 17208 { 17209 if($Info->{"Param"}{$_}{"name"} eq $Name) 17210 { 17211 return $_; 17212 } 17213 } 17214 } 17215 17216 return undef; 17217} 17218 17219sub getParamName($) 17220{ 17221 my $Loc = $_[0]; 17222 $Loc=~s/\->.*//g; 17223 return $Loc; 17224} 17225 17226sub getAffectedSymbols($$$$) 17227{ 17228 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_; 17229 17230 my $LIMIT = 10; 17231 if(defined $AffectLimit) { 17232 $LIMIT = $AffectLimit; 17233 } 17234 17235 my @Kinds = sort keys(%{$Kinds_Locations}); 17236 my %KLocs = (); 17237 foreach my $Kind (@Kinds) 17238 { 17239 my @Locs = sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} keys(%{$Kinds_Locations->{$Kind}}); 17240 $KLocs{$Kind} = \@Locs; 17241 } 17242 17243 my %SymLocKind = (); 17244 foreach my $Symbol (@{$Syms}) 17245 { 17246 if(index($Symbol, "_Z")==0 17247 and $Symbol=~/(C2|D2|D0)[EI]/) 17248 { # duplicated problems for C2 constructors, D2 and D0 destructors 17249 next; 17250 } 17251 17252 foreach my $Kind (@Kinds) 17253 { 17254 if(not defined $CompatProblems{$Level}{$Symbol} 17255 or not defined $CompatProblems{$Level}{$Symbol}{$Kind}) { 17256 next; 17257 } 17258 17259 foreach my $Loc (@{$KLocs{$Kind}}) 17260 { 17261 if(not defined $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}) { 17262 next; 17263 } 17264 17265 if(index($Symbol, "\@")!=-1 17266 or index($Symbol, "\$")!=-1) 17267 { 17268 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17269 17270 if($Level eq "Source") 17271 { # remove symbol version 17272 $Symbol = $SN; 17273 } 17274 17275 if($SV and defined $CompatProblems{$Level}{$SN} 17276 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Loc}) 17277 { # duplicated problems for versioned symbols 17278 next; 17279 } 17280 } 17281 17282 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Loc}{"Type_Name"}; 17283 if($Type_Name ne $Target_TypeName) { 17284 next; 17285 } 17286 17287 $SymLocKind{$Symbol}{$Loc}{$Kind} = 1; 17288 last; 17289 } 17290 } 17291 17292 # if(keys(%SymLocKind)>=$LIMIT) 17293 # { 17294 # last; 17295 # } 17296 } 17297 17298 %KLocs = (); # clear 17299 17300 my %SymSel = (); 17301 my $Num = 0; 17302 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymLocKind)) 17303 { 17304 LOOP: foreach my $Loc (sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$SymLocKind{$Symbol}})) 17305 { 17306 foreach my $Kind (sort keys(%{$SymLocKind{$Symbol}{$Loc}})) 17307 { 17308 $SymSel{$Symbol}{"Loc"} = $Loc; 17309 $SymSel{$Symbol}{"Kind"} = $Kind; 17310 last LOOP; 17311 } 17312 } 17313 17314 $Num += 1; 17315 17316 if($Num>=$LIMIT) { 17317 last; 17318 } 17319 } 17320 17321 my $Affected = ""; 17322 17323 if($ReportFormat eq "xml") 17324 { # XML 17325 $Affected .= " <affected>\n"; 17326 17327 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17328 { 17329 my $Loc = $SymSel{$Symbol}{"Loc"}; 17330 my $PName = getParamName($Loc); 17331 my $Desc = getAffectDesc($Level, $Symbol, $SymSel{$Symbol}{"Kind"}, $Loc); 17332 17333 my $Target = ""; 17334 if($PName) 17335 { 17336 $Target .= " param=\"$PName\""; 17337 $Desc=~s/parameter $PName /parameter \@param /; 17338 } 17339 elsif($Loc=~/\Aretval(\-|\Z)/i) { 17340 $Target .= " affected=\"retval\""; 17341 } 17342 elsif($Loc=~/\Athis(\-|\Z)/i) { 17343 $Target .= " affected=\"this\""; 17344 } 17345 17346 if($Desc=~s/\AField ([^\s]+) /Field \@field /) { 17347 $Target .= " field=\"$1\""; 17348 } 17349 17350 $Affected .= " <symbol name=\"$Symbol\"$Target>\n"; 17351 $Affected .= " <comment>".xmlSpecChars($Desc)."</comment>\n"; 17352 $Affected .= " </symbol>\n"; 17353 } 17354 $Affected .= " </affected>\n"; 17355 } 17356 else 17357 { # HTML 17358 foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) 17359 { 17360 my $Desc = getAffectDesc($Level, $Symbol, $SymSel{$Symbol}{"Kind"}, $SymSel{$Symbol}{"Loc"}); 17361 my $S = get_Signature($Symbol, 1); 17362 my $PName = getParamName($SymSel{$Symbol}{"Loc"}); 17363 my $Pos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1); 17364 17365 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($S, $Pos, 1, 0, 0)."</span><br/>\n"; 17366 $Affected .= "<div class='affect'>".htmlSpecChars($Desc)."</div>\n"; 17367 } 17368 17369 if(keys(%SymLocKind)>$LIMIT) { 17370 $Affected .= " <b>...</b>\n<br/>\n"; # and others ... 17371 } 17372 17373 $Affected = "<div class='affected'>".$Affected."</div>\n"; 17374 if($Affected) 17375 { 17376 $Affected = $ContentDivStart.$Affected.$ContentDivEnd; 17377 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".keys(%SymLocKind).")".$ContentSpanEnd.$Affected; 17378 } 17379 } 17380 17381 return $Affected; 17382} 17383 17384sub cmpLocations($$) 17385{ 17386 my ($L1, $L2) = @_; 17387 if($L2=~/\A(retval|this)\b/ 17388 and $L1!~/\A(retval|this)\b/) 17389 { 17390 if($L1!~/\-\>/) { 17391 return 1; 17392 } 17393 elsif($L2=~/\-\>/) { 17394 return 1; 17395 } 17396 } 17397 return 0; 17398} 17399 17400sub getAffectDesc($$$$) 17401{ 17402 my ($Level, $Symbol, $Kind, $Location) = @_; 17403 17404 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}}; 17405 17406 my $Location_I = $Location; 17407 $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field 17408 17409 my @Sentence = (); 17410 17411 if($Kind eq "Overridden_Virtual_Method" 17412 or $Kind eq "Overridden_Virtual_Method_B") { 17413 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method."); 17414 } 17415 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") 17416 { 17417 my %SymInfo = %{$CompleteSignature{1}{$Symbol}}; 17418 17419 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/) 17420 { 17421 my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method"; 17422 my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"}; 17423 17424 if($ClassName eq $Problem{"Type_Name"}) { 17425 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class."); 17426 } 17427 else { 17428 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'."); 17429 } 17430 } 17431 else 17432 { 17433 my $TypeID = undef; 17434 17435 if($Location=~/retval/) 17436 { # return value 17437 if(index($Location, "->")!=-1) { 17438 push(@Sentence, "Field \'".$Location."\' in return value"); 17439 } 17440 else { 17441 push(@Sentence, "Return value"); 17442 } 17443 17444 $TypeID = $SymInfo{"Return"}; 17445 } 17446 elsif($Location=~/this/) 17447 { # "this" pointer 17448 if(index($Location, "->")!=-1) { 17449 push(@Sentence, "Field \'".$Location."\' in the object of this method"); 17450 } 17451 else { 17452 push(@Sentence, "\'this\' pointer"); 17453 } 17454 17455 $TypeID = $SymInfo{"Class"}; 17456 } 17457 else 17458 { # parameters 17459 17460 my $PName = getParamName($Location); 17461 my $PPos = getParamPos($PName, $Symbol, 1); 17462 17463 if(index($Location, "->")!=-1) { 17464 push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17465 } 17466 else { 17467 push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); 17468 } 17469 if($PName) { 17470 push(@Sentence, "\'".$PName."\'"); 17471 } 17472 17473 $TypeID = $SymInfo{"Param"}{$PPos}{"type"}; 17474 } 17475 17476 if($Location!~/this/) 17477 { 17478 if(my %PureType = get_PureType($TypeID, $TypeInfo{1})) 17479 { 17480 if($PureType{"Type"} eq "Pointer") { 17481 push(@Sentence, "(pointer)"); 17482 } 17483 elsif($PureType{"Type"} eq "Ref") { 17484 push(@Sentence, "(reference)"); 17485 } 17486 } 17487 } 17488 17489 if($Location eq "this") { 17490 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17491 } 17492 else 17493 { 17494 my $Location_T = $Location; 17495 $Location_T=~s/\A\w+(\->|\Z)//; # location in type 17496 17497 my $TypeID_Problem = $TypeID; 17498 if($Location_T) { 17499 $TypeID_Problem = getFieldType($Location_T, $TypeID, 1); 17500 } 17501 17502 if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) { 17503 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); 17504 } 17505 else { 17506 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); 17507 } 17508 } 17509 } 17510 } 17511 if($ExtendedSymbols{$Symbol}) { 17512 push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling."); 17513 } 17514 17515 my $Sent = join(" ", @Sentence); 17516 17517 $Sent=~s/->/./g; 17518 17519 if($ReportFormat eq "xml") 17520 { 17521 $Sent=~s/'//g; 17522 } 17523 17524 return $Sent; 17525} 17526 17527sub getFieldType($$$) 17528{ 17529 my ($Location, $TypeId, $LibVersion) = @_; 17530 17531 my @Fields = split(/\->/, $Location); 17532 17533 foreach my $Name (@Fields) 17534 { 17535 my %Info = get_BaseType($TypeId, $LibVersion); 17536 17537 foreach my $Pos (keys(%{$Info{"Memb"}})) 17538 { 17539 if($Info{"Memb"}{$Pos}{"name"} eq $Name) 17540 { 17541 $TypeId = $Info{"Memb"}{$Pos}{"type"}; 17542 last; 17543 } 17544 } 17545 } 17546 17547 return $TypeId; 17548} 17549 17550sub get_XmlSign($$) 17551{ 17552 my ($Symbol, $LibVersion) = @_; 17553 my $Info = $CompleteSignature{$LibVersion}{$Symbol}; 17554 my $Report = ""; 17555 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}})) 17556 { 17557 my $Name = $Info->{"Param"}{$Pos}{"name"}; 17558 my $Type = $Info->{"Param"}{$Pos}{"type"}; 17559 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"}; 17560 foreach my $Typedef (keys(%ChangedTypedef)) 17561 { 17562 if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { 17563 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g; 17564 } 17565 } 17566 $Report .= " <param pos=\"$Pos\">\n"; 17567 $Report .= " <name>".$Name."</name>\n"; 17568 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n"; 17569 $Report .= " </param>\n"; 17570 } 17571 if(my $Return = $Info->{"Return"}) 17572 { 17573 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"}; 17574 $Report .= " <retval>\n"; 17575 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n"; 17576 $Report .= " </retval>\n"; 17577 } 17578 return $Report; 17579} 17580 17581sub get_Report_SymbolsInfo($) 17582{ 17583 my $Level = $_[0]; 17584 my $Report = "<symbols_info>\n"; 17585 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) 17586 { 17587 my ($SN, $SS, $SV) = separate_symbol($Symbol); 17588 if($SV and defined $CompatProblems{$Level}{$SN}) { 17589 next; 17590 } 17591 $Report .= " <symbol name=\"$Symbol\">\n"; 17592 my ($S1, $P1, $S2, $P2) = (); 17593 if(not $AddedInt{$Level}{$Symbol}) 17594 { 17595 if(defined $CompleteSignature{1}{$Symbol} 17596 and defined $CompleteSignature{1}{$Symbol}{"Header"}) 17597 { 17598 $P1 = get_XmlSign($Symbol, 1); 17599 $S1 = get_Signature($Symbol, 1); 17600 } 17601 elsif($Symbol=~/\A(_Z|\?)/) { 17602 $S1 = $tr_name{$Symbol}; 17603 } 17604 } 17605 if(not $RemovedInt{$Level}{$Symbol}) 17606 { 17607 if(defined $CompleteSignature{2}{$Symbol} 17608 and defined $CompleteSignature{2}{$Symbol}{"Header"}) 17609 { 17610 $P2 = get_XmlSign($Symbol, 2); 17611 $S2 = get_Signature($Symbol, 2); 17612 } 17613 elsif($Symbol=~/\A(_Z|\?)/) { 17614 $S2 = $tr_name{$Symbol}; 17615 } 17616 } 17617 if($S1) 17618 { 17619 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n"; 17620 $Report .= $P1; 17621 $Report .= " </old>\n"; 17622 } 17623 if($S2 and $S2 ne $S1) 17624 { 17625 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n"; 17626 $Report .= $P2; 17627 $Report .= " </new>\n"; 17628 } 17629 $Report .= " </symbol>\n"; 17630 } 17631 $Report .= "</symbols_info>\n"; 17632 return $Report; 17633} 17634 17635sub writeReport($$) 17636{ 17637 my ($Level, $Report) = @_; 17638 if($ReportFormat eq "xml") { 17639 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report; 17640 } 17641 if($StdOut) 17642 { # --stdout option 17643 print STDOUT $Report; 17644 } 17645 else 17646 { 17647 my $RPath = getReportPath($Level); 17648 mkpath(get_dirname($RPath)); 17649 17650 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n"); 17651 print REPORT $Report; 17652 close(REPORT); 17653 } 17654} 17655 17656sub getReport($) 17657{ 17658 my $Level = $_[0]; 17659 if($ReportFormat eq "xml") 17660 { # XML 17661 if($Level eq "Join") 17662 { 17663 my $Report = "<reports>\n"; 17664 $Report .= getReport("Binary"); 17665 $Report .= getReport("Source"); 17666 $Report .= "</reports>\n"; 17667 return $Report; 17668 } 17669 else 17670 { 17671 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n"; 17672 my ($Summary, $MetaData) = get_Summary($Level); 17673 $Report .= $Summary."\n"; 17674 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17675 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17676 17677 # additional symbols info (if needed) 17678 # $Report .= get_Report_SymbolsInfo($Level); 17679 17680 $Report .= "</report>\n"; 17681 return $Report; 17682 } 17683 } 17684 else 17685 { # HTML 17686 my $CssStyles = readModule("Styles", "Report.css"); 17687 my $JScripts = readModule("Scripts", "Sections.js"); 17688 if($Level eq "Join") 17689 { 17690 $CssStyles .= "\n".readModule("Styles", "Tabs.css"); 17691 $JScripts .= "\n".readModule("Scripts", "Tabs.js"); 17692 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report"; 17693 my $Keywords = $TargetTitle.", compatibility, API, ABI, report"; 17694 my $Description = "API/ABI compatibility report for the $TargetTitle $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17695 my ($BSummary, $BMetaData) = get_Summary("Binary"); 17696 my ($SSummary, $SMetaData) = get_Summary("Source"); 17697 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>"; 17698 $Report .= get_Report_Title("Join")." 17699 <br/> 17700 <div class='tabset'> 17701 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a> 17702 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a> 17703 </div>"; 17704 $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>"; 17705 $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>"; 17706 $Report .= getReportFooter(); 17707 $Report .= "\n</body></html>\n"; 17708 return $Report; 17709 } 17710 else 17711 { 17712 my ($Summary, $MetaData) = get_Summary($Level); 17713 my $Title = $TargetTitle.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report"; 17714 my $Keywords = $TargetTitle.", ".lc($Level)." compatibility, API, report"; 17715 my $Description = "$Level compatibility report for the ".$TargetTitle." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; 17716 if($Level eq "Binary") 17717 { 17718 if(getArch(1) eq getArch(2) 17719 and getArch(1) ne "unknown") { 17720 $Description .= " on ".showArch(getArch(1)); 17721 } 17722 } 17723 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n"; 17724 $Report .= get_Report_Title($Level)."\n".$Summary."\n"; 17725 $Report .= get_Report_Added($Level).get_Report_Removed($Level); 17726 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); 17727 $Report .= get_SourceInfo(); 17728 $Report .= "</div>\n<br/><br/><br/>\n"; 17729 $Report .= getReportFooter(); 17730 $Report .= "\n</body></html>\n"; 17731 return $Report; 17732 } 17733 } 17734} 17735 17736sub getLegend() 17737{ 17738 return "<br/> 17739<table class='summary'> 17740<tr> 17741 <td class='new'>added</td> 17742 <td class='passed'>compatible</td> 17743</tr> 17744<tr> 17745 <td class='warning'>warning</td> 17746 <td class='failed'>incompatible</td> 17747</tr></table>\n"; 17748} 17749 17750sub createReport() 17751{ 17752 if($JoinReport) 17753 { # --stdout 17754 writeReport("Join", getReport("Join")); 17755 } 17756 elsif($DoubleReport) 17757 { # default 17758 writeReport("Binary", getReport("Binary")); 17759 writeReport("Source", getReport("Source")); 17760 } 17761 elsif($BinaryOnly) 17762 { # --binary 17763 writeReport("Binary", getReport("Binary")); 17764 } 17765 elsif($SourceOnly) 17766 { # --source 17767 writeReport("Source", getReport("Source")); 17768 } 17769} 17770 17771sub getReportFooter() 17772{ 17773 my $Footer = ""; 17774 17775 $Footer .= "<hr/>\n"; 17776 $Footer .= "<div class='footer' align='right'>"; 17777 $Footer .= "<i>Generated by <a href='".$HomePage."'>ABI Compliance Checker</a> $TOOL_VERSION  </i>\n"; 17778 $Footer .= "</div>\n"; 17779 $Footer .= "<br/>\n"; 17780 17781 return $Footer; 17782} 17783 17784sub get_Report_Problems($$) 17785{ 17786 my ($Severity, $Level) = @_; 17787 17788 my $Report = get_Report_TypeProblems($Severity, $Level); 17789 if(my $SProblems = get_Report_SymbolProblems($Severity, $Level)) { 17790 $Report .= $SProblems; 17791 } 17792 17793 if($Severity eq "Low" or $Severity eq "Safe") { 17794 $Report .= get_Report_ChangedConstants($Severity, $Level); 17795 } 17796 17797 if($ReportFormat eq "html") 17798 { 17799 if($Report) 17800 { # add anchor 17801 if($JoinReport) 17802 { 17803 if($Severity eq "Safe") { 17804 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report; 17805 } 17806 else { 17807 $Report = "<a name=\'".$Severity."_Risk_".$Level."_Problems\'></a>".$Report; 17808 } 17809 } 17810 else 17811 { 17812 if($Severity eq "Safe") { 17813 $Report = "<a name=\'Other_Changes\'></a>".$Report; 17814 } 17815 else { 17816 $Report = "<a name=\'".$Severity."_Risk_Problems\'></a>".$Report; 17817 } 17818 } 17819 } 17820 } 17821 return $Report; 17822} 17823 17824sub composeHTML_Head($$$$$) 17825{ 17826 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_; 17827 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> 17828 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"> 17829 <head> 17830 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> 17831 <meta name=\"keywords\" content=\"$Keywords\" /> 17832 <meta name=\"description\" content=\"$Description\" /> 17833 <title> 17834 $Title 17835 </title> 17836 <style type=\"text/css\"> 17837 $Styles 17838 </style> 17839 <script type=\"text/javascript\" language=\"JavaScript\"> 17840 <!-- 17841 $Scripts 17842 --> 17843 </script> 17844 </head>"; 17845} 17846 17847sub insertIDs($) 17848{ 17849 my $Text = $_[0]; 17850 while($Text=~/CONTENT_ID/) 17851 { 17852 if(int($Content_Counter)%2) { 17853 $ContentID -= 1; 17854 } 17855 $Text=~s/CONTENT_ID/c_$ContentID/; 17856 $ContentID += 1; 17857 $Content_Counter += 1; 17858 } 17859 return $Text; 17860} 17861 17862sub checkPreprocessedUnit($) 17863{ 17864 my $Path = $_[0]; 17865 my ($CurHeader, $CurHeaderName) = ("", ""); 17866 my $CurClass = ""; # extra info 17867 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n"); 17868 17869 while(my $Line = <PREPROC>) 17870 { # detecting public and private constants 17871 if(substr($Line, 0, 1) eq "#") 17872 { 17873 chomp($Line); 17874 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/) 17875 { 17876 $CurHeader = path_format($1, $OSgroup); 17877 $CurHeaderName = get_filename($CurHeader); 17878 $CurClass = ""; 17879 17880 if(index($CurHeader, $TMP_DIR)==0) { 17881 next; 17882 } 17883 17884 if(substr($CurHeaderName, 0, 1) eq "<") 17885 { # <built-in>, <command-line>, etc. 17886 $CurHeaderName = ""; 17887 $CurHeader = ""; 17888 } 17889 17890 if($ExtraInfo) 17891 { 17892 if($CurHeaderName) { 17893 $PreprocessedHeaders{$Version}{$CurHeader} = 1; 17894 } 17895 } 17896 } 17897 if(not $ExtraDump) 17898 { 17899 if($CurHeaderName) 17900 { 17901 if(not $Include_Neighbors{$Version}{$CurHeaderName} 17902 and not $Registered_Headers{$Version}{$CurHeader}) 17903 { # not a target 17904 next; 17905 } 17906 if(not is_target_header($CurHeaderName, 1) 17907 and not is_target_header($CurHeaderName, 2)) 17908 { # user-defined header 17909 next; 17910 } 17911 } 17912 } 17913 17914 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/) 17915 { 17916 my ($Name, $Value) = ($1, $2); 17917 if(not $Constants{$Version}{$Name}{"Access"}) 17918 { 17919 $Constants{$Version}{$Name}{"Access"} = "public"; 17920 $Constants{$Version}{$Name}{"Value"} = $Value; 17921 if($CurHeaderName) { 17922 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName; 17923 } 17924 } 17925 } 17926 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) { 17927 $Constants{$Version}{$1}{"Access"} = "private"; 17928 } 17929 } 17930 else 17931 { 17932 if(defined $ExtraDump) 17933 { 17934 if($Line=~/(\w+)\s*\(/) 17935 { # functions 17936 $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 17937 } 17938 #elsif($Line=~/(\w+)\s*;/) 17939 #{ # data 17940 # $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; 17941 #} 17942 elsif($Line=~/(\A|\s)class\s+(\w+)/) { 17943 $CurClass = $2; 17944 } 17945 } 17946 } 17947 } 17948 close(PREPROC); 17949 foreach my $Constant (keys(%{$Constants{$Version}})) 17950 { 17951 if($Constants{$Version}{$Constant}{"Access"} eq "private") 17952 { 17953 delete($Constants{$Version}{$Constant}); 17954 next; 17955 } 17956 if(not $ExtraDump and ($Constant=~/_h\Z/i 17957 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) 17958 { # skip 17959 delete($Constants{$Version}{$Constant}); 17960 } 17961 else { 17962 delete($Constants{$Version}{$Constant}{"Access"}); 17963 } 17964 } 17965 if($Debug) 17966 { 17967 mkpath($DEBUG_PATH{$Version}); 17968 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt"); 17969 } 17970} 17971 17972sub uncoverConstant($$) 17973{ 17974 my ($LibVersion, $Constant) = @_; 17975 return "" if(not $LibVersion or not $Constant); 17976 return $Constant if(isCyclical(\@RecurConstant, $Constant)); 17977 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) { 17978 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant}; 17979 } 17980 17981 if(defined $Constants{$LibVersion}{$Constant}) 17982 { 17983 my $Value = $Constants{$LibVersion}{$Constant}{"Value"}; 17984 if(defined $Constants{$LibVersion}{$Value}) 17985 { 17986 push(@RecurConstant, $Constant); 17987 my $Uncovered = uncoverConstant($LibVersion, $Value); 17988 if($Uncovered ne "") { 17989 $Value = $Uncovered; 17990 } 17991 pop(@RecurConstant); 17992 } 17993 17994 # FIXME: uncover $Value using all the enum constants 17995 # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define) 17996 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value); 17997 } 17998 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = ""); 17999} 18000 18001sub simpleConstant($$) 18002{ 18003 my ($LibVersion, $Value) = @_; 18004 if($Value=~/\W/) 18005 { 18006 my $Value_Copy = $Value; 18007 while($Value_Copy=~s/([a-z_]\w+)/\@/i) 18008 { 18009 my $Word = $1; 18010 if($Value!~/$Word\s*\(/) 18011 { 18012 my $Val = uncoverConstant($LibVersion, $Word); 18013 if($Val ne "") 18014 { 18015 $Value=~s/\b$Word\b/$Val/g; 18016 } 18017 } 18018 } 18019 } 18020 return $Value; 18021} 18022 18023sub computeValue($) 18024{ 18025 my $Value = $_[0]; 18026 18027 if($Value=~/\A\((-?[\d]+)\)\Z/) { 18028 return $1; 18029 } 18030 18031 if($Value=~/\A[\d\-\+()]+\Z/) { 18032 return eval($Value); 18033 } 18034 18035 return $Value; 18036} 18037 18038my %IgnoreConstant = map {$_=>1} ( 18039 "VERSION", 18040 "VERSIONCODE", 18041 "VERNUM", 18042 "VERS_INFO", 18043 "PATCHLEVEL", 18044 "INSTALLPREFIX", 18045 "VBUILD", 18046 "VPATCH", 18047 "VMINOR", 18048 "BUILD_STRING", 18049 "BUILD_TIME", 18050 "PACKAGE_STRING", 18051 "PRODUCTION", 18052 "CONFIGURE_COMMAND", 18053 "INSTALLDIR", 18054 "BINDIR", 18055 "CONFIG_FILE_PATH", 18056 "DATADIR", 18057 "EXTENSION_DIR", 18058 "INCLUDE_PATH", 18059 "LIBDIR", 18060 "LOCALSTATEDIR", 18061 "SBINDIR", 18062 "SYSCONFDIR", 18063 "RELEASE", 18064 "SOURCE_ID", 18065 "SUBMINOR", 18066 "MINOR", 18067 "MINNOR", 18068 "MINORVERSION", 18069 "MAJOR", 18070 "MAJORVERSION", 18071 "MICRO", 18072 "MICROVERSION", 18073 "BINARY_AGE", 18074 "INTERFACE_AGE", 18075 "CORE_ABI", 18076 "PATCH", 18077 "COPYRIGHT", 18078 "TIMESTAMP", 18079 "REVISION", 18080 "PACKAGE_TAG", 18081 "PACKAGEDATE", 18082 "NUMVERSION", 18083 "Release", 18084 "Version" 18085); 18086 18087sub constantFilter($$$) 18088{ 18089 my ($Name, $Value, $Level) = @_; 18090 18091 if($Level eq "Binary") 18092 { 18093 if($Name=~/_t\Z/) 18094 { # __malloc_ptr_t 18095 return 1; 18096 } 18097 foreach (keys(%IgnoreConstant)) 18098 { 18099 if($Name=~/(\A|_)$_(_|\Z)/) 18100 { # version 18101 return 1; 18102 } 18103 if(/\A[A-Z].*[a-z]\Z/) 18104 { 18105 if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/) 18106 { # version 18107 return 1; 18108 } 18109 } 18110 } 18111 if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i) 18112 { # version 18113 return 1; 18114 } 18115 if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/) 18116 { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ... 18117 return 1; 18118 } 18119 18120 if($Value=~/\A["'].*['"]/i) 18121 { # string 18122 return 0; 18123 } 18124 18125 if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i) 18126 { # static int gcry_pth_init 18127 # extern ABC 18128 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE... 18129 # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ... 18130 return 1; 18131 } 18132 if($Value=~/\w+\s*\(/i) 18133 { # foo(p) 18134 return 1; 18135 } 18136 if($Value=~/\A[a-z_]+\w*\Z/i) 18137 { # asn1_node_st 18138 # __SMTH_P 18139 return 1; 18140 } 18141 } 18142 18143 return 0; 18144} 18145 18146sub mergeConstants($) 18147{ 18148 my $Level = $_[0]; 18149 foreach my $Constant (keys(%{$Constants{1}})) 18150 { 18151 if($SkipConstants{1}{$Constant}) 18152 { # skipped by the user 18153 next; 18154 } 18155 18156 if(my $Header = $Constants{1}{$Constant}{"Header"}) 18157 { 18158 if(not is_target_header($Header, 1) 18159 and not is_target_header($Header, 2)) 18160 { # user-defined header 18161 next; 18162 } 18163 } 18164 else { 18165 next; 18166 } 18167 18168 my $Old_Value = uncoverConstant(1, $Constant); 18169 18170 if(constantFilter($Constant, $Old_Value, $Level)) 18171 { # separate binary and source problems 18172 next; 18173 } 18174 18175 if(not defined $Constants{2}{$Constant}{"Value"}) 18176 { # removed 18177 %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = ( 18178 "Target"=>$Constant, 18179 "Old_Value"=>$Old_Value ); 18180 next; 18181 } 18182 18183 if($Constants{2}{$Constant}{"Value"} eq "") 18184 { # empty value 18185 # TODO: implement a rule 18186 next; 18187 } 18188 18189 my $New_Value = uncoverConstant(2, $Constant); 18190 18191 my $Old_Value_Pure = $Old_Value; 18192 my $New_Value_Pure = $New_Value; 18193 18194 $Old_Value_Pure=~s/(\W)\s+/$1/g; 18195 $Old_Value_Pure=~s/\s+(\W)/$1/g; 18196 $New_Value_Pure=~s/(\W)\s+/$1/g; 18197 $New_Value_Pure=~s/\s+(\W)/$1/g; 18198 18199 next if($New_Value_Pure eq "" or $Old_Value_Pure eq ""); 18200 18201 if($New_Value_Pure ne $Old_Value_Pure) 18202 { # different values 18203 if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value)) 18204 { # complex values 18205 next; 18206 } 18207 if(computeValue($Old_Value) eq computeValue($New_Value)) 18208 { # expressions 18209 next; 18210 } 18211 if(convert_integer($Old_Value) eq convert_integer($New_Value)) 18212 { # 0x0001 and 0x1, 0x1 and 1 equal constants 18213 next; 18214 } 18215 if($Old_Value eq "0" and $New_Value eq "NULL") 18216 { # 0 => NULL 18217 next; 18218 } 18219 if($Old_Value eq "NULL" and $New_Value eq "0") 18220 { # NULL => 0 18221 next; 18222 } 18223 %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = ( 18224 "Target"=>$Constant, 18225 "Old_Value"=>$Old_Value, 18226 "New_Value"=>$New_Value ); 18227 } 18228 } 18229 18230 foreach my $Constant (keys(%{$Constants{2}})) 18231 { 18232 if(not defined $Constants{1}{$Constant}{"Value"}) 18233 { 18234 if($SkipConstants{2}{$Constant}) 18235 { # skipped by the user 18236 next; 18237 } 18238 18239 if(my $Header = $Constants{2}{$Constant}{"Header"}) 18240 { 18241 if(not is_target_header($Header, 1) 18242 and not is_target_header($Header, 2)) 18243 { # user-defined header 18244 next; 18245 } 18246 } 18247 else { 18248 next; 18249 } 18250 18251 my $New_Value = uncoverConstant(2, $Constant); 18252 if(not defined $New_Value or $New_Value eq "") { 18253 next; 18254 } 18255 18256 if(constantFilter($Constant, $New_Value, $Level)) 18257 { # separate binary and source problems 18258 next; 18259 } 18260 18261 %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = ( 18262 "Target"=>$Constant, 18263 "New_Value"=>$New_Value ); 18264 } 18265 } 18266} 18267 18268sub convert_integer($) 18269{ 18270 my $Value = $_[0]; 18271 if($Value=~/\A0x[a-f0-9]+\Z/) 18272 { # hexadecimal 18273 return hex($Value); 18274 } 18275 elsif($Value=~/\A0[0-7]+\Z/) 18276 { # octal 18277 return oct($Value); 18278 } 18279 elsif($Value=~/\A0b[0-1]+\Z/) 18280 { # binary 18281 return oct($Value); 18282 } 18283 else { 18284 return $Value; 18285 } 18286} 18287 18288sub readSymbols($) 18289{ 18290 my $LibVersion = $_[0]; 18291 my @LibPaths = getSOPaths($LibVersion); 18292 if($#LibPaths==-1 and not $CheckHeadersOnly) 18293 { 18294 if($LibVersion==1) 18295 { 18296 printMsg("WARNING", "checking headers only"); 18297 $CheckHeadersOnly = 1; 18298 } 18299 else { 18300 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"}); 18301 } 18302 } 18303 18304 foreach my $LibPath (@LibPaths) { 18305 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1); 18306 } 18307 18308 if($CheckUndefined) 18309 { 18310 my %UndefinedLibs = (); 18311 18312 my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}})); 18313 18314 foreach my $LibName (sort @Libs) 18315 { 18316 if(defined $UndefinedSymbols{$LibVersion}{$LibName}) 18317 { 18318 foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}})) 18319 { 18320 if($Symbol_Library{$LibVersion}{$Symbol} 18321 or $DepSymbol_Library{$LibVersion}{$Symbol}) 18322 { # exported by target library 18323 next; 18324 } 18325 if(index($Symbol, '@')!=-1) 18326 { # exported default symbol version (@@) 18327 $Symbol=~s/\@/\@\@/; 18328 if($Symbol_Library{$LibVersion}{$Symbol} 18329 or $DepSymbol_Library{$LibVersion}{$Symbol}) { 18330 next; 18331 } 18332 } 18333 foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) { 18334 $UndefinedLibs{$Path} = 1; 18335 } 18336 } 18337 } 18338 } 18339 if($ExtraInfo) 18340 { # extra information for other tools 18341 if(my @Paths = sort keys(%UndefinedLibs)) 18342 { 18343 my $LibString = ""; 18344 my %Dirs = (); 18345 foreach (@Paths) 18346 { 18347 $KnownLibs{$_} = 1; 18348 my ($Dir, $Name) = separate_path($_); 18349 18350 if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) { 18351 $Dirs{esc($Dir)} = 1; 18352 } 18353 18354 $Name = parse_libname($Name, "name", $OStarget); 18355 $Name=~s/\Alib//; 18356 18357 $LibString .= " -l$Name"; 18358 } 18359 18360 foreach my $Dir (sort {$b cmp $a} keys(%Dirs)) 18361 { 18362 $LibString = " -L".esc($Dir).$LibString; 18363 } 18364 18365 writeFile($ExtraInfo."/libs-string", $LibString); 18366 } 18367 } 18368 } 18369 18370 if($ExtraInfo) { 18371 writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs))); 18372 } 18373 18374 if(not $CheckHeadersOnly) 18375 { 18376 if($#LibPaths!=-1) 18377 { 18378 if(not keys(%{$Symbol_Library{$LibVersion}})) 18379 { 18380 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)"); 18381 printMsg("WARNING", "checking headers only"); 18382 $CheckHeadersOnly = 1; 18383 } 18384 } 18385 } 18386 18387 # clean memory 18388 %SystemObjects = (); 18389} 18390 18391my %Prefix_Lib_Map=( 18392 # symbols for autodetecting library dependencies (by prefix) 18393 "pthread_" => ["libpthread"], 18394 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"], 18395 "cairo_" => ["libcairo"], 18396 "gtk_" => ["libgtk-x11-2.0"], 18397 "atk_" => ["libatk-1.0"], 18398 "gdk_" => ["libgdk-x11-2.0"], 18399 "gl" => ["libGL"], 18400 "glu" => ["libGLU"], 18401 "popt" => ["libpopt"], 18402 "Py" => ["libpython"], 18403 "jpeg_" => ["libjpeg"], 18404 "BZ2_" => ["libbz2"], 18405 "Fc" => ["libfontconfig"], 18406 "Xft" => ["libXft"], 18407 "SSL_" => ["libssl"], 18408 "sem_" => ["libpthread"], 18409 "snd_" => ["libasound"], 18410 "art_" => ["libart_lgpl_2"], 18411 "dbus_g" => ["libdbus-glib-1"], 18412 "GOMP_" => ["libgomp"], 18413 "omp_" => ["libgomp"], 18414 "cms" => ["liblcms"] 18415); 18416 18417my %Pattern_Lib_Map=( 18418 "SL[a-z]" => ["libslang"] 18419); 18420 18421my %Symbol_Lib_Map=( 18422 # symbols for autodetecting library dependencies (by name) 18423 "pow" => "libm", 18424 "fmod" => "libm", 18425 "sin" => "libm", 18426 "floor" => "libm", 18427 "cos" => "libm", 18428 "dlopen" => "libdl", 18429 "deflate" => "libz", 18430 "inflate" => "libz", 18431 "move_panel" => "libpanel", 18432 "XOpenDisplay" => "libX11", 18433 "resize_term" => "libncurses", 18434 "clock_gettime" => "librt", 18435 "crypt" => "libcrypt" 18436); 18437 18438sub find_SymbolLibs($$) 18439{ 18440 my ($LibVersion, $Symbol) = @_; 18441 18442 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/) 18443 { # debug symbols 18444 return (); 18445 } 18446 18447 my %Paths = (); 18448 18449 if(my $LibName = $Symbol_Lib_Map{$Symbol}) 18450 { 18451 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18452 $Paths{$Path} = 1; 18453 } 18454 } 18455 18456 if(my $SymbolPrefix = getPrefix($Symbol)) 18457 { 18458 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) { 18459 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}}; 18460 } 18461 18462 if(not keys(%Paths)) 18463 { 18464 if(defined $Prefix_Lib_Map{$SymbolPrefix}) 18465 { 18466 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}}) 18467 { 18468 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18469 $Paths{$Path} = 1; 18470 } 18471 } 18472 } 18473 } 18474 18475 if(not keys(%Paths)) 18476 { 18477 foreach my $Prefix (sort keys(%Pattern_Lib_Map)) 18478 { 18479 if($Symbol=~/\A$Prefix/) 18480 { 18481 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}}) 18482 { 18483 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { 18484 $Paths{$Path} = 1; 18485 } 18486 } 18487 } 18488 } 18489 } 18490 18491 if(not keys(%Paths)) 18492 { 18493 if($SymbolPrefix) 18494 { # try to find a library by symbol prefix 18495 if($SymbolPrefix eq "inotify" and 18496 index($Symbol, "\@GLIBC")!=-1) 18497 { 18498 if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) { 18499 $Paths{$Path} = 1; 18500 } 18501 } 18502 else 18503 { 18504 if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) { 18505 $Paths{$Path} = 1; 18506 } 18507 } 18508 } 18509 } 18510 18511 if(my @Paths = keys(%Paths)) { 18512 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths; 18513 } 18514 } 18515 return keys(%Paths); 18516} 18517 18518sub get_LibPath_Prefix($$) 18519{ 18520 my ($LibVersion, $Prefix) = @_; 18521 18522 $Prefix = lc($Prefix); 18523 $Prefix=~s/[_]+\Z//g; 18524 18525 foreach ("-2", "2", "-1", "1", "") 18526 { # libgnome-2.so 18527 # libxml2.so 18528 # libdbus-1.so 18529 if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) { 18530 return $Path; 18531 } 18532 } 18533 return ""; 18534} 18535 18536sub getPrefix($) 18537{ 18538 my $Str = $_[0]; 18539 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/) 18540 { # XmuValidArea: Xmu 18541 return $1; 18542 } 18543 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/) 18544 { # snfReadFont: snf 18545 return $1; 18546 } 18547 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/) 18548 { # XRRTimes: XRR 18549 return $1; 18550 } 18551 elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i) 18552 { # H5HF_delete: H5 18553 return $1; 18554 } 18555 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i) 18556 { # alarm_event_add: alarm_ 18557 return $1; 18558 } 18559 elsif($Str=~/\A(([a-z])\2{1,})/i) 18560 { # ffopen 18561 return $1; 18562 } 18563 return ""; 18564} 18565 18566sub getSymbolSize($$) 18567{ # size from the shared library 18568 my ($Symbol, $LibVersion) = @_; 18569 return 0 if(not $Symbol); 18570 if(defined $Symbol_Library{$LibVersion}{$Symbol} 18571 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol}) 18572 { 18573 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol} 18574 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol}) 18575 { 18576 if($Size<0) { 18577 return -$Size; 18578 } 18579 } 18580 } 18581 return 0; 18582} 18583 18584sub canonifyName($$) 18585{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*) 18586 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*) 18587 my ($Name, $Type) = @_; 18588 18589 # single 18590 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3) 18591 { 18592 my $P = $1; 18593 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g; 18594 } 18595 18596 # double 18597 if($Name=~/$DEFAULT_STD_PARMS/) 18598 { 18599 if($Type eq "S") 18600 { 18601 my ($ShortName, $FuncParams) = split_Signature($Name); 18602 18603 foreach my $FParam (separate_Params($FuncParams, 0, 0)) 18604 { 18605 if(index($FParam, "<")!=-1) 18606 { 18607 $FParam=~s/>([^<>]+)\Z/>/; # remove quals 18608 my $FParam_N = canonifyName($FParam, "T"); 18609 if($FParam_N ne $FParam) { 18610 $Name=~s/\Q$FParam\E/$FParam_N/g; 18611 } 18612 } 18613 } 18614 } 18615 elsif($Type eq "T") 18616 { 18617 my ($ShortTmpl, $TmplParams) = template_Base($Name); 18618 18619 my @TParams = separate_Params($TmplParams, 0, 0); 18620 if($#TParams>=1) 18621 { 18622 my $FParam = $TParams[0]; 18623 foreach my $Pos (1 .. $#TParams) 18624 { 18625 my $TParam = $TParams[$Pos]; 18626 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) { 18627 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g; 18628 } 18629 } 18630 } 18631 } 18632 } 18633 if($Type eq "S") { 18634 return formatName($Name, "S"); 18635 } 18636 return $Name; 18637} 18638 18639sub translateSymbols(@) 18640{ 18641 my $LibVersion = pop(@_); 18642 my (@MnglNames1, @MnglNames2, @UnmangledNames) = (); 18643 foreach my $Symbol (sort @_) 18644 { 18645 if(index($Symbol, "_Z")==0) 18646 { 18647 next if($tr_name{$Symbol}); 18648 $Symbol=~s/[\@\$]+(.*)\Z//; 18649 push(@MnglNames1, $Symbol); 18650 } 18651 elsif(index($Symbol, "?")==0) 18652 { 18653 next if($tr_name{$Symbol}); 18654 push(@MnglNames2, $Symbol); 18655 } 18656 else 18657 { # not mangled 18658 $tr_name{$Symbol} = $Symbol; 18659 $mangled_name_gcc{$Symbol} = $Symbol; 18660 $mangled_name{$LibVersion}{$Symbol} = $Symbol; 18661 } 18662 } 18663 if($#MnglNames1 > -1) 18664 { # GCC names 18665 @UnmangledNames = reverse(unmangleArray(@MnglNames1)); 18666 foreach my $MnglName (@MnglNames1) 18667 { 18668 if(my $Unmangled = pop(@UnmangledNames)) 18669 { 18670 $tr_name{$MnglName} = canonifyName($Unmangled, "S"); 18671 if(not $mangled_name_gcc{$tr_name{$MnglName}}) { 18672 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName; 18673 } 18674 if(index($MnglName, "_ZTV")==0 18675 and $tr_name{$MnglName}=~/vtable for (.+)/) 18676 { # bind class name and v-table symbol 18677 my $ClassName = $1; 18678 $ClassVTable{$ClassName} = $MnglName; 18679 $VTableClass{$MnglName} = $ClassName; 18680 } 18681 } 18682 } 18683 } 18684 if($#MnglNames2 > -1) 18685 { # MSVC names 18686 @UnmangledNames = reverse(unmangleArray(@MnglNames2)); 18687 foreach my $MnglName (@MnglNames2) 18688 { 18689 if(my $Unmangled = pop(@UnmangledNames)) 18690 { 18691 $tr_name{$MnglName} = formatName($Unmangled, "S"); 18692 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName; 18693 } 18694 } 18695 } 18696 return \%tr_name; 18697} 18698 18699sub link_symbol($$$) 18700{ 18701 my ($Symbol, $RunWith, $Deps) = @_; 18702 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) { 18703 return 1; 18704 } 18705 if($Deps eq "+Deps") 18706 { # check the dependencies 18707 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) { 18708 return 1; 18709 } 18710 } 18711 return 0; 18712} 18713 18714sub link_symbol_internal($$$) 18715{ 18716 my ($Symbol, $RunWith, $Where) = @_; 18717 return 0 if(not $Where or not $Symbol); 18718 if($Where->{$RunWith}{$Symbol}) 18719 { # the exact match by symbol name 18720 return 1; 18721 } 18722 if(my $VSym = $SymVer{$RunWith}{$Symbol}) 18723 { # indirect symbol version, i.e. 18724 # foo_old and its symlink foo@v (or foo@@v) 18725 # foo_old may be in symtab table 18726 if($Where->{$RunWith}{$VSym}) { 18727 return 1; 18728 } 18729 } 18730 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol); 18731 if($Sym and $Ver) 18732 { # search for the symbol with the same version 18733 # or without version 18734 if($Where->{$RunWith}{$Sym}) 18735 { # old: foo@v|foo@@v 18736 # new: foo 18737 return 1; 18738 } 18739 if($Where->{$RunWith}{$Sym."\@".$Ver}) 18740 { # old: foo|foo@@v 18741 # new: foo@v 18742 return 1; 18743 } 18744 if($Where->{$RunWith}{$Sym."\@\@".$Ver}) 18745 { # old: foo|foo@v 18746 # new: foo@@v 18747 return 1; 18748 } 18749 } 18750 return 0; 18751} 18752 18753sub readSymbols_App($) 18754{ 18755 my $Path = $_[0]; 18756 return () if(not $Path); 18757 my @Imported = (); 18758 if($OStarget eq "macos") 18759 { 18760 my $NM = get_CmdPath("nm"); 18761 if(not $NM) { 18762 exitStatus("Not_Found", "can't find \"nm\""); 18763 } 18764 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |"); 18765 while(<APP>) 18766 { 18767 if(/ U _([\w\$]+)\s*\Z/) { 18768 push(@Imported, $1); 18769 } 18770 } 18771 close(APP); 18772 } 18773 elsif($OStarget eq "windows") 18774 { 18775 my $DumpBinCmd = get_CmdPath("dumpbin"); 18776 if(not $DumpBinCmd) { 18777 exitStatus("Not_Found", "can't find \"dumpbin.exe\""); 18778 } 18779 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |"); 18780 while(<APP>) 18781 { 18782 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) { 18783 push(@Imported, $1); 18784 } 18785 } 18786 close(APP); 18787 } 18788 else 18789 { 18790 my $ReadelfCmd = get_CmdPath("readelf"); 18791 if(not $ReadelfCmd) { 18792 exitStatus("Not_Found", "can't find \"readelf\""); 18793 } 18794 open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |"); 18795 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 18796 while(<APP>) 18797 { 18798 if(defined $symtab) 18799 { # do nothing with symtab 18800 if(index($_, "'.dynsym'")!=-1) 18801 { # dynamic table 18802 $symtab = undef; 18803 } 18804 } 18805 elsif(index($_, "'.symtab'")!=-1) 18806 { # symbol table 18807 $symtab = 1; 18808 } 18809 elsif(my @Info = readline_ELF($_)) 18810 { 18811 my ($Ndx, $Symbol) = ($Info[5], $Info[6]); 18812 if($Ndx eq "UND") 18813 { # only imported symbols 18814 push(@Imported, $Symbol); 18815 } 18816 } 18817 } 18818 close(APP); 18819 } 18820 return @Imported; 18821} 18822 18823my %ELF_BIND = map {$_=>1} ( 18824 "WEAK", 18825 "GLOBAL" 18826); 18827 18828my %ELF_TYPE = map {$_=>1} ( 18829 "FUNC", 18830 "IFUNC", 18831 "OBJECT", 18832 "COMMON" 18833); 18834 18835my %ELF_VIS = map {$_=>1} ( 18836 "DEFAULT", 18837 "PROTECTED" 18838); 18839 18840sub readline_ELF($) 18841{ # read the line of 'readelf' output corresponding to the symbol 18842 my @Info = split(/\s+/, $_[0]); 18843 # Num: Value Size Type Bind Vis Ndx Name 18844 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4 18845 # 135: 00000000 0 FUNC GLOBAL DEFAULT UND av_image_fill_pointers@LIBAVUTIL_52 (3) 18846 shift(@Info); # spaces 18847 shift(@Info); # num 18848 18849 if($#Info==7) 18850 { # UND SYMBOL (N) 18851 if($Info[7]=~/\(\d+\)/) { 18852 pop(@Info); 18853 } 18854 } 18855 18856 if($#Info!=6) 18857 { # other lines 18858 return (); 18859 } 18860 return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND"); 18861 return () if(not defined $ELF_BIND{$Info[3]}); 18862 return () if(not defined $ELF_VIS{$Info[4]}); 18863 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/) 18864 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3 18865 return (); 18866 } 18867 if($OStarget eq "symbian") 18868 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll 18869 if(index($Info[6], "_._.absent_export_")!=-1) 18870 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll 18871 return (); 18872 } 18873 $Info[6]=~s/\@.+//g; # remove version 18874 } 18875 if(index($Info[2], "0x") == 0) 18876 { # size == 0x3d158 18877 $Info[2] = hex($Info[2]); 18878 } 18879 return @Info; 18880} 18881 18882sub get_LibPath($$) 18883{ 18884 my ($LibVersion, $Name) = @_; 18885 return "" if(not $LibVersion or not $Name); 18886 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) { 18887 return $Cache{"get_LibPath"}{$LibVersion}{$Name}; 18888 } 18889 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name)); 18890} 18891 18892sub get_LibPath_I($$) 18893{ 18894 my ($LibVersion, $Name) = @_; 18895 if(is_abs($Name)) 18896 { 18897 if(-f $Name) 18898 { # absolute path 18899 return $Name; 18900 } 18901 else 18902 { # broken 18903 return ""; 18904 } 18905 } 18906 if(defined $RegisteredObjects{$LibVersion}{$Name}) 18907 { # registered paths 18908 return $RegisteredObjects{$LibVersion}{$Name}; 18909 } 18910 if(defined $RegisteredSONAMEs{$LibVersion}{$Name}) 18911 { # registered paths 18912 return $RegisteredSONAMEs{$LibVersion}{$Name}; 18913 } 18914 if(my $DefaultPath = $DyLib_DefaultPath{$Name}) 18915 { # ldconfig default paths 18916 return $DefaultPath; 18917 } 18918 foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}}) 18919 { # search in default linker directories 18920 # and then in all system paths 18921 if(-f $Dir."/".$Name) { 18922 return join_P($Dir,$Name); 18923 } 18924 } 18925 if(not defined $Cache{"checkSystemFiles"}) { 18926 checkSystemFiles(); 18927 } 18928 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) { 18929 return $AllObjects[0]; 18930 } 18931 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget)) 18932 { 18933 if($ShortName ne $Name) 18934 { # FIXME: check this case 18935 if(my $Path = get_LibPath($LibVersion, $ShortName)) { 18936 return $Path; 18937 } 18938 } 18939 } 18940 # can't find 18941 return ""; 18942} 18943 18944sub readSymbols_Lib($$$$$$) 18945{ 18946 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; 18947 return () if(not $LibVersion or not $Lib_Path); 18948 18949 my $Real_Path = realpath($Lib_Path); 18950 18951 if(not $Real_Path) 18952 { # broken link 18953 return (); 18954 } 18955 18956 my $Lib_Name = get_filename($Real_Path); 18957 18958 if($ExtraInfo) 18959 { 18960 $KnownLibs{$Real_Path} = 1; 18961 $KnownLibs{$Lib_Path} = 1; # links 18962 } 18963 18964 if($IsNeededLib) 18965 { 18966 if($CheckedDyLib{$LibVersion}{$Lib_Name}) { 18967 return (); 18968 } 18969 } 18970 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1); 18971 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1; 18972 18973 push(@RecurLib, $Lib_Name); 18974 my (%Value_Interface, %Interface_Value, %NeededLib) = (); 18975 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget); 18976 18977 if(not $IsNeededLib) 18978 { # special cases: libstdc++ and libc 18979 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget)) 18980 { 18981 if($ShortName eq "libstdc++") 18982 { # libstdc++.so.6 18983 $STDCXX_TESTING = 1; 18984 } 18985 elsif($ShortName eq "libc") 18986 { # libc-2.11.3.so 18987 $GLIBC_TESTING = 1; 18988 } 18989 } 18990 } 18991 my $DebugPath = ""; 18992 if($Debug and not $DumpSystem) 18993 { # debug mode 18994 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt"; 18995 mkpath(get_dirname($DebugPath)); 18996 } 18997 if($OStarget eq "macos") 18998 { # Mac OS X: *.dylib, *.a 18999 my $NM = get_CmdPath("nm"); 19000 if(not $NM) { 19001 exitStatus("Not_Found", "can't find \"nm\""); 19002 } 19003 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19004 if($DebugPath) 19005 { # debug mode 19006 # write to file 19007 system($NM." >\"$DebugPath\""); 19008 open(LIB, $DebugPath); 19009 } 19010 else 19011 { # write to pipe 19012 open(LIB, $NM." |"); 19013 } 19014 while(<LIB>) 19015 { 19016 if($CheckUndefined) 19017 { 19018 if(not $IsNeededLib) 19019 { 19020 if(/ U _([\w\$]+)\s*\Z/) 19021 { 19022 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0; 19023 next; 19024 } 19025 } 19026 } 19027 19028 if(/ [STD] _([\w\$]+)\s*\Z/) 19029 { 19030 my $Symbol = $1; 19031 if($IsNeededLib) 19032 { 19033 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19034 { 19035 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19036 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 19037 } 19038 } 19039 else 19040 { 19041 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19042 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; 19043 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19044 { 19045 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 19046 setLanguage($LibVersion, "C++"); 19047 } 19048 } 19049 } 19050 } 19051 } 19052 close(LIB); 19053 19054 if($Deps) 19055 { 19056 if($LIB_TYPE eq "dynamic") 19057 { # dependencies 19058 19059 my $OtoolCmd = get_CmdPath("otool"); 19060 if(not $OtoolCmd) { 19061 exitStatus("Not_Found", "can't find \"otool\""); 19062 } 19063 19064 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 19065 while(<LIB>) 19066 { 19067 if(/\s*([\/\\].+\.$LIB_EXT)\s*/ 19068 and $1 ne $Lib_Path) { 19069 $NeededLib{$1} = 1; 19070 } 19071 } 19072 close(LIB); 19073 } 19074 } 19075 } 19076 elsif($OStarget eq "windows") 19077 { # Windows *.dll, *.lib 19078 my $DumpBinCmd = get_CmdPath("dumpbin"); 19079 if(not $DumpBinCmd) { 19080 exitStatus("Not_Found", "can't find \"dumpbin\""); 19081 } 19082 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null"; 19083 if($DebugPath) 19084 { # debug mode 19085 # write to file 19086 system($DumpBinCmd." >\"$DebugPath\""); 19087 open(LIB, $DebugPath); 19088 } 19089 else 19090 { # write to pipe 19091 open(LIB, $DumpBinCmd." |"); 19092 } 19093 while(<LIB>) 19094 { # 1197 4AC 0000A620 SetThreadStackGuarantee 19095 # 1198 4AD SetThreadToken (forwarded to ...) 19096 # 3368 _o2i_ECPublicKey 19097 # 1 0 00005B30 ??0?N = ... (with pdb) 19098 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i 19099 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ 19100 or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) 19101 { # dynamic, static and forwarded symbols 19102 my $realname = $1; 19103 if($IsNeededLib) 19104 { 19105 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19106 { 19107 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name; 19108 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 19109 } 19110 } 19111 else 19112 { 19113 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name; 19114 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; 19115 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19116 { 19117 if(index($realname, "_Z")==0 or index($realname, "?")==0) { 19118 setLanguage($LibVersion, "C++"); 19119 } 19120 } 19121 } 19122 } 19123 } 19124 close(LIB); 19125 19126 if($Deps) 19127 { 19128 if($LIB_TYPE eq "dynamic") 19129 { # dependencies 19130 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); 19131 while(<LIB>) 19132 { 19133 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i 19134 and $1 ne $Lib_Path) { 19135 $NeededLib{path_format($1, $OSgroup)} = 1; 19136 } 19137 } 19138 close(LIB); 19139 } 19140 } 19141 } 19142 else 19143 { # Unix; *.so, *.a 19144 # Symbian: *.dso, *.lib 19145 my $ReadelfCmd = get_CmdPath("readelf"); 19146 if(not $ReadelfCmd) { 19147 exitStatus("Not_Found", "can't find \"readelf\""); 19148 } 19149 my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19150 if($DebugPath) 19151 { # debug mode 19152 # write to file 19153 system($Cmd." >\"$DebugPath\""); 19154 open(LIB, $DebugPath); 19155 } 19156 else 19157 { # write to pipe 19158 open(LIB, $Cmd." |"); 19159 } 19160 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 19161 while(<LIB>) 19162 { 19163 if($LIB_TYPE eq "dynamic") 19164 { # dynamic library specifics 19165 if(defined $symtab) 19166 { 19167 if(index($_, "'.dynsym'")!=-1) 19168 { # dynamic table 19169 $symtab = undef; 19170 } 19171 # do nothing with symtab 19172 next; 19173 } 19174 elsif(index($_, "'.symtab'")!=-1) 19175 { # symbol table 19176 $symtab = 1; 19177 next; 19178 } 19179 } 19180 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_)) 19181 { # read ELF entry 19182 if($Ndx eq "UND") 19183 { # ignore interfaces that are imported from somewhere else 19184 if($CheckUndefined) 19185 { 19186 if(not $IsNeededLib) { 19187 $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0; 19188 } 19189 } 19190 next; 19191 } 19192 if($Bind eq "WEAK") 19193 { 19194 $WeakSymbols{$LibVersion}{$Symbol} = 1; 19195 if($Weak eq "-Weak") 19196 { # skip WEAK symbols 19197 next; 19198 } 19199 } 19200 my $Short = $Symbol; 19201 $Short=~s/\@.+//g; 19202 if($Type eq "OBJECT") 19203 { # global data 19204 $GlobalDataObject{$LibVersion}{$Symbol} = $Size; 19205 $GlobalDataObject{$LibVersion}{$Short} = $Size; 19206 } 19207 if($IsNeededLib) 19208 { 19209 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) 19210 { 19211 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19212 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19213 } 19214 } 19215 else 19216 { 19217 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 19218 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 19219 if($Vers) 19220 { 19221 if($LIB_EXT eq "so") 19222 { # value 19223 $Interface_Value{$LibVersion}{$Symbol} = $Value; 19224 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1; 19225 } 19226 } 19227 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 19228 { 19229 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 19230 setLanguage($LibVersion, "C++"); 19231 } 19232 } 19233 } 19234 } 19235 } 19236 close(LIB); 19237 19238 if($Deps and $LIB_TYPE eq "dynamic") 19239 { # dynamic library specifics 19240 $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\""; 19241 open(LIB, $Cmd." |"); 19242 19243 while(<LIB>) 19244 { 19245 if(/NEEDED.+\[([^\[\]]+)\]/) 19246 { # dependencies: 19247 # 0x00000001 (NEEDED) Shared library: [libc.so.6] 19248 $NeededLib{$1} = 1; 19249 } 19250 } 19251 19252 close(LIB); 19253 } 19254 } 19255 if($Vers) 19256 { 19257 if(not $IsNeededLib and $LIB_EXT eq "so") 19258 { # get symbol versions 19259 my %Found = (); 19260 19261 # by value 19262 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19263 { 19264 next if(index($Symbol,"\@")==-1); 19265 if(my $Value = $Interface_Value{$LibVersion}{$Symbol}) 19266 { 19267 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}})) 19268 { 19269 if($Symbol_SameValue ne $Symbol 19270 and index($Symbol_SameValue,"\@")==-1) 19271 { 19272 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol; 19273 $Found{$Symbol} = 1; 19274 last; 19275 } 19276 } 19277 } 19278 } 19279 19280 # default 19281 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19282 { 19283 next if(defined $Found{$Symbol}); 19284 next if(index($Symbol,"\@\@")==-1); 19285 19286 if($Symbol=~/\A([^\@]*)\@\@/ 19287 and not $SymVer{$LibVersion}{$1}) 19288 { 19289 $SymVer{$LibVersion}{$1} = $Symbol; 19290 $Found{$Symbol} = 1; 19291 } 19292 } 19293 19294 # non-default 19295 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 19296 { 19297 next if(defined $Found{$Symbol}); 19298 next if(index($Symbol,"\@")==-1); 19299 19300 if($Symbol=~/\A([^\@]*)\@([^\@]*)/ 19301 and not $SymVer{$LibVersion}{$1}) 19302 { 19303 $SymVer{$LibVersion}{$1} = $Symbol; 19304 $Found{$Symbol} = 1; 19305 } 19306 } 19307 } 19308 } 19309 if($Deps) 19310 { 19311 foreach my $DyLib (sort keys(%NeededLib)) 19312 { 19313 $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1; 19314 19315 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) 19316 { 19317 if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) { 19318 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers); 19319 } 19320 } 19321 } 19322 } 19323 pop(@RecurLib); 19324 return $Library_Symbol{$LibVersion}; 19325} 19326 19327sub get_prefixes($) 19328{ 19329 my %Prefixes = (); 19330 get_prefixes_I([$_[0]], \%Prefixes); 19331 return keys(%Prefixes); 19332} 19333 19334sub get_prefixes_I($$) 19335{ 19336 foreach my $P (@{$_[0]}) 19337 { 19338 my @Parts = reverse(split(/[\/\\]+/, $P)); 19339 my $Name = $Parts[0]; 19340 foreach (1 .. $#Parts) 19341 { 19342 $_[1]->{$Name}{$P} = 1; 19343 last if($_>4 or $Parts[$_] eq "include"); 19344 $Name = $Parts[$_].$SLASH.$Name; 19345 } 19346 } 19347} 19348 19349sub checkSystemFiles() 19350{ 19351 $Cache{"checkSystemFiles"} = 1; 19352 19353 my @SysHeaders = (); 19354 19355 foreach my $DevelPath (@{$SystemPaths{"lib"}}) 19356 { 19357 next if(not -d $DevelPath); 19358 19359 my @Files = cmd_find($DevelPath,"f"); 19360 foreach my $Link (cmd_find($DevelPath,"l")) 19361 { # add symbolic links 19362 if(-f $Link) { 19363 push(@Files, $Link); 19364 } 19365 } 19366 19367 # search for headers in /usr/lib 19368 my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; 19369 @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; 19370 push(@SysHeaders, @Headers); 19371 19372 # search for libraries in /usr/lib (including symbolic links) 19373 my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files; 19374 foreach my $Path (@Libs) 19375 { 19376 my $N = get_filename($Path); 19377 $SystemObjects{$N}{$Path} = 1; 19378 $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1; 19379 } 19380 } 19381 19382 foreach my $DevelPath (@{$SystemPaths{"include"}}) 19383 { 19384 next if(not -d $DevelPath); 19385 # search for all header files in the /usr/include 19386 # with or without extension (ncurses.h, QtCore, ...) 19387 push(@SysHeaders, cmd_find($DevelPath,"f")); 19388 foreach my $Link (cmd_find($DevelPath,"l")) 19389 { # add symbolic links 19390 if(-f $Link) { 19391 push(@SysHeaders, $Link); 19392 } 19393 } 19394 } 19395 get_prefixes_I(\@SysHeaders, \%SystemHeaders); 19396} 19397 19398sub getSOPaths($) 19399{ 19400 my $LibVersion = $_[0]; 19401 my @Paths = (); 19402 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"})) 19403 { 19404 if(not -e $Dest) { 19405 exitStatus("Access_Error", "can't access \'$Dest\'"); 19406 } 19407 $Dest = get_abs_path($Dest); 19408 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion); 19409 foreach (@SoPaths_Dest) { 19410 push(@Paths, $_); 19411 } 19412 } 19413 return sort @Paths; 19414} 19415 19416sub skipLib($$) 19417{ 19418 my ($Path, $LibVersion) = @_; 19419 return 1 if(not $Path or not $LibVersion); 19420 my $Name = get_filename($Path); 19421 if($SkipLibs{$LibVersion}{"Name"}{$Name}) { 19422 return 1; 19423 } 19424 my $ShortName = parse_libname($Name, "name+ext", $OStarget); 19425 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) { 19426 return 1; 19427 } 19428 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}})) 19429 { 19430 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) { 19431 return 1; 19432 } 19433 } 19434 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}})) 19435 { 19436 if($Name=~/$P/) { 19437 return 1; 19438 } 19439 if($P=~/[\/\\]/ and $Path=~/$P/) { 19440 return 1; 19441 } 19442 } 19443 return 0; 19444} 19445 19446sub specificHeader($$) 19447{ 19448 my ($Header, $Spec) = @_; 19449 my $Name = get_filename($Header); 19450 19451 if($Spec eq "windows") 19452 {# MS Windows 19453 return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i); 19454 return 1 if($Name=~/([._-]w|win)(32|64)/i); 19455 return 1 if($Name=~/\A(Win|Windows)[A-Z]/); 19456 return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i); 19457 my @Dirs = ( 19458 "win32", 19459 "win64", 19460 "win", 19461 "windows", 19462 "msvcrt" 19463 ); # /gsf-win32/ 19464 if(my $DIRs = join("|", @Dirs)) { 19465 return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19466 } 19467 } 19468 elsif($Spec eq "macos") 19469 { # Mac OS 19470 return 1 if($Name=~/(\A|[_-])mac[._-]/i); 19471 } 19472 19473 return 0; 19474} 19475 19476sub skipAlienHeader($) 19477{ 19478 my $Path = $_[0]; 19479 my $Name = get_filename($Path); 19480 my $Dir = get_dirname($Path); 19481 19482 if($Tolerance=~/2/) 19483 { # 2 - skip internal headers 19484 my @Terms = ( 19485 "p", 19486 "priv", 19487 "int", 19488 "impl", 19489 "implementation", 19490 "internal", 19491 "private", 19492 "old", 19493 "compat", 19494 "debug", 19495 "test", 19496 "gen" 19497 ); 19498 19499 my @Dirs = ( 19500 "private", 19501 "priv", 19502 "port", 19503 "impl", 19504 "internal", 19505 "detail", 19506 "details", 19507 "old", 19508 "compat", 19509 "debug", 19510 "config", 19511 "compiler", 19512 "platform", 19513 "test" 19514 ); 19515 19516 if(my $TERMs = join("|", @Terms)) { 19517 return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i); 19518 } 19519 if(my $DIRs = join("|", @Dirs)) { 19520 return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); 19521 } 19522 19523 return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/); 19524 } 19525 19526 if($Tolerance=~/1/) 19527 { # 1 - skip non-Linux headers 19528 if($OSgroup ne "windows") 19529 { 19530 if(specificHeader($Path, "windows")) { 19531 return 1; 19532 } 19533 } 19534 if($OSgroup ne "macos") 19535 { 19536 if(specificHeader($Path, "macos")) { 19537 return 1; 19538 } 19539 } 19540 } 19541 19542 # valid 19543 return 0; 19544} 19545 19546sub skipHeader($$) 19547{ 19548 my ($Path, $LibVersion) = @_; 19549 return 1 if(not $Path or not $LibVersion); 19550 if(defined $Cache{"skipHeader"}{$Path}) { 19551 return $Cache{"skipHeader"}{$Path}; 19552 } 19553 if(defined $Tolerance and $Tolerance=~/1|2/) 19554 { # --tolerant 19555 if(skipAlienHeader($Path)) { 19556 return ($Cache{"skipHeader"}{$Path} = 1); 19557 } 19558 } 19559 if(not keys(%{$SkipHeaders{$LibVersion}})) { 19560 return 0; 19561 } 19562 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_)); 19563} 19564 19565sub skipHeader_I($$) 19566{ # returns: 19567 # 1 - if header should NOT be included and checked 19568 # 2 - if header should NOT be included, but should be checked 19569 my ($Path, $LibVersion) = @_; 19570 my $Name = get_filename($Path); 19571 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) { 19572 return $Kind; 19573 } 19574 foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}} 19575 keys(%{$SkipHeaders{$LibVersion}{"Path"}})) 19576 { 19577 if(index($Path, $D)!=-1) 19578 { 19579 if($Path=~/\Q$D\E([\/\\]|\Z)/) { 19580 return $SkipHeaders{$LibVersion}{"Path"}{$D}; 19581 } 19582 } 19583 } 19584 foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}} 19585 keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) 19586 { 19587 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P}) 19588 { 19589 if($Name=~/$P/) { 19590 return $Kind; 19591 } 19592 if($P=~/[\/\\]/ and $Path=~/$P/) { 19593 return $Kind; 19594 } 19595 } 19596 } 19597 19598 return 0; 19599} 19600 19601sub registerObject_Dir($$) 19602{ 19603 my ($Dir, $LibVersion) = @_; 19604 if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}}) 19605 { # system directory 19606 return; 19607 } 19608 if($RegisteredObject_Dirs{$LibVersion}{$Dir}) 19609 { # already registered 19610 return; 19611 } 19612 foreach my $Path (find_libs($Dir,"",1)) 19613 { 19614 next if(ignore_path($Path)); 19615 next if(skipLib($Path, $LibVersion)); 19616 registerObject($Path, $LibVersion); 19617 } 19618 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1; 19619} 19620 19621sub registerObject($$) 19622{ 19623 my ($Path, $LibVersion) = @_; 19624 19625 my $Name = get_filename($Path); 19626 $RegisteredObjects{$LibVersion}{$Name} = $Path; 19627 if($OStarget=~/linux|bsd|gnu/i) 19628 { 19629 if(my $SONAME = getSONAME($Path)) { 19630 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path; 19631 } 19632 } 19633 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) { 19634 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path; 19635 } 19636 19637 if(not $CheckedArch{$LibVersion} and -f $Path) 19638 { 19639 if(my $ObjArch = getArch_Object($Path)) 19640 { 19641 if($ObjArch ne getArch_GCC($LibVersion)) 19642 { # translation unit dump generated by the GCC compiler should correspond to the input objects 19643 $CheckedArch{$LibVersion} = 1; 19644 printMsg("WARNING", "the architectures of input objects and the used GCC compiler are not equal, please change the compiler by --gcc-path=PATH option."); 19645 } 19646 } 19647 } 19648} 19649 19650sub getArch_Object($) 19651{ 19652 my $Path = $_[0]; 19653 19654 my %MachineType = ( 19655 "14C" => "x86", 19656 "8664" => "x86_64", 19657 "1C0" => "arm", 19658 "200" => "ia64" 19659 ); 19660 19661 my %ArchName = ( 19662 "s390:31-bit" => "s390", 19663 "s390:64-bit" => "s390x", 19664 "powerpc:common" => "ppc32", 19665 "powerpc:common64" => "ppc64", 19666 "i386:x86-64" => "x86_64", 19667 "mips:3000" => "mips", 19668 "sparc:v8plus" => "sparcv9" 19669 ); 19670 19671 if($OStarget eq "windows") 19672 { 19673 my $DumpbinCmd = get_CmdPath("dumpbin"); 19674 if(not $DumpbinCmd) { 19675 exitStatus("Not_Found", "can't find \"dumpbin\""); 19676 } 19677 19678 my $Cmd = $DumpbinCmd." /headers \"$Path\""; 19679 my $Out = `$Cmd`; 19680 19681 if($Out=~/(\w+)\smachine/) 19682 { 19683 if(my $Type = $MachineType{uc($1)}) 19684 { 19685 return $Type; 19686 } 19687 } 19688 } 19689 elsif($OStarget=~/linux|bsd|gnu/) 19690 { 19691 my $ObjdumpCmd = get_CmdPath("objdump"); 19692 if(not $ObjdumpCmd) { 19693 exitStatus("Not_Found", "can't find \"objdump\""); 19694 } 19695 19696 my $Cmd = $ObjdumpCmd." -f \"$Path\""; 19697 19698 if($OSgroup eq "windows") { 19699 $Cmd = "set LANG=$LOCALE & ".$Cmd; 19700 } 19701 else { 19702 $Cmd = "LANG=$LOCALE ".$Cmd; 19703 } 19704 my $Out = `$Cmd`; 19705 19706 if($Out=~/architecture:\s+([\w\-\:]+)/) 19707 { 19708 my $Arch = $1; 19709 if($Arch=~s/\:(.+)//) 19710 { 19711 my $Suffix = $1; 19712 19713 if(my $Name = $ArchName{$Arch.":".$Suffix}) 19714 { 19715 $Arch = $Name; 19716 } 19717 } 19718 19719 if($Arch=~/i[3-6]86/) { 19720 $Arch = "x86"; 19721 } 19722 19723 if($Arch eq "x86-64") { 19724 $Arch = "x86_64"; 19725 } 19726 19727 if($Arch eq "ia64-elf64") { 19728 $Arch = "ia64"; 19729 } 19730 19731 return $Arch; 19732 } 19733 } 19734 else 19735 { # macos, etc. 19736 # TODO 19737 } 19738 19739 return undef; 19740} 19741 19742sub getSONAME($) 19743{ 19744 my $Path = $_[0]; 19745 return if(not $Path); 19746 if(defined $Cache{"getSONAME"}{$Path}) { 19747 return $Cache{"getSONAME"}{$Path}; 19748 } 19749 my $ObjdumpCmd = get_CmdPath("objdump"); 19750 if(not $ObjdumpCmd) { 19751 exitStatus("Not_Found", "can't find \"objdump\""); 19752 } 19753 my $SonameCmd = "$ObjdumpCmd -x \"$Path\" 2>$TMP_DIR/null"; 19754 if($OSgroup eq "windows") { 19755 $SonameCmd .= " | find \"SONAME\""; 19756 } 19757 else { 19758 $SonameCmd .= " | grep SONAME"; 19759 } 19760 if(my $SonameInfo = `$SonameCmd`) 19761 { 19762 if($SonameInfo=~/SONAME\s+([^\s]+)/) { 19763 return ($Cache{"getSONAME"}{$Path} = $1); 19764 } 19765 } 19766 return ($Cache{"getSONAME"}{$Path}=""); 19767} 19768 19769sub getSOPaths_Dest($$) 19770{ 19771 my ($Dest, $LibVersion) = @_; 19772 if(skipLib($Dest, $LibVersion)) { 19773 return (); 19774 } 19775 if(-f $Dest) 19776 { 19777 if(not parse_libname($Dest, "name", $OStarget)) { 19778 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'"); 19779 } 19780 registerObject($Dest, $LibVersion); 19781 registerObject_Dir(get_dirname($Dest), $LibVersion); 19782 return ($Dest); 19783 } 19784 elsif(-d $Dest) 19785 { 19786 $Dest=~s/[\/\\]+\Z//g; 19787 my %Libs = (); 19788 if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}}) 19789 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor 19790 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...) 19791 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2)) 19792 { # all files and symlinks that match the name of a library 19793 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i) 19794 { 19795 registerObject($Path, $LibVersion); 19796 $Libs{realpath($Path)}=1; 19797 } 19798 } 19799 } 19800 else 19801 { # search for all files and symlinks 19802 foreach my $Path (find_libs($Dest,"","")) 19803 { 19804 next if(ignore_path($Path)); 19805 next if(skipLib($Path, $LibVersion)); 19806 registerObject($Path, $LibVersion); 19807 $Libs{realpath($Path)}=1; 19808 } 19809 if($OSgroup eq "macos") 19810 { # shared libraries on MacOS X may have no extension 19811 foreach my $Path (cmd_find($Dest,"f")) 19812 { 19813 next if(ignore_path($Path)); 19814 next if(skipLib($Path, $LibVersion)); 19815 if(get_filename($Path)!~/\./ 19816 and cmd_file($Path)=~/(shared|dynamic)\s+library/i) 19817 { 19818 registerObject($Path, $LibVersion); 19819 $Libs{realpath($Path)}=1; 19820 } 19821 } 19822 } 19823 } 19824 return keys(%Libs); 19825 } 19826 else { 19827 return (); 19828 } 19829} 19830 19831sub isCyclical($$) 19832{ 19833 my ($Stack, $Value) = @_; 19834 return (grep {$_ eq $Value} @{$Stack}); 19835} 19836 19837sub getGCC_Opts($) 19838{ # to use in module 19839 my $LibVersion = $_[0]; 19840 19841 my @Opts = (); 19842 19843 if($CompilerOptions{$LibVersion}) 19844 { # user-defined options 19845 push(@Opts, $CompilerOptions{$LibVersion}); 19846 } 19847 if($GccOptions) 19848 { # additional 19849 push(@Opts, $GccOptions); 19850 } 19851 19852 if(@Opts) { 19853 return join(" ", @Opts); 19854 } 19855 19856 return undef; 19857} 19858 19859sub getArch_GCC($) 19860{ 19861 my $LibVersion = $_[0]; 19862 19863 if(defined $Cache{"getArch_GCC"}{$LibVersion}) { 19864 return $Cache{"getArch_GCC"}{$LibVersion}; 19865 } 19866 19867 my $Arch = undef; 19868 19869 if($GCC_PATH) 19870 { 19871 writeFile("$TMP_DIR/test.c", "int main(){return 0;}\n"); 19872 19873 my $Cmd = $GCC_PATH." test.c -o test"; 19874 if(my $Opts = getGCC_Opts($LibVersion)) 19875 { # user-defined options 19876 $Cmd .= " ".$Opts; 19877 } 19878 19879 chdir($TMP_DIR); 19880 system($Cmd); 19881 chdir($ORIG_DIR); 19882 19883 $Arch = getArch_Object("$TMP_DIR/test"); 19884 19885 unlink("$TMP_DIR/test.c"); 19886 unlink("$TMP_DIR/test"); 19887 } 19888 19889 if(not $Arch) { 19890 exitStatus("Error", "can't check ARCH type"); 19891 } 19892 19893 return ($Cache{"getArch_GCC"}{$LibVersion} = $Arch); 19894} 19895 19896sub detectWordSize($) 19897{ 19898 my $LibVersion = $_[0]; 19899 19900 my $Size = undef; 19901 19902 # speed up detection 19903 if(my $Arch = getArch($LibVersion)) 19904 { 19905 if($Arch=~/\A(x86_64|s390x|ppc64|ia64|alpha)\Z/) { 19906 $Size = "8"; 19907 } 19908 elsif($Arch=~/\A(x86|s390|ppc32)\Z/) { 19909 $Size = "4"; 19910 } 19911 } 19912 19913 if($GCC_PATH) 19914 { 19915 writeFile("$TMP_DIR/empty.h", ""); 19916 19917 my $Cmd = $GCC_PATH." -E -dD empty.h"; 19918 if(my $Opts = getGCC_Opts($LibVersion)) 19919 { # user-defined options 19920 $Cmd .= " ".$Opts; 19921 } 19922 19923 chdir($TMP_DIR); 19924 my $Defines = `$Cmd`; 19925 chdir($ORIG_DIR); 19926 19927 unlink("$TMP_DIR/empty.h"); 19928 19929 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/) 19930 { # GCC 4 19931 $Size = $1; 19932 } 19933 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/) 19934 { # GCC 3 19935 my $PTRDIFF = $1; 19936 if($PTRDIFF=~/long/) { 19937 $Size = "8"; 19938 } 19939 else { 19940 $Size = "4"; 19941 } 19942 } 19943 } 19944 19945 if(not $Size) { 19946 exitStatus("Error", "can't check WORD size"); 19947 } 19948 19949 return $Size; 19950} 19951 19952sub getWordSize($) 19953{ # to use in module 19954 return $WORD_SIZE{$_[0]}; 19955} 19956 19957sub majorVersion($) 19958{ 19959 my $V = $_[0]; 19960 return 0 if(not $V); 19961 my @VParts = split(/\./, $V); 19962 return $VParts[0]; 19963} 19964 19965sub cmpVersions($$) 19966{ # compare two versions in dotted-numeric format 19967 my ($V1, $V2) = @_; 19968 return 0 if($V1 eq $V2); 19969 my @V1Parts = split(/\./, $V1); 19970 my @V2Parts = split(/\./, $V2); 19971 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) 19972 { 19973 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); 19974 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); 19975 } 19976 return -1 if($#V1Parts < $#V2Parts); 19977 return 1 if($#V1Parts > $#V2Parts); 19978 return 0; 19979} 19980 19981sub read_ABI_Dump($$) 19982{ 19983 my ($LibVersion, $Path) = @_; 19984 return if(not $LibVersion or not -e $Path); 19985 my $FilePath = ""; 19986 if(isDump_U($Path)) 19987 { # input *.abi 19988 $FilePath = $Path; 19989 } 19990 else 19991 { # input *.abi.tar.gz 19992 $FilePath = unpackDump($Path); 19993 if(not isDump_U($FilePath)) { 19994 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 19995 } 19996 } 19997 19998 my $ABI = {}; 19999 20000 my $Line = readLineNum($FilePath, 0); 20001 if($Line=~/xml/) 20002 { # XML format 20003 loadModule("XmlDump"); 20004 $ABI = readXmlDump($FilePath); 20005 } 20006 else 20007 { # Perl Data::Dumper format (default) 20008 open(DUMP, $FilePath); 20009 local $/ = undef; 20010 my $Content = <DUMP>; 20011 close(DUMP); 20012 20013 if(get_dirname($FilePath) eq $TMP_DIR."/unpack") 20014 { # remove temp file 20015 unlink($FilePath); 20016 } 20017 if($Content!~/};\s*\Z/) { 20018 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); 20019 } 20020 $ABI = eval($Content); 20021 if(not $ABI) { 20022 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 20023 } 20024 } 20025 # new dumps (>=1.22) have a personal versioning 20026 my $DVersion = $ABI->{"ABI_DUMP_VERSION"}; 20027 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}; 20028 if(not $DVersion) 20029 { # old dumps (<=1.21.6) have been marked by the tool version 20030 $DVersion = $ToolVersion; 20031 } 20032 $UsedDump{$LibVersion}{"V"} = $DVersion; 20033 $UsedDump{$LibVersion}{"M"} = $ABI->{"LibraryName"}; 20034 20035 if($ABI->{"PublicABI"}) { 20036 $UsedDump{$LibVersion}{"Public"} = 1; 20037 } 20038 20039 if($ABI->{"ABI_DUMP_VERSION"}) 20040 { 20041 if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0) 20042 { # Don't know how to parse future dump formats 20043 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)"); 20044 } 20045 } 20046 else 20047 { # support for old ABI dumps 20048 if(cmpVersions($DVersion, $TOOL_VERSION)>0) 20049 { # Don't know how to parse future dump formats 20050 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)"); 20051 } 20052 } 20053 20054 if(majorVersion($DVersion)<2) 20055 { 20056 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)"); 20057 } 20058 20059 if(defined $ABI->{"ABI_DUMPER_VERSION"}) 20060 { # DWARF ABI Dump 20061 $UseConv_Real{$LibVersion}{"P"} = 1; 20062 $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet 20063 20064 $UsedDump{$LibVersion}{"DWARF"} = 1; 20065 20066 if(not $TargetComponent_Opt) 20067 { 20068 if($ABI->{"LibraryName"}=~/\.ko[\.\d]*\Z/) { 20069 $TargetComponent = "module"; 20070 } 20071 else { 20072 $TargetComponent = "object"; 20073 } 20074 } 20075 } 20076 20077 if(not checkDump($LibVersion, "2.11")) 20078 { # old ABI dumps 20079 $UsedDump{$LibVersion}{"BinOnly"} = 1; 20080 } 20081 elsif($ABI->{"BinOnly"}) 20082 { # ABI dump created with --binary option 20083 $UsedDump{$LibVersion}{"BinOnly"} = 1; 20084 } 20085 else 20086 { # default 20087 $UsedDump{$LibVersion}{"SrcBin"} = 1; 20088 } 20089 20090 if(defined $ABI->{"Mode"} 20091 and $ABI->{"Mode"} eq "Extended") 20092 { # --ext option 20093 $ExtendedCheck = 1; 20094 } 20095 if($ABI->{"Extra"}) { 20096 $ExtraDump = 1; 20097 } 20098 20099 if(my $Lang = $ABI->{"Language"}) 20100 { 20101 $UsedDump{$LibVersion}{"L"} = $Lang; 20102 setLanguage($LibVersion, $Lang); 20103 } 20104 if(checkDump($LibVersion, "2.15")) { 20105 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"}; 20106 } 20107 else 20108 { # support for old ABI dumps 20109 my $TInfo = $ABI->{"TypeInfo"}; 20110 if(not $TInfo) 20111 { # support for older ABI dumps 20112 $TInfo = $ABI->{"TypeDescr"}; 20113 } 20114 my %Tid_TDid = (); 20115 foreach my $TDid (keys(%{$TInfo})) 20116 { 20117 foreach my $Tid (keys(%{$TInfo->{$TDid}})) 20118 { 20119 $MAX_ID = $Tid if($Tid>$MAX_ID); 20120 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID); 20121 $Tid_TDid{$Tid}{$TDid} = 1; 20122 } 20123 } 20124 my %NewID = (); 20125 foreach my $Tid (keys(%Tid_TDid)) 20126 { 20127 my @TDids = keys(%{$Tid_TDid{$Tid}}); 20128 if($#TDids>=1) 20129 { 20130 foreach my $TDid (@TDids) 20131 { 20132 if($TDid) { 20133 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 20134 } 20135 else 20136 { 20137 my $ID = ++$MAX_ID; 20138 20139 $NewID{$TDid}{$Tid} = $ID; 20140 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; 20141 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; 20142 } 20143 } 20144 } 20145 else 20146 { 20147 my $TDid = $TDids[0]; 20148 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; 20149 } 20150 } 20151 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 20152 { 20153 my %Info = %{$TypeInfo{$LibVersion}{$Tid}}; 20154 if(defined $Info{"BaseType"}) 20155 { 20156 my $Bid = $Info{"BaseType"}{"Tid"}; 20157 my $BDid = $Info{"BaseType"}{"TDid"}; 20158 $BDid="" if(not defined $BDid); 20159 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"}); 20160 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) { 20161 $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID; 20162 } 20163 } 20164 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"}); 20165 } 20166 } 20167 read_Machine_DumpInfo($ABI, $LibVersion); 20168 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"}; 20169 if(not $SymbolInfo{$LibVersion}) 20170 { # support for old dumps 20171 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"}; 20172 } 20173 if(not keys(%{$SymbolInfo{$LibVersion}})) 20174 { # validation of old-version dumps 20175 if(not $ExtendedCheck) { 20176 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid"); 20177 } 20178 } 20179 if(checkDump($LibVersion, "2.15")) { 20180 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"}; 20181 } 20182 else 20183 { # support for old ABI dumps 20184 my $DepSymbols = $ABI->{"DepSymbols"}; 20185 if(not $DepSymbols) { 20186 $DepSymbols = $ABI->{"DepInterfaces"}; 20187 } 20188 if(not $DepSymbols) 20189 { # Cannot reconstruct DepSymbols. This may result in false 20190 # positives if the old dump is for library 2. Not a problem if 20191 # old dumps are only from old libraries. 20192 $DepSymbols = {}; 20193 } 20194 foreach my $Symbol (keys(%{$DepSymbols})) { 20195 $DepSymbol_Library{$LibVersion}{$Symbol} = 1; 20196 } 20197 } 20198 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"}; 20199 20200 if(my $V = $TargetVersion{$LibVersion}) { 20201 $Descriptor{$LibVersion}{"Version"} = $V; 20202 } 20203 else { 20204 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"}; 20205 } 20206 20207 if(not $SkipTypes{$LibVersion}) 20208 { # if not defined by -skip-types option 20209 if(defined $ABI->{"SkipTypes"}) 20210 { 20211 foreach my $TName (keys(%{$ABI->{"SkipTypes"}})) 20212 { 20213 $SkipTypes{$LibVersion}{$TName} = 1; 20214 } 20215 } 20216 if(defined $ABI->{"OpaqueTypes"}) 20217 { # support for old dumps 20218 foreach my $TName (keys(%{$ABI->{"OpaqueTypes"}})) 20219 { 20220 $SkipTypes{$LibVersion}{$TName} = 1; 20221 } 20222 } 20223 } 20224 20225 if(not $SkipSymbols{$LibVersion}) 20226 { # if not defined by -skip-symbols option 20227 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; 20228 if(not $SkipSymbols{$LibVersion}) 20229 { # support for old dumps 20230 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"}; 20231 } 20232 if(not $SkipSymbols{$LibVersion}) 20233 { # support for old dumps 20234 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"}; 20235 } 20236 } 20237 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"}; 20238 20239 if(not $TargetHeaders{$LibVersion}) 20240 { # if not defined by -headers-list option 20241 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"}; 20242 } 20243 20244 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}})) 20245 { 20246 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path}; 20247 my ($CPath, $Type) = classifyPath($Path); 20248 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path}; 20249 } 20250 20251 read_Source_DumpInfo($ABI, $LibVersion); 20252 read_Libs_DumpInfo($ABI, $LibVersion); 20253 20254 if(not checkDump($LibVersion, "2.10.1") 20255 or not $TargetHeaders{$LibVersion}) 20256 { # support for old ABI dumps: added target headers 20257 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20258 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20259 } 20260 20261 if(not $ABI->{"PublicABI"}) 20262 { 20263 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20264 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20265 } 20266 } 20267 } 20268 $Constants{$LibVersion} = $ABI->{"Constants"}; 20269 if(defined $ABI->{"GccConstants"}) 20270 { # 3.0 20271 foreach my $Name (keys(%{$ABI->{"GccConstants"}})) { 20272 $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name}; 20273 } 20274 } 20275 20276 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"}; 20277 if(not $NestedNameSpaces{$LibVersion}) 20278 { # support for old dumps 20279 # Cannot reconstruct NameSpaces. This may affect design 20280 # of the compatibility report. 20281 $NestedNameSpaces{$LibVersion} = {}; 20282 } 20283 # target system type 20284 # needed to adopt HTML report 20285 if(not $DumpSystem) 20286 { # to use in createSymbolsList(...) 20287 $OStarget = $ABI->{"Target"}; 20288 } 20289 # recreate environment 20290 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}})) 20291 { 20292 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) 20293 { 20294 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20295 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1) 20296 { # data marked as -size in the dump 20297 $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}; 20298 } 20299 if($COMMON_LANGUAGE{$LibVersion} ne "C++") 20300 { 20301 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 20302 setLanguage($LibVersion, "C++"); 20303 } 20304 } 20305 } 20306 } 20307 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}})) 20308 { 20309 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) { 20310 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; 20311 } 20312 } 20313 20314 my @VFunc = (); 20315 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20316 { 20317 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20318 { 20319 if(not $Symbol_Library{$LibVersion}{$MnglName} 20320 and not $DepSymbol_Library{$LibVersion}{$MnglName}) { 20321 push(@VFunc, $MnglName); 20322 } 20323 } 20324 } 20325 translateSymbols(@VFunc, $LibVersion); 20326 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 20327 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 20328 20329 if(not checkDump($LibVersion, "3.0")) 20330 { # support for old ABI dumps 20331 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20332 { 20333 if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20334 { 20335 if(ref($BaseType) eq "HASH") { 20336 $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"}; 20337 } 20338 } 20339 } 20340 } 20341 20342 if(not checkDump($LibVersion, "3.2")) 20343 { # support for old ABI dumps 20344 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20345 { 20346 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) 20347 { 20348 foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) { 20349 $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset}); 20350 } 20351 } 20352 } 20353 20354 # repair target headers list 20355 delete($TargetHeaders{$LibVersion}); 20356 foreach (keys(%{$Registered_Headers{$LibVersion}})) { 20357 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20358 } 20359 foreach (keys(%{$Registered_Sources{$LibVersion}})) { 20360 $TargetHeaders{$LibVersion}{get_filename($_)} = 1; 20361 } 20362 20363 # non-target constants from anon enums 20364 foreach my $Name (keys(%{$Constants{$LibVersion}})) 20365 { 20366 if(not $ExtraDump 20367 and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion)) 20368 { 20369 delete($Constants{$LibVersion}{$Name}); 20370 } 20371 } 20372 } 20373 20374 if(not checkDump($LibVersion, "2.20")) 20375 { # support for old ABI dumps 20376 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20377 { 20378 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20379 20380 if($TType=~/Struct|Union|Enum|Typedef/) 20381 { # repair complex types first 20382 next; 20383 } 20384 20385 if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) 20386 { 20387 my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"}); 20388 if($BType=~/Struct|Union|Enum/i) 20389 { 20390 my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}; 20391 $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g; 20392 } 20393 } 20394 } 20395 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20396 { 20397 my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; 20398 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; 20399 if($TType=~/Struct|Union|Enum/) { 20400 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName; 20401 } 20402 } 20403 } 20404 20405 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) 20406 { # NOTE: order is important 20407 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}) 20408 { # support for old ABI dumps < 2.0 (ACC 1.22) 20409 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}})) 20410 { 20411 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId}) 20412 { 20413 if($Access ne "public") { 20414 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access; 20415 } 20416 } 20417 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {}; 20418 } 20419 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}); 20420 } 20421 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"}) 20422 { # support for old ABI dumps 20423 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup); 20424 } 20425 elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"}) 20426 { # DWARF ABI Dumps 20427 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source; 20428 } 20429 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) { 20430 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId; 20431 } 20432 20433 # support for old formatting of type names 20434 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = formatName($TypeInfo{$LibVersion}{$TypeId}{"Name"}, "T"); 20435 20436 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}}; 20437 if(defined $TInfo{"Base"}) 20438 { 20439 foreach my $SubId (keys(%{$TInfo{"Base"}})) 20440 { 20441 if($SubId eq $TypeId) 20442 { # Fix erroneus ABI dump 20443 delete($TypeInfo{$LibVersion}{$TypeId}{"Base"}{$SubId}); 20444 next; 20445 } 20446 20447 $Class_SubClasses{$LibVersion}{$SubId}{$TypeId} = 1; 20448 } 20449 } 20450 if($TInfo{"Type"} eq "MethodPtr") 20451 { 20452 if(defined $TInfo{"Param"}) 20453 { # support for old ABI dumps <= 1.17 20454 if(not defined $TInfo{"Param"}{"0"}) 20455 { 20456 my $Max = keys(%{$TInfo{"Param"}}); 20457 foreach my $Pos (1 .. $Max) { 20458 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos}; 20459 } 20460 delete($TInfo{"Param"}{$Max}); 20461 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo; 20462 } 20463 } 20464 } 20465 if($TInfo{"BaseType"} eq $TypeId) 20466 { # fix ABI dump 20467 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"}); 20468 } 20469 20470 if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"}) 20471 { 20472 if(my $BTid = $TInfo{"BaseType"}) 20473 { 20474 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"}; 20475 if(not $BName) 20476 { # broken type 20477 next; 20478 } 20479 if($TInfo{"Name"} eq $BName) 20480 { # typedef to "class Class" 20481 # should not be registered in TName_Tid 20482 next; 20483 } 20484 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) { 20485 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName; 20486 } 20487 } 20488 } 20489 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}}) 20490 { # classes: class (id1), typedef (artificial, id2 > id1) 20491 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId; 20492 } 20493 } 20494 20495 if(not checkDump($LibVersion, "2.15")) 20496 { # support for old ABI dumps 20497 my %Dups = (); 20498 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20499 { 20500 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20501 { 20502 if(not defined $TypeInfo{$LibVersion}{$ClassId}) 20503 { # remove template decls 20504 delete($SymbolInfo{$LibVersion}{$InfoId}); 20505 next; 20506 } 20507 } 20508 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; 20509 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) 20510 { # templates 20511 delete($SymbolInfo{$LibVersion}{$InfoId}); 20512 } 20513 } 20514 } 20515 20516 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) 20517 { 20518 if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"} 20519 and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"} 20520 and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) 20521 { # support for old ABI dumps (< 3.1) 20522 if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} 20523 or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") 20524 { # add "this" first parameter 20525 my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion); 20526 my %PInfo = ("name"=>"this", "type"=>"$ThisTid"); 20527 20528 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) 20529 { 20530 my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); 20531 foreach my $Pos (reverse(0 .. $#Pos)) { 20532 %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}}; 20533 } 20534 } 20535 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo; 20536 } 20537 } 20538 20539 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) 20540 { # ABI dumps have no mangled names for C-functions 20541 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; 20542 } 20543 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"}) 20544 { # support for old ABI dumps 20545 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup); 20546 } 20547 elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"}) 20548 { # DWARF ABI Dumps 20549 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source; 20550 } 20551 } 20552 20553 $Descriptor{$LibVersion}{"Dump"} = 1; 20554} 20555 20556sub read_Machine_DumpInfo($$) 20557{ 20558 my ($ABI, $LibVersion) = @_; 20559 if($ABI->{"Arch"}) { 20560 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"}; 20561 } 20562 if($ABI->{"WordSize"}) { 20563 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"}; 20564 } 20565 else 20566 { # support for old dumps 20567 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"}; 20568 } 20569 if(not $WORD_SIZE{$LibVersion}) 20570 { # support for old dumps (<1.23) 20571 if(my $Tid = getTypeIdByName("char*", $LibVersion)) 20572 { # size of char* 20573 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20574 } 20575 else 20576 { 20577 my $PSize = 0; 20578 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) 20579 { 20580 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer") 20581 { # any "pointer"-type 20582 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"}; 20583 last; 20584 } 20585 } 20586 if($PSize) 20587 { # a pointer type size 20588 $WORD_SIZE{$LibVersion} = $PSize; 20589 } 20590 else { 20591 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)"); 20592 } 20593 } 20594 } 20595 if($ABI->{"GccVersion"}) { 20596 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"}; 20597 } 20598} 20599 20600sub read_Libs_DumpInfo($$) 20601{ 20602 my ($ABI, $LibVersion) = @_; 20603 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"}; 20604 if(not $Library_Symbol{$LibVersion}) 20605 { # support for old dumps 20606 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"}; 20607 } 20608 if(keys(%{$Library_Symbol{$LibVersion}}) 20609 and not $DumpAPI) { 20610 $Descriptor{$LibVersion}{"Libs"} = "OK"; 20611 } 20612} 20613 20614sub read_Source_DumpInfo($$) 20615{ 20616 my ($ABI, $LibVersion) = @_; 20617 20618 if(keys(%{$ABI->{"Headers"}}) 20619 and not $DumpAPI) { 20620 $Descriptor{$LibVersion}{"Headers"} = "OK"; 20621 } 20622 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}})) 20623 { 20624 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity; 20625 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity}; 20626 } 20627 20628 if(keys(%{$ABI->{"Sources"}}) 20629 and not $DumpAPI) { 20630 $Descriptor{$LibVersion}{"Sources"} = "OK"; 20631 } 20632 foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}})) 20633 { 20634 $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name; 20635 $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name}; 20636 } 20637} 20638 20639sub find_libs($$$) 20640{ 20641 my ($Path, $Type, $MaxDepth) = @_; 20642 # FIXME: correct the search pattern 20643 return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1); 20644} 20645 20646sub createDescriptor($$) 20647{ 20648 my ($LibVersion, $Path) = @_; 20649 if(not $LibVersion or not $Path 20650 or not -e $Path) { 20651 return ""; 20652 } 20653 if(-d $Path) 20654 { # directory with headers files and shared objects 20655 return " 20656 <version> 20657 ".$TargetVersion{$LibVersion}." 20658 </version> 20659 20660 <headers> 20661 $Path 20662 </headers> 20663 20664 <libs> 20665 $Path 20666 </libs>"; 20667 } 20668 else 20669 { # files 20670 if($Path=~/\.(xml|desc)\Z/i) 20671 { # standard XML-descriptor 20672 return readFile($Path); 20673 } 20674 elsif(is_header($Path, 2, $LibVersion)) 20675 { # header file 20676 $CheckHeadersOnly = 1; 20677 20678 if($LibVersion==1) { 20679 $TargetVersion{$LibVersion} = "X"; 20680 } 20681 20682 if($LibVersion==2) { 20683 $TargetVersion{$LibVersion} = "Y"; 20684 } 20685 20686 return " 20687 <version> 20688 ".$TargetVersion{$LibVersion}." 20689 </version> 20690 20691 <headers> 20692 $Path 20693 </headers> 20694 20695 <libs> 20696 none 20697 </libs>"; 20698 } 20699 else 20700 { # standard XML-descriptor 20701 return readFile($Path); 20702 } 20703 } 20704} 20705 20706sub detect_lib_default_paths() 20707{ 20708 my %LPaths = (); 20709 if($OSgroup eq "bsd") 20710 { 20711 if(my $LdConfig = get_CmdPath("ldconfig")) 20712 { 20713 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`)) 20714 { 20715 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) 20716 { 20717 my $Name = "lib".$1; 20718 if(not defined $LPaths{$Name}) { 20719 $LPaths{$Name} = $2; 20720 } 20721 } 20722 } 20723 } 20724 else { 20725 printMsg("WARNING", "can't find ldconfig"); 20726 } 20727 } 20728 else 20729 { 20730 if(my $LdConfig = get_CmdPath("ldconfig")) 20731 { 20732 if($SystemRoot and $OSgroup eq "linux") 20733 { # use host (x86) ldconfig with the target (arm) ld.so.conf 20734 if(-e $SystemRoot."/etc/ld.so.conf") { 20735 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf"; 20736 } 20737 } 20738 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`)) 20739 { 20740 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/) 20741 { 20742 my ($Name, $Path) = ($1, $2); 20743 $Path=~s/[\/]{2,}/\//; 20744 if(not defined $LPaths{$Name}) 20745 { # get first element from the list of available paths 20746 20747 # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 20748 # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6 20749 # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6 20750 20751 $LPaths{$Name} = $Path; 20752 } 20753 } 20754 } 20755 } 20756 elsif($OSgroup eq "linux") { 20757 printMsg("WARNING", "can't find ldconfig"); 20758 } 20759 } 20760 return \%LPaths; 20761} 20762 20763sub detect_bin_default_paths() 20764{ 20765 my $EnvPaths = $ENV{"PATH"}; 20766 if($OSgroup eq "beos") { 20767 $EnvPaths.=":".$ENV{"BETOOLS"}; 20768 } 20769 my $Sep = ($OSgroup eq "windows")?";":":|;"; 20770 foreach my $Path (split(/$Sep/, $EnvPaths)) 20771 { 20772 $Path = path_format($Path, $OSgroup); 20773 next if(not $Path); 20774 if($SystemRoot 20775 and $Path=~/\A\Q$SystemRoot\E\//) 20776 { # do NOT use binaries from target system 20777 next; 20778 } 20779 push_U(\@DefaultBinPaths, $Path); 20780 } 20781} 20782 20783sub detect_inc_default_paths() 20784{ 20785 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]); 20786 writeFile("$TMP_DIR/empty.h", ""); 20787 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`)) 20788 { # detecting GCC default include paths 20789 next if(index($Line, "/cc1plus ")!=-1); 20790 20791 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) 20792 { 20793 my $Path = realpath($1); 20794 $Path = path_format($Path, $OSgroup); 20795 if(index($Path, "c++")!=-1 20796 or index($Path, "/g++/")!=-1) 20797 { 20798 push_U($DPaths{"Cpp"}, $Path); 20799 if(not defined $MAIN_CPP_DIR 20800 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) { 20801 $MAIN_CPP_DIR = $Path; 20802 } 20803 } 20804 elsif(index($Path, "gcc")!=-1) { 20805 push_U($DPaths{"Gcc"}, $Path); 20806 } 20807 else 20808 { 20809 if($Path=~/local[\/\\]+include/) 20810 { # local paths 20811 next; 20812 } 20813 if($SystemRoot 20814 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/) 20815 { # The GCC include path for user headers is not a part of the system root 20816 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler 20817 # or it is the internal cross-GCC path like arm-linux-gnueabi/include 20818 next; 20819 } 20820 push_U($DPaths{"Inc"}, $Path); 20821 } 20822 } 20823 } 20824 unlink("$TMP_DIR/empty.h"); 20825 return %DPaths; 20826} 20827 20828sub detect_default_paths($) 20829{ 20830 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1); 20831 my $Search = $_[0]; 20832 if($Search!~/inc/) { 20833 $HSearch = 0; 20834 } 20835 if($Search!~/lib/) { 20836 $LSearch = 0; 20837 } 20838 if($Search!~/bin/) { 20839 $BSearch = 0; 20840 } 20841 if($Search!~/gcc/) { 20842 $GSearch = 0; 20843 } 20844 if(@{$SystemPaths{"include"}}) 20845 { # <search_headers> section of the XML descriptor 20846 # do NOT search for systems headers 20847 $HSearch = 0; 20848 } 20849 if(@{$SystemPaths{"lib"}}) 20850 { # <search_libs> section of the XML descriptor 20851 # do NOT search for systems libraries 20852 $LSearch = 0; 20853 } 20854 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}})) 20855 { # additional search paths 20856 next if($Type eq "include" and not $HSearch); 20857 next if($Type eq "lib" and not $LSearch); 20858 next if($Type eq "bin" and not $BSearch); 20859 push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}}); 20860 } 20861 if($OSgroup ne "windows") 20862 { # unix-like 20863 foreach my $Type ("include", "lib", "bin") 20864 { # automatic detection of system "devel" directories 20865 next if($Type eq "include" and not $HSearch); 20866 next if($Type eq "lib" and not $LSearch); 20867 next if($Type eq "bin" and not $BSearch); 20868 my ($UsrDir, $RootDir) = ("/usr", "/"); 20869 if($SystemRoot and $Type ne "bin") 20870 { # 1. search for target headers and libraries 20871 # 2. use host commands: ldconfig, readelf, etc. 20872 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot); 20873 } 20874 push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1)); 20875 if(-d $RootDir."/".$Type) 20876 { # if "/lib" is symbolic link 20877 if($RootDir eq "/") { 20878 push_U($SystemPaths{$Type}, "/".$Type); 20879 } 20880 else { 20881 push_U($SystemPaths{$Type}, $RootDir."/".$Type); 20882 } 20883 } 20884 if(-d $UsrDir) 20885 { 20886 push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1)); 20887 if(-d $UsrDir."/".$Type) 20888 { # if "/usr/lib" is symbolic link 20889 push_U($SystemPaths{$Type}, $UsrDir."/".$Type); 20890 } 20891 } 20892 } 20893 } 20894 if($BSearch) 20895 { 20896 detect_bin_default_paths(); 20897 push_U($SystemPaths{"bin"}, @DefaultBinPaths); 20898 } 20899 # check environment variables 20900 if($OSgroup eq "beos") 20901 { 20902 foreach (my @Paths = @{$SystemPaths{"bin"}}) 20903 { 20904 if($_ eq ".") { 20905 next; 20906 } 20907 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/ 20908 if(my @Dirs = sort cmd_find($_, "d", "bin")) { 20909 push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs); 20910 } 20911 } 20912 if($HSearch) 20913 { 20914 push_U(\@DefaultIncPaths, grep { is_abs($_) } ( 20915 split(/:|;/, $ENV{"BEINCLUDES"}) 20916 )); 20917 } 20918 if($LSearch) 20919 { 20920 push_U(\@DefaultLibPaths, grep { is_abs($_) } ( 20921 split(/:|;/, $ENV{"BELIBRARIES"}), 20922 split(/:|;/, $ENV{"LIBRARY_PATH"}) 20923 )); 20924 } 20925 } 20926 if($LSearch) 20927 { # using linker to get system paths 20928 if(my $LPaths = detect_lib_default_paths()) 20929 { # unix-like 20930 my %Dirs = (); 20931 foreach my $Name (keys(%{$LPaths})) 20932 { 20933 if($SystemRoot 20934 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//) 20935 { # wrong ldconfig configuration 20936 # check your <sysroot>/etc/ld.so.conf 20937 next; 20938 } 20939 $DyLib_DefaultPath{$Name} = $LPaths->{$Name}; 20940 if(my $Dir = get_dirname($LPaths->{$Name})) { 20941 $Dirs{$Dir} = 1; 20942 } 20943 } 20944 push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs)); 20945 } 20946 push_U($SystemPaths{"lib"}, @DefaultLibPaths); 20947 } 20948 if($BSearch) 20949 { 20950 if($CrossGcc) 20951 { # --cross-gcc=arm-linux-gcc 20952 if(-e $CrossGcc) 20953 { # absolute or relative path 20954 $GCC_PATH = get_abs_path($CrossGcc); 20955 } 20956 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc)) 20957 { # command name 20958 $GCC_PATH = $CrossGcc; 20959 } 20960 else { 20961 exitStatus("Access_Error", "can't access \'$CrossGcc\'"); 20962 } 20963 if($GCC_PATH=~/\s/) { 20964 $GCC_PATH = "\"".$GCC_PATH."\""; 20965 } 20966 } 20967 } 20968 if($GSearch) 20969 { # GCC path and default include dirs 20970 if(not $CrossGcc) 20971 { # try default gcc 20972 $GCC_PATH = get_CmdPath("gcc"); 20973 } 20974 if(not $GCC_PATH) 20975 { # try to find gcc-X.Y 20976 foreach my $Path (@{$SystemPaths{"bin"}}) 20977 { 20978 if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1)) 20979 { # select the latest version 20980 @GCCs = sort {$b cmp $a} @GCCs; 20981 if(check_gcc($GCCs[0], "3")) 20982 { 20983 $GCC_PATH = $GCCs[0]; 20984 last; 20985 } 20986 } 20987 } 20988 } 20989 if(not $GCC_PATH) { 20990 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); 20991 } 20992 20993 my $GCC_Ver = get_dumpversion($GCC_PATH); 20994 if($GCC_Ver eq "4.8") 20995 { # on Ubuntu -dumpversion returns 4.8 for gcc 4.8.4 20996 my $Info = `$GCC_PATH --version`; 20997 20998 if($Info=~/gcc\s+(|\([^()]+\)\s+)(\d+\.\d+\.\d+)/) 20999 { # gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 21000 # gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6) 21001 $GCC_Ver = $2; 21002 } 21003 } 21004 21005 if($GCC_Ver) 21006 { 21007 my $GccTarget = get_dumpmachine($GCC_PATH); 21008 21009 if($GccTarget=~/linux/) 21010 { 21011 $OStarget = "linux"; 21012 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; 21013 } 21014 elsif($GccTarget=~/symbian/) 21015 { 21016 $OStarget = "symbian"; 21017 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; 21018 } 21019 21020 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget, target: ".getArch_GCC(1).")"); 21021 21022 # check GCC version 21023 if($GCC_Ver=~/\A4\.8(|\.[012])\Z/) 21024 { # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 21025 # introduced in 4.8 and fixed in 4.8.3 21026 printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update GCC to 4.8.3 or downgrade it to 4.7. You can use a local GCC installation by --gcc-path=PATH option."); 21027 21028 $EMERGENCY_MODE_48 = 1; 21029 } 21030 } 21031 else { 21032 exitStatus("Error", "something is going wrong with the GCC compiler"); 21033 } 21034 } 21035 if($HSearch) 21036 { 21037 # GCC standard paths 21038 if($GCC_PATH and not $NoStdInc) 21039 { 21040 my %DPaths = detect_inc_default_paths(); 21041 @DefaultCppPaths = @{$DPaths{"Cpp"}}; 21042 @DefaultGccPaths = @{$DPaths{"Gcc"}}; 21043 @DefaultIncPaths = @{$DPaths{"Inc"}}; 21044 push_U($SystemPaths{"include"}, @DefaultIncPaths); 21045 } 21046 21047 # users include paths 21048 my $IncPath = "/usr/include"; 21049 if($SystemRoot) { 21050 $IncPath = $SystemRoot.$IncPath; 21051 } 21052 if(-d $IncPath) { 21053 push_U(\@UsersIncPath, $IncPath); 21054 } 21055 } 21056 21057 if($ExtraInfo) 21058 { 21059 writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths)); 21060 writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths))); 21061 } 21062} 21063 21064sub getLIB_EXT($) 21065{ 21066 my $Target = $_[0]; 21067 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) { 21068 return $Ext; 21069 } 21070 return $OS_LibExt{$LIB_TYPE}{"default"}; 21071} 21072 21073sub getAR_EXT($) 21074{ 21075 my $Target = $_[0]; 21076 if(my $Ext = $OS_Archive{$Target}) { 21077 return $Ext; 21078 } 21079 return $OS_Archive{"default"}; 21080} 21081 21082sub get_dumpversion($) 21083{ 21084 my $Cmd = $_[0]; 21085 return "" if(not $Cmd); 21086 if($Cache{"get_dumpversion"}{$Cmd}) { 21087 return $Cache{"get_dumpversion"}{$Cmd}; 21088 } 21089 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`; 21090 chomp($V); 21091 return ($Cache{"get_dumpversion"}{$Cmd} = $V); 21092} 21093 21094sub get_dumpmachine($) 21095{ 21096 my $Cmd = $_[0]; 21097 return "" if(not $Cmd); 21098 if($Cache{"get_dumpmachine"}{$Cmd}) { 21099 return $Cache{"get_dumpmachine"}{$Cmd}; 21100 } 21101 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`; 21102 chomp($Machine); 21103 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine); 21104} 21105 21106sub checkCmd($) 21107{ 21108 my $Cmd = $_[0]; 21109 return "" if(not $Cmd); 21110 my @Options = ( 21111 "--version", 21112 "-help" 21113 ); 21114 foreach my $Opt (@Options) 21115 { 21116 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`; 21117 if($Info) { 21118 return 1; 21119 } 21120 } 21121 return 0; 21122} 21123 21124sub check_gcc($$) 21125{ 21126 my ($Cmd, $ReqVer) = @_; 21127 return 0 if(not $Cmd or not $ReqVer); 21128 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) { 21129 return $Cache{"check_gcc"}{$Cmd}{$ReqVer}; 21130 } 21131 if(my $GccVer = get_dumpversion($Cmd)) 21132 { 21133 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818") 21134 if(cmpVersions($GccVer, $ReqVer)>=0) { 21135 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd); 21136 } 21137 } 21138 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = ""); 21139} 21140 21141sub get_depth($) 21142{ 21143 if(defined $Cache{"get_depth"}{$_[0]}) { 21144 return $Cache{"get_depth"}{$_[0]}; 21145 } 21146 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!)); 21147} 21148 21149sub registerGccHeaders() 21150{ 21151 return if($Cache{"registerGccHeaders"}); # this function should be called once 21152 21153 foreach my $Path (@DefaultGccPaths) 21154 { 21155 my @Headers = cmd_find($Path,"f"); 21156 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 21157 foreach my $HPath (@Headers) 21158 { 21159 my $FileName = get_filename($HPath); 21160 if(not defined $DefaultGccHeader{$FileName}) 21161 { # skip duplicated 21162 $DefaultGccHeader{$FileName} = $HPath; 21163 } 21164 } 21165 } 21166 $Cache{"registerGccHeaders"} = 1; 21167} 21168 21169sub registerCppHeaders() 21170{ 21171 return if($Cache{"registerCppHeaders"}); # this function should be called once 21172 21173 foreach my $CppDir (@DefaultCppPaths) 21174 { 21175 my @Headers = cmd_find($CppDir,"f"); 21176 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; 21177 foreach my $Path (@Headers) 21178 { 21179 my $FileName = get_filename($Path); 21180 if(not defined $DefaultCppHeader{$FileName}) 21181 { # skip duplicated 21182 $DefaultCppHeader{$FileName} = $Path; 21183 } 21184 } 21185 } 21186 $Cache{"registerCppHeaders"} = 1; 21187} 21188 21189sub parse_libname($$$) 21190{ 21191 return "" if(not $_[0]); 21192 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) { 21193 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}; 21194 } 21195 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_)); 21196} 21197 21198sub parse_libname_I($$$) 21199{ 21200 my ($Name, $Type, $Target) = @_; 21201 21202 if($Target eq "symbian") { 21203 return parse_libname_symbian($Name, $Type); 21204 } 21205 elsif($Target eq "windows") { 21206 return parse_libname_windows($Name, $Type); 21207 } 21208 21209 # unix 21210 my $Ext = getLIB_EXT($Target); 21211 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/) 21212 { # libSDL-1.2.so.0.7.1 21213 # libwbxml2.so.0.0.18 21214 # libopcodes-2.21.53-system.20110810.so 21215 if($Type eq "name") 21216 { # libSDL-1.2 21217 # libwbxml2 21218 return $2; 21219 } 21220 elsif($Type eq "name+ext") 21221 { # libSDL-1.2.so 21222 # libwbxml2.so 21223 return $1; 21224 } 21225 elsif($Type eq "version") 21226 { 21227 if(defined $7 21228 and $7 ne "") 21229 { # 0.7.1 21230 return $7; 21231 } 21232 else 21233 { # libc-2.5.so (=>2.5 version) 21234 my $MV = $5; 21235 $MV=~s/\A[\-\_]+//g; 21236 return $MV; 21237 } 21238 } 21239 elsif($Type eq "short") 21240 { # libSDL 21241 # libwbxml2 21242 return $3; 21243 } 21244 elsif($Type eq "shortest") 21245 { # SDL 21246 # wbxml 21247 return shortest_name($3); 21248 } 21249 } 21250 return "";# error 21251} 21252 21253sub parse_libname_symbian($$) 21254{ 21255 my ($Name, $Type) = @_; 21256 my $Ext = getLIB_EXT("symbian"); 21257 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/) 21258 { # libpthread{00010001}.dso 21259 if($Type eq "name") 21260 { # libpthread{00010001} 21261 return $2; 21262 } 21263 elsif($Type eq "name+ext") 21264 { # libpthread{00010001}.dso 21265 return $1; 21266 } 21267 elsif($Type eq "version") 21268 { # 00010001 21269 my $V = $4; 21270 $V=~s/\{(.+)\}/$1/; 21271 return $V; 21272 } 21273 elsif($Type eq "short") 21274 { # libpthread 21275 return $3; 21276 } 21277 elsif($Type eq "shortest") 21278 { # pthread 21279 return shortest_name($3); 21280 } 21281 } 21282 return "";# error 21283} 21284 21285sub parse_libname_windows($$) 21286{ 21287 my ($Name, $Type) = @_; 21288 my $Ext = getLIB_EXT("windows"); 21289 if($Name=~/((.+?)\.$Ext)\Z/) 21290 { # netapi32.dll 21291 if($Type eq "name") 21292 { # netapi32 21293 return $2; 21294 } 21295 elsif($Type eq "name+ext") 21296 { # netapi32.dll 21297 return $1; 21298 } 21299 elsif($Type eq "version") 21300 { # DLL version embedded 21301 # at binary-level 21302 return ""; 21303 } 21304 elsif($Type eq "short") 21305 { # netapi32 21306 return $2; 21307 } 21308 elsif($Type eq "shortest") 21309 { # netapi 21310 return shortest_name($2); 21311 } 21312 } 21313 return "";# error 21314} 21315 21316sub shortest_name($) 21317{ 21318 my $Name = $_[0]; 21319 # remove prefix 21320 $Name=~s/\A(lib|open)//; 21321 # remove suffix 21322 $Name=~s/[\W\d_]+\Z//i; 21323 $Name=~s/([a-z]{2,})(lib)\Z/$1/i; 21324 return $Name; 21325} 21326 21327sub createSymbolsList($$$$$) 21328{ 21329 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_; 21330 21331 read_ABI_Dump(1, $DPath); 21332 prepareSymbols(1); 21333 21334 my %SymbolHeaderLib = (); 21335 my $Total = 0; 21336 21337 # Get List 21338 foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) 21339 { 21340 if(not link_symbol($Symbol, 1, "-Deps")) 21341 { # skip src only and all external functions 21342 next; 21343 } 21344 if(not symbolFilter($Symbol, 1, "Public", "Binary")) 21345 { # skip other symbols 21346 next; 21347 } 21348 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; 21349 if(not $HeaderName) 21350 { # skip src only and all external functions 21351 next; 21352 } 21353 my $DyLib = $Symbol_Library{1}{$Symbol}; 21354 if(not $DyLib) 21355 { # skip src only and all external functions 21356 next; 21357 } 21358 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1; 21359 $Total+=1; 21360 } 21361 # Draw List 21362 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)"; 21363 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>"; 21364 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib)) 21365 { 21366 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}})) 21367 { 21368 my %NS_Symbol = (); 21369 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) { 21370 $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; 21371 } 21372 foreach my $NameSpace (sort keys(%NS_Symbol)) 21373 { 21374 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace); 21375 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}}); 21376 foreach my $Symbol (@SortedInterfaces) 21377 { 21378 my $SubReport = ""; 21379 my $Signature = get_Signature($Symbol, 1); 21380 if($NameSpace) { 21381 $Signature=~s/\b\Q$NameSpace\E::\b//g; 21382 } 21383 if($Symbol=~/\A(_Z|\?)/) 21384 { 21385 if($Signature) { 21386 $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n"); 21387 } 21388 else { 21389 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21390 } 21391 } 21392 else 21393 { 21394 if($Signature) { 21395 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n"; 21396 } 21397 else { 21398 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n"; 21399 } 21400 } 21401 $SYMBOLS_LIST .= $SubReport; 21402 } 21403 } 21404 $SYMBOLS_LIST .= "<br/>\n"; 21405 } 21406 } 21407 # clear info 21408 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library, 21409 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols, 21410 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames, 21411 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = (); 21412 ($Content_Counter, $ContentID) = (0, 0); 21413 # print report 21414 my $CssStyles = readModule("Styles", "SymbolsList.css"); 21415 my $JScripts = readModule("Scripts", "Sections.js"); 21416 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n"; 21417 my $Title = "$LName: public symbols"; 21418 my $Keywords = "$LName, API, symbols"; 21419 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName); 21420 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)." 21421 <body><div>\n$SYMBOLS_LIST</div> 21422 <br/><br/>\n".getReportFooter()." 21423 </body></html>"; 21424 writeFile($SaveTo, $SYMBOLS_LIST); 21425} 21426 21427sub add_target_libs($) 21428{ 21429 foreach (@{$_[0]}) { 21430 $TargetLibs{$_} = 1; 21431 } 21432} 21433 21434sub is_target_lib($) 21435{ 21436 my $LName = $_[0]; 21437 if(not $LName) { 21438 return 0; 21439 } 21440 if($TargetLibraryName 21441 and $LName!~/\Q$TargetLibraryName\E/) { 21442 return 0; 21443 } 21444 if(keys(%TargetLibs) 21445 and not $TargetLibs{$LName} 21446 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) { 21447 return 0; 21448 } 21449 return 1; 21450} 21451 21452sub is_target_header($$) 21453{ # --header, --headers-list 21454 my ($H, $V) = @_; 21455 if(keys(%{$TargetHeaders{$V}})) 21456 { 21457 if($TargetHeaders{$V}{$H}) { 21458 return 1; 21459 } 21460 } 21461 return 0; 21462} 21463 21464sub readLibs($) 21465{ 21466 my $LibVersion = $_[0]; 21467 if($OStarget eq "windows") 21468 { # dumpbin.exe will crash 21469 # without VS Environment 21470 check_win32_env(); 21471 } 21472 readSymbols($LibVersion); 21473 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); 21474 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); 21475} 21476 21477sub dump_sorting($) 21478{ 21479 my $Hash = $_[0]; 21480 return [] if(not $Hash); 21481 my @Keys = keys(%{$Hash}); 21482 return [] if($#Keys<0); 21483 if($Keys[0]=~/\A\d+\Z/) 21484 { # numbers 21485 return [sort {int($a)<=>int($b)} @Keys]; 21486 } 21487 else 21488 { # strings 21489 return [sort {$a cmp $b} @Keys]; 21490 } 21491} 21492 21493sub printMsg($$) 21494{ 21495 my ($Type, $Msg) = @_; 21496 if($Type!~/\AINFO/) { 21497 $Msg = $Type.": ".$Msg; 21498 } 21499 if($Type!~/_C\Z/) { 21500 $Msg .= "\n"; 21501 } 21502 if($Quiet) 21503 { # --quiet option 21504 appendFile($COMMON_LOG_PATH, $Msg); 21505 } 21506 else 21507 { 21508 if($Type eq "ERROR") { 21509 print STDERR $Msg; 21510 } 21511 else { 21512 print $Msg; 21513 } 21514 } 21515} 21516 21517sub exitStatus($$) 21518{ 21519 my ($Code, $Msg) = @_; 21520 printMsg("ERROR", $Msg); 21521 exit($ERROR_CODE{$Code}); 21522} 21523 21524sub exitReport() 21525{ # the tool has run without any errors 21526 printReport(); 21527 if($COMPILE_ERRORS) 21528 { # errors in headers may add false positives/negatives 21529 exit($ERROR_CODE{"Compile_Error"}); 21530 } 21531 if($BinaryOnly and $RESULT{"Binary"}{"Problems"}) 21532 { # --binary 21533 exit($ERROR_CODE{"Incompatible"}); 21534 } 21535 elsif($SourceOnly and $RESULT{"Source"}{"Problems"}) 21536 { # --source 21537 exit($ERROR_CODE{"Incompatible"}); 21538 } 21539 elsif($RESULT{"Source"}{"Problems"} 21540 or $RESULT{"Binary"}{"Problems"}) 21541 { # default 21542 exit($ERROR_CODE{"Incompatible"}); 21543 } 21544 else { 21545 exit($ERROR_CODE{"Compatible"}); 21546 } 21547} 21548 21549sub readRules($) 21550{ 21551 my $Kind = $_[0]; 21552 if(not -f $RULES_PATH{$Kind}) { 21553 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'"); 21554 } 21555 my $Content = readFile($RULES_PATH{$Kind}); 21556 while(my $Rule = parseTag(\$Content, "rule")) 21557 { 21558 my $RId = parseTag(\$Rule, "id"); 21559 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind"); 21560 foreach my $Prop (@Properties) { 21561 if(my $Value = parseTag(\$Rule, lc($Prop))) 21562 { 21563 $Value=~s/\n[ ]*//; 21564 $CompatRules{$Kind}{$RId}{$Prop} = $Value; 21565 } 21566 } 21567 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) { 21568 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols"; 21569 } 21570 else { 21571 $CompatRules{$Kind}{$RId}{"Kind"} = "Types"; 21572 } 21573 } 21574} 21575 21576sub getReportPath($) 21577{ 21578 my $Level = $_[0]; 21579 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"}; 21580 if($Level eq "Binary") 21581 { 21582 if($BinaryReportPath) 21583 { # --bin-report-path 21584 return $BinaryReportPath; 21585 } 21586 elsif($OutputReportPath) 21587 { # --report-path 21588 return $OutputReportPath; 21589 } 21590 else 21591 { # default 21592 return $Dir."/abi_compat_report.$ReportFormat"; 21593 } 21594 } 21595 elsif($Level eq "Source") 21596 { 21597 if($SourceReportPath) 21598 { # --src-report-path 21599 return $SourceReportPath; 21600 } 21601 elsif($OutputReportPath) 21602 { # --report-path 21603 return $OutputReportPath; 21604 } 21605 else 21606 { # default 21607 return $Dir."/src_compat_report.$ReportFormat"; 21608 } 21609 } 21610 else 21611 { 21612 if($OutputReportPath) 21613 { # --report-path 21614 return $OutputReportPath; 21615 } 21616 else 21617 { # default 21618 return $Dir."/compat_report.$ReportFormat"; 21619 } 21620 } 21621} 21622 21623sub printStatMsg($) 21624{ 21625 my $Level = $_[0]; 21626 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"}); 21627} 21628 21629sub listAffected($) 21630{ 21631 my $Level = $_[0]; 21632 my $List = ""; 21633 foreach (keys(%{$TotalAffected{$Level}})) 21634 { 21635 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low") 21636 { # skip "Low"-severity problems 21637 next; 21638 } 21639 $List .= "$_\n"; 21640 } 21641 my $Dir = get_dirname(getReportPath($Level)); 21642 if($Level eq "Binary") { 21643 writeFile($Dir."/abi_affected.txt", $List); 21644 } 21645 elsif($Level eq "Source") { 21646 writeFile($Dir."/src_affected.txt", $List); 21647 } 21648} 21649 21650sub printReport() 21651{ 21652 printMsg("INFO", "creating compatibility report ..."); 21653 createReport(); 21654 if($JoinReport or $DoubleReport) 21655 { 21656 if($RESULT{"Binary"}{"Problems"} 21657 or $RESULT{"Source"}{"Problems"}) { 21658 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)"); 21659 } 21660 else { 21661 printMsg("INFO", "result: COMPATIBLE"); 21662 } 21663 printStatMsg("Binary"); 21664 printStatMsg("Source"); 21665 if($ListAffected) 21666 { # --list-affected 21667 listAffected("Binary"); 21668 listAffected("Source"); 21669 } 21670 } 21671 elsif($BinaryOnly) 21672 { 21673 if($RESULT{"Binary"}{"Problems"}) { 21674 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)"); 21675 } 21676 else { 21677 printMsg("INFO", "result: COMPATIBLE"); 21678 } 21679 printStatMsg("Binary"); 21680 if($ListAffected) 21681 { # --list-affected 21682 listAffected("Binary"); 21683 } 21684 } 21685 elsif($SourceOnly) 21686 { 21687 if($RESULT{"Source"}{"Problems"}) { 21688 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)"); 21689 } 21690 else { 21691 printMsg("INFO", "result: COMPATIBLE"); 21692 } 21693 printStatMsg("Source"); 21694 if($ListAffected) 21695 { # --list-affected 21696 listAffected("Source"); 21697 } 21698 } 21699 if($StdOut) 21700 { 21701 if($JoinReport or not $DoubleReport) 21702 { # --binary or --source 21703 printMsg("INFO", "compatibility report has been generated to stdout"); 21704 } 21705 else 21706 { # default 21707 printMsg("INFO", "compatibility reports have been generated to stdout"); 21708 } 21709 } 21710 else 21711 { 21712 if($JoinReport) 21713 { 21714 printMsg("INFO", "see detailed report:\n ".getReportPath("Join")); 21715 } 21716 elsif($DoubleReport) 21717 { # default 21718 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source")); 21719 } 21720 elsif($BinaryOnly) 21721 { # --binary 21722 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary")); 21723 } 21724 elsif($SourceOnly) 21725 { # --source 21726 printMsg("INFO", "see detailed report:\n ".getReportPath("Source")); 21727 } 21728 } 21729} 21730 21731sub check_win32_env() 21732{ 21733 if(not $ENV{"DevEnvDir"} 21734 or not $ENV{"LIB"}) { 21735 exitStatus("Error", "can't start without VS environment (vsvars32.bat)"); 21736 } 21737} 21738 21739sub diffSets($$) 21740{ 21741 my ($S1, $S2) = @_; 21742 my @SK1 = keys(%{$S1}); 21743 my @SK2 = keys(%{$S2}); 21744 if($#SK1!=$#SK2) { 21745 return 1; 21746 } 21747 foreach my $K1 (@SK1) 21748 { 21749 if(not defined $S2->{$K1}) { 21750 return 1; 21751 } 21752 } 21753 return 0; 21754} 21755 21756sub defaultDumpPath($$) 21757{ 21758 my ($N, $V) = @_; 21759 return "abi_dumps/".$N."/".$N."_".$V.".abi.".$AR_EXT; # gzipped by default 21760} 21761 21762sub create_ABI_Dump() 21763{ 21764 if(not -e $DumpAPI) { 21765 exitStatus("Access_Error", "can't access \'$DumpAPI\'"); 21766 } 21767 21768 if(isDump($DumpAPI)) { 21769 read_ABI_Dump(1, $DumpAPI); 21770 } 21771 else { 21772 readDescriptor(1, createDescriptor(1, $DumpAPI)); 21773 } 21774 21775 if(not $Descriptor{1}{"Version"}) 21776 { # set to default: N 21777 $Descriptor{1}{"Version"} = "N"; 21778 } 21779 21780 initLogging(1); 21781 detect_default_paths("inc|lib|bin|gcc"); # complete analysis 21782 21783 my $DumpPath = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 21784 if($OutputDumpPath) 21785 { # user defined path 21786 $DumpPath = $OutputDumpPath; 21787 } 21788 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g); 21789 21790 if(not $Archive and not $StdOut) 21791 { # check archive utilities 21792 if($OSgroup eq "windows") 21793 { # using zip 21794 my $ZipCmd = get_CmdPath("zip"); 21795 if(not $ZipCmd) { 21796 exitStatus("Not_Found", "can't find \"zip\""); 21797 } 21798 } 21799 else 21800 { # using tar and gzip 21801 my $TarCmd = get_CmdPath("tar"); 21802 if(not $TarCmd) { 21803 exitStatus("Not_Found", "can't find \"tar\""); 21804 } 21805 my $GzipCmd = get_CmdPath("gzip"); 21806 if(not $GzipCmd) { 21807 exitStatus("Not_Found", "can't find \"gzip\""); 21808 } 21809 } 21810 } 21811 21812 if(not $Descriptor{1}{"Dump"}) 21813 { 21814 if(not $CheckHeadersOnly) { 21815 readLibs(1); 21816 } 21817 if($CheckHeadersOnly) { 21818 setLanguage(1, "C++"); 21819 } 21820 searchForHeaders(1); 21821 $WORD_SIZE{1} = detectWordSize(1); 21822 } 21823 if(not $Descriptor{1}{"Dump"}) 21824 { 21825 if($Descriptor{1}{"Headers"}) { 21826 readHeaders(1); 21827 } 21828 } 21829 cleanDump(1); 21830 if(not keys(%{$SymbolInfo{1}})) 21831 { # check if created dump is valid 21832 if(not $ExtendedCheck) 21833 { 21834 if($CheckHeadersOnly) { 21835 exitStatus("Empty_Set", "the set of public symbols is empty"); 21836 } 21837 else { 21838 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection"); 21839 } 21840 } 21841 } 21842 my %HeadersInfo = (); 21843 foreach my $HPath (keys(%{$Registered_Headers{1}})) { 21844 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"}; 21845 } 21846 if($ExtraDump) 21847 { # add unmangled names to the ABI dump 21848 my @Names = (); 21849 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 21850 { 21851 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) { 21852 push(@Names, $MnglName); 21853 } 21854 } 21855 translateSymbols(@Names, 1); 21856 foreach my $InfoId (keys(%{$SymbolInfo{1}})) 21857 { 21858 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) 21859 { 21860 if(my $Unmangled = $tr_name{$MnglName}) 21861 { 21862 if($MnglName ne $Unmangled) { 21863 $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled; 21864 } 21865 } 21866 } 21867 } 21868 } 21869 21870 my %GccConstants = (); # built-in GCC constants 21871 foreach my $Name (keys(%{$Constants{1}})) 21872 { 21873 if(not defined $Constants{1}{$Name}{"Header"}) 21874 { 21875 $GccConstants{$Name} = $Constants{1}{$Name}{"Value"}; 21876 delete($Constants{1}{$Name}); 21877 } 21878 } 21879 21880 printMsg("INFO", "creating library ABI dump ..."); 21881 my %ABI = ( 21882 "TypeInfo" => $TypeInfo{1}, 21883 "SymbolInfo" => $SymbolInfo{1}, 21884 "Symbols" => $Library_Symbol{1}, 21885 "DepSymbols" => $DepLibrary_Symbol{1}, 21886 "SymbolVersion" => $SymVer{1}, 21887 "LibraryVersion" => $Descriptor{1}{"Version"}, 21888 "LibraryName" => $TargetLibraryName, 21889 "Language" => $COMMON_LANGUAGE{1}, 21890 "SkipTypes" => $SkipTypes{1}, 21891 "SkipSymbols" => $SkipSymbols{1}, 21892 "SkipNameSpaces" => $SkipNameSpaces{1}, 21893 "SkipHeaders" => $SkipHeadersList{1}, 21894 "Headers" => \%HeadersInfo, 21895 "Constants" => $Constants{1}, 21896 "GccConstants" => \%GccConstants, 21897 "NameSpaces" => $NestedNameSpaces{1}, 21898 "Target" => $OStarget, 21899 "Arch" => getArch(1), 21900 "WordSize" => $WORD_SIZE{1}, 21901 "GccVersion" => get_dumpversion($GCC_PATH), 21902 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION, 21903 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION 21904 ); 21905 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) { 21906 $ABI{"TargetHeaders"} = $TargetHeaders{1}; 21907 } 21908 if($UseXML) { 21909 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION; 21910 } 21911 if($ExtendedCheck) 21912 { # --ext option 21913 $ABI{"Mode"} = "Extended"; 21914 } 21915 if($BinaryOnly) 21916 { # --binary 21917 $ABI{"BinOnly"} = 1; 21918 } 21919 if($ExtraDump) 21920 { # --extra-dump 21921 $ABI{"Extra"} = 1; 21922 $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1}; 21923 $ABI{"Needed"} = $Library_Needed{1}; 21924 } 21925 21926 my $ABI_DUMP = ""; 21927 if($UseXML) 21928 { 21929 loadModule("XmlDump"); 21930 $ABI_DUMP = createXmlDump(\%ABI); 21931 } 21932 else 21933 { # default 21934 $ABI_DUMP = Dumper(\%ABI); 21935 } 21936 if($StdOut) 21937 { # --stdout option 21938 print STDOUT $ABI_DUMP; 21939 printMsg("INFO", "ABI dump has been generated to stdout"); 21940 return; 21941 } 21942 else 21943 { # write to gzipped file 21944 my ($DDir, $DName) = separate_path($DumpPath); 21945 my $DPath = $TMP_DIR."/".$DName; 21946 if(not $Archive) { 21947 $DPath = $DumpPath; 21948 } 21949 21950 mkpath($DDir); 21951 21952 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n"); 21953 print DUMP $ABI_DUMP; 21954 close(DUMP); 21955 21956 if(not -s $DPath) { 21957 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module"); 21958 } 21959 if($Archive) { 21960 $DumpPath = createArchive($DPath, $DDir); 21961 } 21962 21963 if($OutputDumpPath) { 21964 printMsg("INFO", "library ABI has been dumped to:\n $OutputDumpPath"); 21965 } 21966 else { 21967 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath"); 21968 } 21969 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor"); 21970 } 21971} 21972 21973sub quickEmptyReports() 21974{ # Quick "empty" reports 21975 # 4 times faster than merging equal dumps 21976 # NOTE: the dump contains the "LibraryVersion" attribute 21977 # if you change the version, then your dump will be different 21978 # OVERCOME: use -v1 and v2 options for comparing dumps 21979 # and don't change version in the XML descriptor (and dumps) 21980 # OVERCOME 2: separate meta info from the dumps in ACC 2.0 21981 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) 21982 { 21983 my $FilePath1 = unpackDump($Descriptor{1}{"Path"}); 21984 my $FilePath2 = unpackDump($Descriptor{2}{"Path"}); 21985 if($FilePath1 and $FilePath2) 21986 { 21987 my $Line = readLineNum($FilePath1, 0); 21988 if($Line=~/xml/) 21989 { # XML format 21990 # is not supported yet 21991 return; 21992 } 21993 21994 local $/ = undef; 21995 21996 open(DUMP1, $FilePath1); 21997 my $Content1 = <DUMP1>; 21998 close(DUMP1); 21999 22000 open(DUMP2, $FilePath2); 22001 my $Content2 = <DUMP2>; 22002 close(DUMP2); 22003 22004 if($Content1 eq $Content2) 22005 { 22006 # clean memory 22007 undef $Content2; 22008 22009 # read a number of headers, libs, symbols and types 22010 my $ABIdump = eval($Content1); 22011 22012 # clean memory 22013 undef $Content1; 22014 22015 if(not $ABIdump) { 22016 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); 22017 } 22018 if(not $ABIdump->{"TypeInfo"}) 22019 { # support for old dumps 22020 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"}; 22021 } 22022 if(not $ABIdump->{"SymbolInfo"}) 22023 { # support for old dumps 22024 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"}; 22025 } 22026 read_Source_DumpInfo($ABIdump, 1); 22027 read_Libs_DumpInfo($ABIdump, 1); 22028 read_Machine_DumpInfo($ABIdump, 1); 22029 read_Machine_DumpInfo($ABIdump, 2); 22030 22031 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}}; 22032 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}}; 22033 22034 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}}; 22035 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}}; 22036 22037 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"}; 22038 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"}; 22039 exitReport(); 22040 } 22041 } 22042 } 22043} 22044 22045sub initLogging($) 22046{ 22047 my $LibVersion = $_[0]; 22048 # create log directory 22049 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt"); 22050 if($OutputLogPath{$LibVersion}) 22051 { # user-defined by -log-path option 22052 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion}); 22053 } 22054 if($LogMode ne "n") { 22055 mkpath($LOG_DIR); 22056 } 22057 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE; 22058 if($Debug) 22059 { # debug directory 22060 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}; 22061 22062 if(not $ExtraInfo) 22063 { # enable --extra-info 22064 $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info"; 22065 } 22066 } 22067 resetLogging($LibVersion); 22068} 22069 22070sub writeLog($$) 22071{ 22072 my ($LibVersion, $Msg) = @_; 22073 if($LogMode ne "n") { 22074 appendFile($LOG_PATH{$LibVersion}, $Msg); 22075 } 22076} 22077 22078sub resetLogging($) 22079{ 22080 my $LibVersion = $_[0]; 22081 if($LogMode!~/a|n/) 22082 { # remove old log 22083 unlink($LOG_PATH{$LibVersion}); 22084 if($Debug) { 22085 rmtree($DEBUG_PATH{$LibVersion}); 22086 } 22087 } 22088} 22089 22090sub printErrorLog($) 22091{ 22092 my $LibVersion = $_[0]; 22093 if($LogMode ne "n") { 22094 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n"); 22095 } 22096} 22097 22098sub isDump($) 22099{ 22100 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz(\.\w+|)|\.zip|\.xml|)\Z/) 22101 { # NOTE: name.abi.tar.gz.amd64 (dh & cdbs) 22102 return $1; 22103 } 22104 return 0; 22105} 22106 22107sub isDump_U($) 22108{ 22109 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.xml|)\Z/) { 22110 return $1; 22111 } 22112 return 0; 22113} 22114 22115sub compareInit() 22116{ 22117 # read input XML descriptors or ABI dumps 22118 if(not $Descriptor{1}{"Path"}) { 22119 exitStatus("Error", "-old option is not specified"); 22120 } 22121 if(not -e $Descriptor{1}{"Path"}) { 22122 exitStatus("Access_Error", "can't access \'".$Descriptor{1}{"Path"}."\'"); 22123 } 22124 22125 if(not $Descriptor{2}{"Path"}) { 22126 exitStatus("Error", "-new option is not specified"); 22127 } 22128 if(not -e $Descriptor{2}{"Path"}) { 22129 exitStatus("Access_Error", "can't access \'".$Descriptor{2}{"Path"}."\'"); 22130 } 22131 22132 detect_default_paths("bin"); # to extract dumps 22133 if(isDump($Descriptor{1}{"Path"}) 22134 and isDump($Descriptor{2}{"Path"})) 22135 { # optimization: equal ABI dumps 22136 quickEmptyReports(); 22137 } 22138 22139 printMsg("INFO", "preparation, please wait ..."); 22140 22141 if(isDump($Descriptor{1}{"Path"})) { 22142 read_ABI_Dump(1, $Descriptor{1}{"Path"}); 22143 } 22144 else { 22145 readDescriptor(1, createDescriptor(1, $Descriptor{1}{"Path"})); 22146 } 22147 22148 if(isDump($Descriptor{2}{"Path"})) { 22149 read_ABI_Dump(2, $Descriptor{2}{"Path"}); 22150 } 22151 else { 22152 readDescriptor(2, createDescriptor(2, $Descriptor{2}{"Path"})); 22153 } 22154 22155 if(not $Descriptor{1}{"Version"}) 22156 { # set to default: X 22157 $Descriptor{1}{"Version"} = "X"; 22158 print STDERR "WARNING: version number #1 is not set (use --v1=NUM option)\n"; 22159 } 22160 22161 if(not $Descriptor{2}{"Version"}) 22162 { # set to default: Y 22163 $Descriptor{2}{"Version"} = "Y"; 22164 print STDERR "WARNING: version number #2 is not set (use --v2=NUM option)\n"; 22165 } 22166 22167 if(not $UsedDump{1}{"V"}) { 22168 initLogging(1); 22169 } 22170 22171 if(not $UsedDump{2}{"V"}) { 22172 initLogging(2); 22173 } 22174 22175 # check input data 22176 if(not $Descriptor{1}{"Headers"}) { 22177 exitStatus("Error", "can't find header files info in descriptor d1"); 22178 } 22179 if(not $Descriptor{2}{"Headers"}) { 22180 exitStatus("Error", "can't find header files info in descriptor d2"); 22181 } 22182 22183 if(not $CheckHeadersOnly) 22184 { 22185 if(not $Descriptor{1}{"Libs"}) { 22186 exitStatus("Error", "can't find libraries info in descriptor d1"); 22187 } 22188 if(not $Descriptor{2}{"Libs"}) { 22189 exitStatus("Error", "can't find libraries info in descriptor d2"); 22190 } 22191 } 22192 22193 if($UseDumps) 22194 { # --use-dumps 22195 # parallel processing 22196 my $DumpPath1 = defaultDumpPath($TargetLibraryName, $Descriptor{1}{"Version"}); 22197 my $DumpPath2 = defaultDumpPath($TargetLibraryName, $Descriptor{2}{"Version"}); 22198 22199 unlink($DumpPath1); 22200 unlink($DumpPath2); 22201 22202 my $pid = fork(); 22203 if($pid) 22204 { # dump on two CPU cores 22205 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName); 22206 if($RelativeDirectory{1}) { 22207 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1}); 22208 } 22209 if($OutputLogPath{1}) { 22210 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1}); 22211 } 22212 if($CrossGcc) { 22213 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22214 } 22215 if($Quiet) 22216 { 22217 @PARAMS = (@PARAMS, "-quiet"); 22218 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22219 } 22220 elsif($LogMode and $LogMode ne "w") 22221 { # "w" is default 22222 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22223 } 22224 if($ExtendedCheck) { 22225 @PARAMS = (@PARAMS, "-extended"); 22226 } 22227 if($UserLang) { 22228 @PARAMS = (@PARAMS, "-lang", $UserLang); 22229 } 22230 if($TargetVersion{1}) { 22231 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1}); 22232 } 22233 if($BinaryOnly) { 22234 @PARAMS = (@PARAMS, "-binary"); 22235 } 22236 if($SourceOnly) { 22237 @PARAMS = (@PARAMS, "-source"); 22238 } 22239 if($SortDump) { 22240 @PARAMS = (@PARAMS, "-sort"); 22241 } 22242 if($DumpFormat and $DumpFormat ne "perl") { 22243 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22244 } 22245 if($CheckHeadersOnly) { 22246 @PARAMS = (@PARAMS, "-headers-only"); 22247 } 22248 if($Debug) 22249 { 22250 @PARAMS = (@PARAMS, "-debug"); 22251 printMsg("INFO", "running perl $0 @PARAMS"); 22252 } 22253 system("perl", $0, @PARAMS); 22254 if(not -f $DumpPath1) { 22255 exit(1); 22256 } 22257 } 22258 else 22259 { # child 22260 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName); 22261 if($RelativeDirectory{2}) { 22262 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2}); 22263 } 22264 if($OutputLogPath{2}) { 22265 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2}); 22266 } 22267 if($CrossGcc) { 22268 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); 22269 } 22270 if($Quiet) 22271 { 22272 @PARAMS = (@PARAMS, "-quiet"); 22273 @PARAMS = (@PARAMS, "-logging-mode", "a"); 22274 } 22275 elsif($LogMode and $LogMode ne "w") 22276 { # "w" is default 22277 @PARAMS = (@PARAMS, "-logging-mode", $LogMode); 22278 } 22279 if($ExtendedCheck) { 22280 @PARAMS = (@PARAMS, "-extended"); 22281 } 22282 if($UserLang) { 22283 @PARAMS = (@PARAMS, "-lang", $UserLang); 22284 } 22285 if($TargetVersion{2}) { 22286 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2}); 22287 } 22288 if($BinaryOnly) { 22289 @PARAMS = (@PARAMS, "-binary"); 22290 } 22291 if($SourceOnly) { 22292 @PARAMS = (@PARAMS, "-source"); 22293 } 22294 if($SortDump) { 22295 @PARAMS = (@PARAMS, "-sort"); 22296 } 22297 if($DumpFormat and $DumpFormat ne "perl") { 22298 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); 22299 } 22300 if($CheckHeadersOnly) { 22301 @PARAMS = (@PARAMS, "-headers-only"); 22302 } 22303 if($Debug) 22304 { 22305 @PARAMS = (@PARAMS, "-debug"); 22306 printMsg("INFO", "running perl $0 @PARAMS"); 22307 } 22308 system("perl", $0, @PARAMS); 22309 if(not -f $DumpPath2) { 22310 exit(1); 22311 } 22312 else { 22313 exit(0); 22314 } 22315 } 22316 waitpid($pid, 0); 22317 22318 my @CMP_PARAMS = ("-l", $TargetLibraryName); 22319 @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1); 22320 @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2); 22321 if($TargetTitle ne $TargetLibraryName) { 22322 @CMP_PARAMS = (@CMP_PARAMS, "-title", $TargetTitle); 22323 } 22324 if($ShowRetVal) { 22325 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval"); 22326 } 22327 if($CrossGcc) { 22328 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc); 22329 } 22330 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a"); 22331 if($Quiet) { 22332 @CMP_PARAMS = (@CMP_PARAMS, "-quiet"); 22333 } 22334 if($ReportFormat and $ReportFormat ne "html") 22335 { # HTML is default format 22336 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat); 22337 } 22338 if($OutputReportPath) { 22339 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath); 22340 } 22341 if($BinaryReportPath) { 22342 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath); 22343 } 22344 if($SourceReportPath) { 22345 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath); 22346 } 22347 if($LoggingPath) { 22348 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath); 22349 } 22350 if($CheckHeadersOnly) { 22351 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only"); 22352 } 22353 if($BinaryOnly) { 22354 @CMP_PARAMS = (@CMP_PARAMS, "-binary"); 22355 } 22356 if($SourceOnly) { 22357 @CMP_PARAMS = (@CMP_PARAMS, "-source"); 22358 } 22359 if($Debug) 22360 { 22361 @CMP_PARAMS = (@CMP_PARAMS, "-debug"); 22362 printMsg("INFO", "running perl $0 @CMP_PARAMS"); 22363 } 22364 system("perl", $0, @CMP_PARAMS); 22365 exit($?>>8); 22366 } 22367 if(not $Descriptor{1}{"Dump"} 22368 or not $Descriptor{2}{"Dump"}) 22369 { # need GCC toolchain to analyze 22370 # header files and libraries 22371 detect_default_paths("inc|lib|gcc"); 22372 } 22373 if(not $Descriptor{1}{"Dump"}) 22374 { 22375 if(not $CheckHeadersOnly) { 22376 readLibs(1); 22377 } 22378 if($CheckHeadersOnly) { 22379 setLanguage(1, "C++"); 22380 } 22381 searchForHeaders(1); 22382 $WORD_SIZE{1} = detectWordSize(1); 22383 } 22384 if(not $Descriptor{2}{"Dump"}) 22385 { 22386 if(not $CheckHeadersOnly) { 22387 readLibs(2); 22388 } 22389 if($CheckHeadersOnly) { 22390 setLanguage(2, "C++"); 22391 } 22392 searchForHeaders(2); 22393 $WORD_SIZE{2} = detectWordSize(2); 22394 } 22395 if($WORD_SIZE{1} ne $WORD_SIZE{2}) 22396 { # support for old ABI dumps 22397 # try to synch different WORD sizes 22398 if(not checkDump(1, "2.1")) 22399 { 22400 $WORD_SIZE{1} = $WORD_SIZE{2}; 22401 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes"); 22402 } 22403 elsif(not checkDump(2, "2.1")) 22404 { 22405 $WORD_SIZE{2} = $WORD_SIZE{1}; 22406 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes"); 22407 } 22408 } 22409 elsif(not $WORD_SIZE{1} 22410 and not $WORD_SIZE{2}) 22411 { # support for old ABI dumps 22412 $WORD_SIZE{1} = "4"; 22413 $WORD_SIZE{2} = "4"; 22414 } 22415 if($Descriptor{1}{"Dump"}) 22416 { # support for old ABI dumps 22417 prepareTypes(1); 22418 } 22419 if($Descriptor{2}{"Dump"}) 22420 { # support for old ABI dumps 22421 prepareTypes(2); 22422 } 22423 if($AppPath and not keys(%{$Symbol_Library{1}})) { 22424 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries"); 22425 } 22426 # process input data 22427 if($Descriptor{1}{"Headers"} 22428 and not $Descriptor{1}{"Dump"}) { 22429 readHeaders(1); 22430 } 22431 if($Descriptor{2}{"Headers"} 22432 and not $Descriptor{2}{"Dump"}) { 22433 readHeaders(2); 22434 } 22435 22436 # clean memory 22437 %SystemHeaders = (); 22438 %mangled_name_gcc = (); 22439 22440 prepareSymbols(1); 22441 prepareSymbols(2); 22442 22443 # clean memory 22444 %SymbolInfo = (); 22445 22446 # Virtual Tables 22447 registerVTable(1); 22448 registerVTable(2); 22449 22450 if(not checkDump(1, "1.22") 22451 and checkDump(2, "1.22")) 22452 { # support for old ABI dumps 22453 foreach my $ClassName (keys(%{$VirtualTable{2}})) 22454 { 22455 if($ClassName=~/</) 22456 { # templates 22457 if(not defined $VirtualTable{1}{$ClassName}) 22458 { # synchronize 22459 delete($VirtualTable{2}{$ClassName}); 22460 } 22461 } 22462 } 22463 } 22464 22465 registerOverriding(1); 22466 registerOverriding(2); 22467 22468 setVirtFuncPositions(1); 22469 setVirtFuncPositions(2); 22470 22471 # Other 22472 addParamNames(1); 22473 addParamNames(2); 22474 22475 detectChangedTypedefs(); 22476} 22477 22478sub compareAPIs($) 22479{ 22480 my $Level = $_[0]; 22481 22482 readRules($Level); 22483 loadModule("CallConv"); 22484 22485 if($Level eq "Binary") { 22486 printMsg("INFO", "comparing ABIs ..."); 22487 } 22488 else { 22489 printMsg("INFO", "comparing APIs ..."); 22490 } 22491 22492 if($CheckHeadersOnly 22493 or $Level eq "Source") 22494 { # added/removed in headers 22495 detectAdded_H($Level); 22496 detectRemoved_H($Level); 22497 } 22498 else 22499 { # added/removed in libs 22500 detectAdded($Level); 22501 detectRemoved($Level); 22502 } 22503 22504 mergeSymbols($Level); 22505 if(keys(%{$CheckedSymbols{$Level}})) { 22506 mergeConstants($Level); 22507 } 22508 22509 $Cache{"mergeTypes"} = (); # free memory 22510 22511 if($CheckHeadersOnly 22512 or $Level eq "Source") 22513 { # added/removed in headers 22514 mergeHeaders($Level); 22515 } 22516 else 22517 { # added/removed in libs 22518 mergeLibs($Level); 22519 } 22520} 22521 22522sub getSysOpts() 22523{ 22524 my %Opts = ( 22525 "OStarget"=>$OStarget, 22526 "Debug"=>$Debug, 22527 "Quiet"=>$Quiet, 22528 "LogMode"=>$LogMode, 22529 "CheckHeadersOnly"=>$CheckHeadersOnly, 22530 22531 "SystemRoot"=>$SystemRoot, 22532 "GCC_PATH"=>$GCC_PATH, 22533 "TargetSysInfo"=>$TargetSysInfo, 22534 "CrossPrefix"=>$CrossPrefix, 22535 "TargetLibraryName"=>$TargetLibraryName, 22536 "CrossGcc"=>$CrossGcc, 22537 "UseStaticLibs"=>$UseStaticLibs, 22538 "NoStdInc"=>$NoStdInc, 22539 22540 "BinaryOnly" => $BinaryOnly, 22541 "SourceOnly" => $SourceOnly 22542 ); 22543 return \%Opts; 22544} 22545 22546sub get_CodeError($) 22547{ 22548 my %CODE_ERROR = reverse(%ERROR_CODE); 22549 return $CODE_ERROR{$_[0]}; 22550} 22551 22552sub scenario() 22553{ 22554 if($StdOut) 22555 { # enable quiet mode 22556 $Quiet = 1; 22557 $JoinReport = 1; 22558 } 22559 if(not $LogMode) 22560 { # default 22561 $LogMode = "w"; 22562 } 22563 if($UserLang) 22564 { # --lang=C++ 22565 $UserLang = uc($UserLang); 22566 $COMMON_LANGUAGE{1}=$UserLang; 22567 $COMMON_LANGUAGE{2}=$UserLang; 22568 } 22569 if($LoggingPath) 22570 { 22571 $OutputLogPath{1} = $LoggingPath; 22572 $OutputLogPath{2} = $LoggingPath; 22573 if($Quiet) { 22574 $COMMON_LOG_PATH = $LoggingPath; 22575 } 22576 } 22577 22578 if($SkipInternalSymbols) { 22579 $SkipInternalSymbols=~s/\*/.*/g; 22580 } 22581 22582 if($SkipInternalTypes) { 22583 $SkipInternalTypes=~s/\*/.*/g; 22584 } 22585 22586 if($Quick) { 22587 $ADD_TMPL_INSTANCES = 0; 22588 } 22589 if($OutputDumpPath) 22590 { # validate 22591 if(not isDump($OutputDumpPath)) { 22592 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file"); 22593 } 22594 } 22595 if($BinaryOnly and $SourceOnly) 22596 { # both --binary and --source 22597 # is the default mode 22598 if(not $CmpSystems) 22599 { 22600 $BinaryOnly = 0; 22601 $SourceOnly = 0; 22602 } 22603 22604 $DoubleReport = 1; 22605 $JoinReport = 0; 22606 22607 if($OutputReportPath) 22608 { # --report-path 22609 $DoubleReport = 0; 22610 $JoinReport = 1; 22611 } 22612 } 22613 elsif($BinaryOnly or $SourceOnly) 22614 { # --binary or --source 22615 $DoubleReport = 0; 22616 $JoinReport = 0; 22617 } 22618 if($UseXML) 22619 { # --xml option 22620 $ReportFormat = "xml"; 22621 $DumpFormat = "xml"; 22622 } 22623 if($ReportFormat) 22624 { # validate 22625 $ReportFormat = lc($ReportFormat); 22626 if($ReportFormat!~/\A(xml|html|htm)\Z/) { 22627 exitStatus("Error", "unknown report format \'$ReportFormat\'"); 22628 } 22629 if($ReportFormat eq "htm") 22630 { # HTM == HTML 22631 $ReportFormat = "html"; 22632 } 22633 elsif($ReportFormat eq "xml") 22634 { # --report-format=XML equal to --xml 22635 $UseXML = 1; 22636 } 22637 } 22638 else 22639 { # default: HTML 22640 $ReportFormat = "html"; 22641 } 22642 if($DumpFormat) 22643 { # validate 22644 $DumpFormat = lc($DumpFormat); 22645 if($DumpFormat!~/\A(xml|perl)\Z/) { 22646 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'"); 22647 } 22648 if($DumpFormat eq "xml") 22649 { # --dump-format=XML equal to --xml 22650 $UseXML = 1; 22651 } 22652 } 22653 else 22654 { # default: Perl Data::Dumper 22655 $DumpFormat = "perl"; 22656 } 22657 if($Quiet and $LogMode!~/a|n/) 22658 { # --quiet log 22659 if(-f $COMMON_LOG_PATH) { 22660 unlink($COMMON_LOG_PATH); 22661 } 22662 } 22663 if($ExtraInfo) { 22664 $CheckUndefined = 1; 22665 } 22666 if($TestTool and $UseDumps) 22667 { # --test && --use-dumps == --test-dump 22668 $TestDump = 1; 22669 } 22670 if($Tolerant) 22671 { # enable all 22672 $Tolerance = 1234; 22673 } 22674 if($Help) 22675 { 22676 HELP_MESSAGE(); 22677 exit(0); 22678 } 22679 if($InfoMsg) 22680 { 22681 INFO_MESSAGE(); 22682 exit(0); 22683 } 22684 if($ShowVersion) 22685 { 22686 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."); 22687 exit(0); 22688 } 22689 if($DumpVersion) 22690 { 22691 printMsg("INFO", $TOOL_VERSION); 22692 exit(0); 22693 } 22694 if($ExtendedCheck) { 22695 $CheckHeadersOnly = 1; 22696 } 22697 if($SystemRoot_Opt) 22698 { # user defined root 22699 if(not -e $SystemRoot_Opt) { 22700 exitStatus("Access_Error", "can't access \'$SystemRoot\'"); 22701 } 22702 $SystemRoot = $SystemRoot_Opt; 22703 $SystemRoot=~s/[\/]+\Z//g; 22704 if($SystemRoot) { 22705 $SystemRoot = get_abs_path($SystemRoot); 22706 } 22707 } 22708 $Data::Dumper::Sortkeys = 1; 22709 22710 if($SortDump) 22711 { 22712 $Data::Dumper::Useperl = 1; 22713 $Data::Dumper::Sortkeys = \&dump_sorting; 22714 } 22715 22716 if($TargetLibsPath) 22717 { 22718 if(not -f $TargetLibsPath) { 22719 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'"); 22720 } 22721 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) { 22722 $TargetLibs{$Lib} = 1; 22723 } 22724 } 22725 if($TargetHeadersPath) 22726 { # --headers-list 22727 if(not -f $TargetHeadersPath) { 22728 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'"); 22729 } 22730 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath))) 22731 { 22732 $TargetHeaders{1}{get_filename($Header)} = 1; 22733 $TargetHeaders{2}{get_filename($Header)} = 1; 22734 } 22735 } 22736 if($TargetHeader) 22737 { # --header 22738 $TargetHeaders{1}{get_filename($TargetHeader)} = 1; 22739 $TargetHeaders{2}{get_filename($TargetHeader)} = 1; 22740 } 22741 if($TestTool 22742 or $TestDump) 22743 { # --test, --test-dump 22744 detect_default_paths("bin|gcc"); # to compile libs 22745 loadModule("RegTests"); 22746 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, 22747 $LIB_EXT, $GCC_PATH, $SortDump, $CheckHeadersOnly); 22748 exit(0); 22749 } 22750 if($DumpSystem) 22751 { # --dump-system 22752 22753 if(not $TargetSysInfo) { 22754 exitStatus("Error", "-sysinfo option should be specified to dump system ABI"); 22755 } 22756 22757 if(not -d $TargetSysInfo) { 22758 exitStatus("Access_Error", "can't access \'$TargetSysInfo\'"); 22759 } 22760 22761 loadModule("SysCheck"); 22762 if($DumpSystem=~/\.(xml|desc)\Z/) 22763 { # system XML descriptor 22764 if(not -f $DumpSystem) { 22765 exitStatus("Access_Error", "can't access file \'$DumpSystem\'"); 22766 } 22767 22768 my $SDesc = readFile($DumpSystem); 22769 if(my $RelDir = $RelativeDirectory{1}) { 22770 $SDesc =~ s/{RELPATH}/$RelDir/g; 22771 } 22772 22773 my $Ret = readSystemDescriptor($SDesc); 22774 foreach (@{$Ret->{"Tools"}}) 22775 { 22776 push_U($SystemPaths{"bin"}, $_); 22777 $TargetTools{$_} = 1; 22778 } 22779 if($Ret->{"CrossPrefix"}) { 22780 $CrossPrefix = $Ret->{"CrossPrefix"}; 22781 } 22782 } 22783 elsif($SystemRoot_Opt) 22784 { # -sysroot "/" option 22785 # default target: /usr/lib, /usr/include 22786 # search libs: /usr/lib and /lib 22787 if(not -e $SystemRoot."/usr/lib") { 22788 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'"); 22789 } 22790 if(not -e $SystemRoot."/lib") { 22791 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'"); 22792 } 22793 if(not -e $SystemRoot."/usr/include") { 22794 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'"); 22795 } 22796 readSystemDescriptor(" 22797 <name> 22798 $DumpSystem 22799 </name> 22800 <headers> 22801 $SystemRoot/usr/include 22802 </headers> 22803 <libs> 22804 $SystemRoot/usr/lib 22805 </libs> 22806 <search_libs> 22807 $SystemRoot/lib 22808 </search_libs>"); 22809 } 22810 else { 22811 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\""); 22812 } 22813 detect_default_paths("bin|gcc"); # to check symbols 22814 if($OStarget eq "windows") 22815 { # to run dumpbin.exe 22816 # and undname.exe 22817 check_win32_env(); 22818 } 22819 dumpSystem(getSysOpts()); 22820 exit(0); 22821 } 22822 if($CmpSystems) 22823 { # --cmp-systems 22824 detect_default_paths("bin"); # to extract dumps 22825 loadModule("SysCheck"); 22826 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts()); 22827 exit(0); 22828 } 22829 if(not $TargetLibraryName) { 22830 exitStatus("Error", "library name is not selected (-l option)"); 22831 } 22832 else 22833 { # validate library name 22834 if($TargetLibraryName=~/[\*\/\\]/) { 22835 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name"); 22836 } 22837 } 22838 if(not $TargetTitle) { 22839 $TargetTitle = $TargetLibraryName; 22840 } 22841 22842 if($SymbolsListPath) 22843 { 22844 if(not -f $SymbolsListPath) { 22845 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'"); 22846 } 22847 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) { 22848 $SymbolsList{$Interface} = 1; 22849 } 22850 } 22851 if($TypesListPath) 22852 { 22853 if(not -f $TypesListPath) { 22854 exitStatus("Access_Error", "can't access file \'$TypesListPath\'"); 22855 } 22856 foreach my $Type (split(/\s*\n\s*/, readFile($TypesListPath))) { 22857 $TypesList{$Type} = 1; 22858 } 22859 } 22860 if($SkipSymbolsListPath) 22861 { 22862 if(not -f $SkipSymbolsListPath) { 22863 exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'"); 22864 } 22865 foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) 22866 { 22867 $SkipSymbols{1}{$Interface} = 1; 22868 $SkipSymbols{2}{$Interface} = 1; 22869 } 22870 } 22871 if($SkipTypesListPath) 22872 { 22873 if(not -f $SkipTypesListPath) { 22874 exitStatus("Access_Error", "can't access file \'$SkipTypesListPath\'"); 22875 } 22876 foreach my $Type (split(/\s*\n\s*/, readFile($SkipTypesListPath))) 22877 { 22878 $SkipTypes{1}{$Type} = 1; 22879 $SkipTypes{2}{$Type} = 1; 22880 } 22881 } 22882 if($SkipHeadersPath) 22883 { 22884 if(not -f $SkipHeadersPath) { 22885 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'"); 22886 } 22887 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath))) 22888 { # register for both versions 22889 $SkipHeadersList{1}{$Path} = 1; 22890 $SkipHeadersList{2}{$Path} = 1; 22891 my ($CPath, $Type) = classifyPath($Path); 22892 $SkipHeaders{1}{$Type}{$CPath} = 1; 22893 $SkipHeaders{2}{$Type}{$CPath} = 1; 22894 } 22895 } 22896 if($ParamNamesPath) 22897 { 22898 if(not -f $ParamNamesPath) { 22899 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'"); 22900 } 22901 foreach my $Line (split(/\n/, readFile($ParamNamesPath))) 22902 { 22903 if($Line=~s/\A(\w+)\;//) 22904 { 22905 my $Interface = $1; 22906 if($Line=~/;(\d+);/) 22907 { 22908 while($Line=~s/(\d+);(\w+)//) { 22909 $AddIntParams{$Interface}{$1}=$2; 22910 } 22911 } 22912 else 22913 { 22914 my $Num = 0; 22915 foreach my $Name (split(/;/, $Line)) { 22916 $AddIntParams{$Interface}{$Num++}=$Name; 22917 } 22918 } 22919 } 22920 } 22921 } 22922 if($AppPath) 22923 { 22924 if(not -f $AppPath) { 22925 exitStatus("Access_Error", "can't access file \'$AppPath\'"); 22926 } 22927 22928 detect_default_paths("bin|gcc"); 22929 foreach my $Interface (readSymbols_App($AppPath)) { 22930 $SymbolsList_App{$Interface} = 1; 22931 } 22932 } 22933 if($DumpAPI) 22934 { # --dump-abi 22935 # make an API dump 22936 create_ABI_Dump(); 22937 exit($COMPILE_ERRORS); 22938 } 22939 # default: compare APIs 22940 # -d1 <path> 22941 # -d2 <path> 22942 compareInit(); 22943 if($JoinReport or $DoubleReport) 22944 { 22945 compareAPIs("Binary"); 22946 compareAPIs("Source"); 22947 } 22948 elsif($BinaryOnly) { 22949 compareAPIs("Binary"); 22950 } 22951 elsif($SourceOnly) { 22952 compareAPIs("Source"); 22953 } 22954 exitReport(); 22955} 22956 22957scenario(); 22958