1########################################################################### 2# A module to create ABI dump from AST tree 3# 4# Copyright (C) 2015-2018 Andrey Ponomarenko's ABI Laboratory 5# 6# Written by Andrey Ponomarenko 7# 8# This library is free software; you can redistribute it and/or 9# modify it under the terms of the GNU Lesser General Public 10# License as published by the Free Software Foundation; either 11# version 2.1 of the License, or (at your option) any later version. 12# 13# This library is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16# Lesser General Public License for more details. 17# 18# You should have received a copy of the GNU Lesser General Public 19# License along with this library; if not, write to the Free Software 20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21# MA 02110-1301 USA 22########################################################################### 23use strict; 24 25loadModule("ElfTools"); 26loadModule("TUDump"); 27loadModule("GccAst"); 28 29my %Cache; 30 31my %RegisteredObj; 32my %RegisteredObj_Short; 33my %RegisteredSoname; 34my %RegisteredObj_Dir; 35my %CheckedDyLib; 36my %KnownLibs; 37my %CheckedArch; 38my @RecurLib; 39 40sub createABIDump($) 41{ 42 my $LVer = $_[0]; 43 44 if($In::Opt{"CheckHeadersOnly"}) { 45 $In::ABI{$LVer}{"Language"} = "C++"; 46 } 47 else 48 { 49 readLibs($LVer); 50 51 if(not keys(%{$In::ABI{$LVer}{"SymLib"}})) { 52 exitStatus("Error", "the set of public symbols in library(ies) is empty"); 53 } 54 } 55 56 if($In::Opt{"TargetArch"}) { 57 $In::ABI{$LVer}{"Arch"} = $In::Opt{"TargetArch"}; 58 } 59 else { 60 $In::ABI{$LVer}{"Arch"} = getArch_GCC($LVer); 61 } 62 63 $In::ABI{$LVer}{"WordSize"} = detectWordSize($LVer); 64 65 $In::ABI{$LVer}{"LibraryVersion"} = $In::Desc{$LVer}{"Version"}; 66 $In::ABI{$LVer}{"LibraryName"} = $In::Opt{"TargetLib"}; 67 68 if(not $In::ABI{$LVer}{"Language"}) { 69 $In::ABI{$LVer}{"Language"} = "C"; 70 } 71 72 if($In::Opt{"UserLang"}) { 73 $In::ABI{$LVer}{"Language"} = $In::Opt{"UserLang"}; 74 } 75 76 $In::ABI{$LVer}{"GccVersion"} = $In::Opt{"GccVer"}; 77 78 printMsg("INFO", "Checking header(s) ".$In::Desc{$LVer}{"Version"}." ..."); 79 my $TUDump = createTUDump($LVer); 80 81 if($In::Opt{"Debug"}) 82 { # debug mode 83 copy($TUDump, getDebugDir($LVer)."/translation-unit-dump.txt"); 84 } 85 86 readGccAst($LVer, $TUDump); 87 88 if($In::Opt{"DebugMangling"}) 89 { 90 if($In::ABI{$LVer}{"Language"} eq "C++") 91 { 92 debugMangling($LVer); 93 } 94 } 95 96 delete($In::ABI{$LVer}{"EnumConstants"}); 97 delete($In::ABI{$LVer}{"ClassVTable_Content"}); 98 delete($In::ABI{$LVer}{"WeakSymbols"}); 99 100 cleanDump($LVer); 101 102 if(not keys(%{$In::ABI{$LVer}{"SymbolInfo"}})) 103 { # check if created dump is valid 104 if(not $In::Opt{"ExtendedCheck"}) 105 { 106 if($In::Opt{"CheckHeadersOnly"}) { 107 exitStatus("Empty_Set", "the set of public symbols is empty"); 108 } 109 else { 110 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection"); 111 } 112 } 113 } 114 115 foreach my $HPath (keys(%{$In::Desc{$LVer}{"RegHeader"}})) { 116 $In::ABI{$LVer}{"Headers"}{getFilename($HPath)} = 1; 117 } 118 119 foreach my $InfoId (keys(%{$In::ABI{$LVer}{"SymbolInfo"}})) 120 { 121 if(my $MnglName = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"MnglName"}) 122 { 123 if(my $Unmangled = getUnmangled($MnglName, $LVer)) { 124 $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Unmangled"} = $Unmangled; 125 } 126 } 127 } 128 129 my %CompilerConstants = (); # built-in GCC constants 130 my $CRef = $In::ABI{$LVer}{"Constants"}; 131 foreach my $Name (keys(%{$CRef})) 132 { 133 if(not defined $CRef->{$Name}{"Header"}) 134 { 135 $CompilerConstants{$Name} = $CRef->{$Name}{"Value"}; 136 delete($CRef->{$Name}); 137 } 138 } 139 $In::ABI{$LVer}{"CompilerConstants"} = \%CompilerConstants; 140 141 if($In::Opt{"ExtendedCheck"}) 142 { # --ext option 143 $In::ABI{$LVer}{"Mode"} = "Extended"; 144 } 145 if($In::Opt{"BinOnly"}) 146 { # --binary 147 $In::ABI{$LVer}{"BinOnly"} = 1; 148 } 149 if($In::Opt{"ExtraDump"}) 150 { # --extra-dump 151 $In::ABI{$LVer}{"Extra"} = 1; 152 } 153 154 $In::ABI{$LVer}{"Target"} = $In::Opt{"Target"}; 155} 156 157sub readSymbols($) 158{ 159 my $LVer = $_[0]; 160 161 my @LibPaths = getSOPaths($LVer); 162 if($#LibPaths==-1) { 163 exitStatus("Error", "library objects are not found"); 164 } 165 166 foreach my $LibPath (@LibPaths) { 167 readSymbols_Lib($LVer, $LibPath, 0, "+Weak", 1, 1); 168 } 169 170 if($In::Opt{"CheckUndefined"}) 171 { 172 my %UndefinedLibs = (); 173 174 my @Libs = (keys(%{$In::ABI{$LVer}{"Symbols"}}), keys(%{$In::ABI{$LVer}{"DepSymbols"}})); 175 176 foreach my $LibName (sort @Libs) 177 { 178 if(defined $In::ABI{$LVer}{"UndefinedSymbols"}{$LibName}) 179 { 180 foreach my $Symbol (keys(%{$In::ABI{$LVer}{"UndefinedSymbols"}{$LibName}})) 181 { 182 if($In::ABI{$LVer}{"SymLib"}{$Symbol} 183 or $In::ABI{$LVer}{"DepSymLib"}{$Symbol}) 184 { # exported by target library 185 next; 186 } 187 if(index($Symbol, '@')!=-1) 188 { # exported default symbol version (@@) 189 $Symbol=~s/\@/\@\@/; 190 if($In::ABI{$LVer}{"SymLib"}{$Symbol} 191 or $In::ABI{$LVer}{"DepSymLib"}{$Symbol}) { 192 next; 193 } 194 } 195 foreach my $Path (find_SymbolLibs($LVer, $Symbol)) { 196 $UndefinedLibs{$Path} = 1; 197 } 198 } 199 } 200 } 201 202 if(my @Paths = sort keys(%UndefinedLibs)) 203 { 204 my $LibString = ""; 205 my %Dirs = (); 206 foreach (@Paths) 207 { 208 $KnownLibs{$_} = 1; 209 my ($Dir, $Name) = sepPath($_); 210 211 if(not grep {$Dir eq $_} (@{$In::Opt{"SysPaths"}{"lib"}})) { 212 $Dirs{escapeArg($Dir)} = 1; 213 } 214 215 $Name = libPart($Name, "name"); 216 $Name=~s/\Alib//; 217 218 $LibString .= " -l$Name"; 219 } 220 221 foreach my $Dir (sort {$b cmp $a} keys(%Dirs)) 222 { 223 $LibString = " -L".escapeArg($Dir).$LibString; 224 } 225 226 if($In::Opt{"ExtraInfo"}) { 227 writeFile($In::Opt{"ExtraInfo"}."/libs-string", $LibString); 228 } 229 } 230 } 231 232 if($In::Opt{"ExtraInfo"}) { 233 writeFile($In::Opt{"ExtraInfo"}."/lib-paths", join("\n", sort keys(%KnownLibs))); 234 } 235} 236 237sub readSymbols_Lib($$$$$$) 238{ 239 my ($LVer, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; 240 241 my $Real_Path = realpath_F($Lib_Path); 242 243 if(not $Real_Path) 244 { # broken link 245 return (); 246 } 247 248 my $Lib_Name = getFilename($Real_Path); 249 my $LExt = $In::Opt{"Ext"}; 250 251 if($In::Opt{"ExtraInfo"}) 252 { 253 $KnownLibs{$Real_Path} = 1; 254 $KnownLibs{$Lib_Path} = 1; # links 255 } 256 257 if($IsNeededLib) 258 { 259 if($CheckedDyLib{$LVer}{$Lib_Name}) { 260 return (); 261 } 262 } 263 if($#RecurLib>=1 or isCyclical(\@RecurLib, $Lib_Name)) { 264 return (); 265 } 266 $CheckedDyLib{$LVer}{$Lib_Name} = 1; 267 268 my $TmpDir = $In::Opt{"Tmp"}; 269 270 push(@RecurLib, $Lib_Name); 271 my (%Value_Interface, %Interface_Value, %NeededLib) = (); 272 my $Lib_ShortName = libPart($Lib_Name, "name+ext"); 273 274 if(not $IsNeededLib) 275 { # special cases: libstdc++ and libc 276 if(my $ShortName = libPart($Lib_Name, "short")) 277 { 278 if($ShortName eq "libstdc++" 279 or $ShortName eq "libc++") 280 { # libstdc++.so.6 281 $In::Opt{"StdcxxTesting"} = 1; 282 } 283 elsif($ShortName eq "libc") 284 { # libc-2.11.3.so 285 $In::Opt{"GlibcTesting"} = 1; 286 } 287 } 288 } 289 my $DebugPath = ""; 290 if($In::Opt{"Debug"} and not $In::Opt{"DumpSystem"}) 291 { # debug mode 292 $DebugPath = getDebugDir($LVer)."/libs/".getFilename($Lib_Path).".txt"; 293 mkpath(getDirname($DebugPath)); 294 } 295 if($In::Opt{"Target"} eq "macos") 296 { # Mac OS X: *.dylib, *.a 297 my $NM = getCmdPath("nm"); 298 if(not $NM) { 299 exitStatus("Not_Found", "can't find \"nm\""); 300 } 301 $NM .= " -g \"$Lib_Path\" 2>\"$TmpDir/null\""; 302 if($DebugPath) 303 { # debug mode 304 # write to file 305 system($NM." >\"$DebugPath\""); 306 open(LIB, $DebugPath); 307 } 308 else 309 { # write to pipe 310 open(LIB, $NM." |"); 311 } 312 while(<LIB>) 313 { 314 if($In::Opt{"CheckUndefined"}) 315 { 316 if(not $IsNeededLib) 317 { 318 if(/ U _([\w\$]+)\s*\Z/) 319 { 320 $In::ABI{$LVer}{"UndefinedSymbols"}{$Lib_Name}{$1} = 0; 321 next; 322 } 323 } 324 } 325 326 if(/ [STD] _([\w\$]+)\s*\Z/) 327 { 328 my $Symbol = $1; 329 if($IsNeededLib) 330 { 331 if(not defined $RegisteredObj_Short{$LVer}{$Lib_ShortName}) 332 { 333 $In::ABI{$LVer}{"DepSymLib"}{$Symbol} = $Lib_Name; 334 $In::ABI{$LVer}{"DepSymbols"}{$Lib_Name}{$Symbol} = 1; 335 } 336 } 337 else 338 { 339 $In::ABI{$LVer}{"SymLib"}{$Symbol} = $Lib_Name; 340 $In::ABI{$LVer}{"Symbols"}{$Lib_Name}{$Symbol} = 1; 341 if($In::ABI{$LVer}{"Language"} ne "C++") 342 { 343 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 344 $In::ABI{$LVer}{"Language"} = "C++"; 345 } 346 } 347 } 348 } 349 } 350 close(LIB); 351 352 if($Deps) 353 { 354 if(not $In::Opt{"UseStaticLibs"}) 355 { # dependencies 356 my $OtoolCmd = getCmdPath("otool"); 357 if(not $OtoolCmd) { 358 exitStatus("Not_Found", "can't find \"otool\""); 359 } 360 361 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TmpDir/null\" |"); 362 while(<LIB>) 363 { 364 if(/\s*([\/\\].+\.$LExt)\s*/ 365 and $1 ne $Lib_Path) { 366 $NeededLib{$1} = 1; 367 } 368 } 369 close(LIB); 370 } 371 } 372 } 373 elsif($In::Opt{"Target"} eq "windows") 374 { # Windows *.dll, *.lib 375 my $DumpBinCmd = getCmdPath("dumpbin"); 376 if(not $DumpBinCmd) { 377 exitStatus("Not_Found", "can't find \"dumpbin\""); 378 } 379 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TmpDir/null"; 380 if($DebugPath) 381 { # debug mode 382 # write to file 383 system($DumpBinCmd." >\"$DebugPath\""); 384 open(LIB, $DebugPath); 385 } 386 else 387 { # write to pipe 388 open(LIB, $DumpBinCmd." |"); 389 } 390 while(<LIB>) 391 { 392 my $Symbol = undef; 393 if($In::Opt{"UseStaticLibs"}) 394 { 395 if(/\A\s{10,}(\d+\s+|)([_\w\?\@]+)(\s*\Z|\s+)/i) 396 { 397 # 16 IID_ISecurityInformation 398 # ??_7TestBaseClass@api@@6B@ (const api::TestBaseClass::`vftable') 399 $Symbol = $2; 400 } 401 } 402 else 403 { # Dll 404 # 1197 4AC 0000A620 SetThreadStackGuarantee 405 # 1198 4AD SetThreadToken (forwarded to ...) 406 # 3368 _o2i_ECPublicKey 407 # 1 0 00005B30 ??0?N = ... (with pdb) 408 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i 409 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ 410 or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) 411 { # dynamic, static and forwarded symbols 412 $Symbol = $1; 413 } 414 } 415 416 if($Symbol) 417 { 418 if($IsNeededLib) 419 { 420 if(not defined $RegisteredObj_Short{$LVer}{$Lib_ShortName}) 421 { 422 $In::ABI{$LVer}{"DepSymLib"}{$Symbol} = $Lib_Name; 423 $In::ABI{$LVer}{"DepSymbols"}{$Lib_Name}{$Symbol} = 1; 424 } 425 } 426 else 427 { 428 $In::ABI{$LVer}{"SymLib"}{$Symbol} = $Lib_Name; 429 $In::ABI{$LVer}{"Symbols"}{$Lib_Name}{$Symbol} = 1; 430 if($In::ABI{$LVer}{"Language"} ne "C++") 431 { 432 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 433 $In::ABI{$LVer}{"Language"} = "C++"; 434 } 435 } 436 } 437 } 438 } 439 close(LIB); 440 441 if($Deps) 442 { 443 if(not $In::Opt{"UseStaticLibs"}) 444 { # dependencies 445 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TmpDir/null\" |"); 446 while(<LIB>) 447 { 448 if(/\s*([^\s]+?\.$LExt)\s*/i 449 and $1 ne $Lib_Path) { 450 $NeededLib{pathFmt($1)} = 1; 451 } 452 } 453 close(LIB); 454 } 455 } 456 } 457 else 458 { # Unix; *.so, *.a 459 # Symbian: *.dso, *.lib 460 my $ReadelfCmd = getCmdPath("readelf"); 461 if(not $ReadelfCmd) { 462 exitStatus("Not_Found", "can't find \"readelf\""); 463 } 464 my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TmpDir/null\""; 465 if($DebugPath) 466 { # debug mode 467 # write to file 468 system($Cmd." >\"$DebugPath\""); 469 open(LIB, $DebugPath); 470 } 471 else 472 { # write to pipe 473 open(LIB, $Cmd." |"); 474 } 475 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 476 while(<LIB>) 477 { 478 if(not $In::Opt{"UseStaticLibs"}) 479 { # dynamic library specifics 480 if(defined $symtab) 481 { 482 if(index($_, "'.dynsym'")!=-1) 483 { # dynamic table 484 $symtab = undef; 485 } 486 # do nothing with symtab 487 next; 488 } 489 elsif(index($_, "'.symtab'")!=-1) 490 { # symbol table 491 $symtab = 1; 492 next; 493 } 494 } 495 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_)) 496 { # read ELF entry 497 if($Ndx eq "UND") 498 { # ignore interfaces that are imported from somewhere else 499 if($In::Opt{"CheckUndefined"}) 500 { 501 if(not $IsNeededLib) { 502 $In::ABI{$LVer}{"UndefinedSymbols"}{$Lib_Name}{$Symbol} = 0; 503 } 504 } 505 next; 506 } 507 if($Bind eq "WEAK") 508 { 509 $In::ABI{$LVer}{"WeakSymbols"}{$Symbol} = 1; 510 if($Weak eq "-Weak") 511 { # skip WEAK symbols 512 next; 513 } 514 } 515 if($IsNeededLib) 516 { 517 if(not defined $RegisteredObj_Short{$LVer}{$Lib_ShortName}) 518 { 519 $In::ABI{$LVer}{"DepSymLib"}{$Symbol} = $Lib_Name; 520 $In::ABI{$LVer}{"DepSymbols"}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 521 } 522 } 523 else 524 { 525 $In::ABI{$LVer}{"SymLib"}{$Symbol} = $Lib_Name; 526 $In::ABI{$LVer}{"Symbols"}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; 527 if($Vers) 528 { 529 if($LExt eq "so") 530 { # value 531 $Interface_Value{$LVer}{$Symbol} = $Value; 532 $Value_Interface{$LVer}{$Value}{$Symbol} = 1; 533 } 534 } 535 if($In::ABI{$LVer}{"Language"} ne "C++") 536 { 537 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { 538 $In::ABI{$LVer}{"Language"} = "C++"; 539 } 540 } 541 } 542 } 543 } 544 close(LIB); 545 546 if($Deps and not $In::Opt{"UseStaticLibs"}) 547 { # dynamic library specifics 548 $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TmpDir/null\""; 549 open(LIB, $Cmd." |"); 550 551 while(<LIB>) 552 { 553 if(/NEEDED.+\[([^\[\]]+)\]/) 554 { # dependencies: 555 # 0x00000001 (NEEDED) Shared library: [libc.so.6] 556 $NeededLib{$1} = 1; 557 } 558 } 559 560 close(LIB); 561 } 562 } 563 if($Vers) 564 { 565 if(not $IsNeededLib and $LExt eq "so") 566 { # get symbol versions 567 my %Found = (); 568 569 # by value 570 foreach my $Symbol (sort keys(%{$In::ABI{$LVer}{"Symbols"}{$Lib_Name}})) 571 { 572 next if(index($Symbol, '@')==-1); 573 if(my $Value = $Interface_Value{$LVer}{$Symbol}) 574 { 575 foreach my $Symbol_SameValue (sort keys(%{$Value_Interface{$LVer}{$Value}})) 576 { 577 if($Symbol_SameValue ne $Symbol 578 and index($Symbol_SameValue, '@')==-1) 579 { 580 $In::ABI{$LVer}{"SymbolVersion"}{$Symbol_SameValue} = $Symbol; 581 $Found{$Symbol} = 1; 582 583 if(index($Symbol, '@@')==-1) { 584 last; 585 } 586 } 587 } 588 } 589 } 590 591 # default 592 foreach my $Symbol (keys(%{$In::ABI{$LVer}{"Symbols"}{$Lib_Name}})) 593 { 594 next if(defined $Found{$Symbol}); 595 next if(index($Symbol, '@@')==-1); 596 597 if($Symbol=~/\A([^\@]*)\@\@/ 598 and not $In::ABI{$LVer}{"SymbolVersion"}{$1}) 599 { 600 $In::ABI{$LVer}{"SymbolVersion"}{$1} = $Symbol; 601 $Found{$Symbol} = 1; 602 } 603 } 604 605 # non-default 606 foreach my $Symbol (keys(%{$In::ABI{$LVer}{"Symbols"}{$Lib_Name}})) 607 { 608 next if(defined $Found{$Symbol}); 609 next if(index($Symbol, '@')==-1); 610 611 if($Symbol=~/\A([^\@]*)\@([^\@]*)/ 612 and not $In::ABI{$LVer}{"SymbolVersion"}{$1}) 613 { 614 $In::ABI{$LVer}{"SymbolVersion"}{$1} = $Symbol; 615 $Found{$Symbol} = 1; 616 } 617 } 618 } 619 } 620 if($Deps) 621 { 622 foreach my $DyLib (sort keys(%NeededLib)) 623 { 624 if($In::Opt{"ExtraDump"}) { 625 $In::ABI{$LVer}{"Needed"}{$Lib_Name}{getFilename($DyLib)} = 1; 626 } 627 628 if(my $DepPath = getLibPath($LVer, $DyLib)) 629 { 630 if(not $CheckedDyLib{$LVer}{getFilename($DepPath)}) { 631 readSymbols_Lib($LVer, $DepPath, 1, "+Weak", $Deps, $Vers); 632 } 633 } 634 } 635 } 636 pop(@RecurLib); 637 return $In::ABI{$LVer}{"Symbols"}; 638} 639 640sub readSymbols_App($) 641{ 642 my $Path = $_[0]; 643 644 my $TmpDir = $In::Opt{"Tmp"}; 645 646 my @Imported = (); 647 if($In::Opt{"Target"} eq "macos") 648 { 649 my $NM = getCmdPath("nm"); 650 if(not $NM) { 651 exitStatus("Not_Found", "can't find \"nm\""); 652 } 653 open(APP, "$NM -g \"$Path\" 2>\"$TmpDir/null\" |"); 654 while(<APP>) 655 { 656 if(/ U _([\w\$]+)\s*\Z/) { 657 push(@Imported, $1); 658 } 659 } 660 close(APP); 661 } 662 elsif($In::Opt{"Target"} eq "windows") 663 { 664 my $DumpBinCmd = getCmdPath("dumpbin"); 665 if(not $DumpBinCmd) { 666 exitStatus("Not_Found", "can't find \"dumpbin.exe\""); 667 } 668 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TmpDir/null\" |"); 669 while(<APP>) 670 { 671 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) { 672 push(@Imported, $1); 673 } 674 } 675 close(APP); 676 } 677 else 678 { 679 my $ReadelfCmd = getCmdPath("readelf"); 680 if(not $ReadelfCmd) { 681 exitStatus("Not_Found", "can't find \"readelf\""); 682 } 683 open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TmpDir/null\" |"); 684 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output 685 while(<APP>) 686 { 687 if(defined $symtab) 688 { # do nothing with symtab 689 if(index($_, "'.dynsym'")!=-1) 690 { # dynamic table 691 $symtab = undef; 692 } 693 } 694 elsif(index($_, "'.symtab'")!=-1) 695 { # symbol table 696 $symtab = 1; 697 } 698 elsif(my @Info = readline_ELF($_)) 699 { 700 my ($Ndx, $Symbol) = ($Info[5], $Info[6]); 701 if($Ndx eq "UND") 702 { # only imported symbols 703 push(@Imported, $Symbol); 704 } 705 } 706 } 707 close(APP); 708 } 709 return @Imported; 710} 711 712sub cleanDump($) 713{ # clean data 714 my $LVer = $_[0]; 715 foreach my $InfoId (keys(%{$In::ABI{$LVer}{"SymbolInfo"}})) 716 { 717 if(not keys(%{$In::ABI{$LVer}{"SymbolInfo"}{$InfoId}})) 718 { 719 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}); 720 next; 721 } 722 my $MnglName = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"MnglName"}; 723 if(not $MnglName) 724 { 725 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}); 726 next; 727 } 728 my $ShortName = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"ShortName"}; 729 if(not $ShortName) 730 { 731 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}); 732 next; 733 } 734 if($MnglName eq $ShortName) 735 { # remove duplicate data 736 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"MnglName"}); 737 } 738 if(not keys(%{$In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Param"}})) { 739 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Param"}); 740 } 741 if(not keys(%{$In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"TParam"}})) { 742 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"TParam"}); 743 } 744 delete($In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Type"}); 745 } 746 foreach my $Tid (keys(%{$In::ABI{$LVer}{"TypeInfo"}})) 747 { 748 if(not keys(%{$In::ABI{$LVer}{"TypeInfo"}{$Tid}})) 749 { 750 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}); 751 next; 752 } 753 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}{"Tid"}); 754 foreach my $Attr ("Header", "Line", "Size", "NameSpace") 755 { 756 if(not $In::ABI{$LVer}{"TypeInfo"}{$Tid}{$Attr}) { 757 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}{$Attr}); 758 } 759 } 760 if(not keys(%{$In::ABI{$LVer}{"TypeInfo"}{$Tid}{"TParam"}})) { 761 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}{"TParam"}); 762 } 763 } 764} 765 766sub readLibs($) 767{ 768 my $LVer = $_[0]; 769 770 if($In::Opt{"Target"} eq "windows") 771 { # dumpbin.exe will crash 772 # without VS Environment 773 checkWin32Env(); 774 } 775 776 readSymbols($LVer); 777 778 translateSymbols(keys(%{$In::ABI{$LVer}{"SymLib"}}), $LVer); 779 translateSymbols(keys(%{$In::ABI{$LVer}{"DepSymLib"}}), $LVer); 780} 781 782sub getSOPaths($) 783{ 784 my $LVer = $_[0]; 785 my @Paths = (); 786 foreach my $P (keys(%{$In::Desc{$LVer}{"Libs"}})) 787 { 788 my @Found = getSOPaths_Dir(getAbsPath($P), $LVer); 789 foreach (@Found) { 790 push(@Paths, $_); 791 } 792 } 793 return sort @Paths; 794} 795 796sub getSOPaths_Dir($$) 797{ 798 my ($Path, $LVer) = @_; 799 if(skipLib($Path, $LVer)) { 800 return (); 801 } 802 803 my $LExt = $In::Opt{"Ext"}; 804 805 if(-f $Path) 806 { 807 if(not libPart($Path, "name")) { 808 exitStatus("Error", "incorrect format of library (should be *.$LExt): \'$Path\'"); 809 } 810 registerObject($Path, $LVer); 811 registerObject_Dir(getDirname($Path), $LVer); 812 return ($Path); 813 } 814 elsif(-d $Path) 815 { 816 $Path=~s/[\/\\]+\Z//g; 817 my %Libs = (); 818 if(my $TN = $In::Opt{"TargetLib"} 819 and grep { $Path eq $_ } @{$In::Opt{"SysPaths"}{"lib"}}) 820 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor 821 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...) 822 foreach my $P (cmdFind($Path,"","*".escapeArg($TN)."*.$LExt*",2)) 823 { # all files and symlinks that match the name of a library 824 if(getFilename($P)=~/\A(|lib)\Q$TN\E[\d\-]*\.$LExt[\d\.]*\Z/i) 825 { 826 registerObject($P, $LVer); 827 $Libs{realpath_F($P)} = 1; 828 } 829 } 830 } 831 else 832 { # search for all files and symlinks 833 foreach my $P (findLibs($Path,"","")) 834 { 835 next if(ignorePath($P)); 836 next if(skipLib($P, $LVer)); 837 registerObject($P, $LVer); 838 $Libs{realpath_F($P)} = 1; 839 } 840 if($In::Opt{"OS"} eq "macos") 841 { # shared libraries on macOS may have no extension 842 foreach my $P (cmdFind($Path,"f")) 843 { 844 next if(ignorePath($P)); 845 next if(skipLib($P, $LVer)); 846 if(getFilename($P)!~/\./ and -B $P 847 and cmdFile($P)=~/(shared|dynamic)\s+library/i) 848 { 849 registerObject($P, $LVer); 850 $Libs{realpath_F($P)} = 1; 851 } 852 } 853 } 854 } 855 return keys(%Libs); 856 } 857 858 return (); 859} 860 861sub registerObject_Dir($$) 862{ 863 my ($Dir, $LVer) = @_; 864 if(grep {$_ eq $Dir} @{$In::Opt{"SysPaths"}{"lib"}}) 865 { # system directory 866 return; 867 } 868 if($RegisteredObj_Dir{$LVer}{$Dir}) 869 { # already registered 870 return; 871 } 872 foreach my $Path (findLibs($Dir,"",1)) 873 { 874 if(ignorePath($Path)) { 875 next; 876 } 877 if(skipLib($Path, $LVer)) { 878 next; 879 } 880 registerObject($Path, $LVer); 881 } 882 $RegisteredObj_Dir{$LVer}{$Dir} = 1; 883} 884 885sub registerObject($$) 886{ 887 my ($Path, $LVer) = @_; 888 889 my $Name = getFilename($Path); 890 $RegisteredObj{$LVer}{$Name} = $Path; 891 if($In::Opt{"Target"}=~/linux|bsd|gnu|solaris/i) 892 { 893 if(my $SONAME = getSONAME($Path)) { 894 $RegisteredSoname{$LVer}{$SONAME} = $Path; 895 } 896 } 897 if(my $Short = libPart($Name, "name+ext")) { 898 $RegisteredObj_Short{$LVer}{$Short} = $Path; 899 } 900 901 if(not $CheckedArch{$LVer} and -f $Path) 902 { 903 if(my $ObjArch = getArch_Object($Path)) 904 { 905 if($ObjArch ne getArch_GCC($LVer)) 906 { # translation unit dump generated by the GCC compiler should correspond to input objects 907 $CheckedArch{$LVer} = 1; 908 printMsg("WARNING", "the architectures of input objects and the used GCC compiler are not equal, please change the compiler by --gcc-path=PATH option."); 909 } 910 } 911 } 912} 913 914sub remove_Unused($$) 915{ # remove unused data types from the ABI dump 916 my ($LVer, $Kind) = @_; 917 918 my %UsedType = (); 919 920 foreach my $InfoId (sort {$a<=>$b} keys(%{$In::ABI{$LVer}{"SymbolInfo"}})) 921 { 922 registerSymbolUsage($InfoId, \%UsedType, $LVer); 923 } 924 foreach my $Tid (sort {$a<=>$b} keys(%{$In::ABI{$LVer}{"TypeInfo"}})) 925 { 926 if($UsedType{$Tid}) 927 { # All & Extended 928 next; 929 } 930 931 if($Kind eq "Extended") 932 { 933 if(pickType($Tid, $LVer)) 934 { 935 my %Tree = (); 936 registerTypeUsage($Tid, \%Tree, $LVer); 937 938 my $Tmpl = 0; 939 foreach (sort {$a<=>$b} keys(%Tree)) 940 { 941 if(defined $In::ABI{$LVer}{"TypeInfo"}{$_}{"Template"} 942 or $In::ABI{$LVer}{"TypeInfo"}{$_}{"Type"} eq "TemplateParam") 943 { 944 $Tmpl = 1; 945 last; 946 } 947 } 948 if(not $Tmpl) 949 { 950 foreach (keys(%Tree)) { 951 $UsedType{$_} = 1; 952 } 953 } 954 } 955 } 956 } 957 958 my %Delete = (); 959 960 foreach my $Tid (sort {$a<=>$b} keys(%{$In::ABI{$LVer}{"TypeInfo"}})) 961 { # remove unused types 962 if($UsedType{$Tid}) 963 { # All & Extended 964 next; 965 } 966 967 if($Kind eq "Extra") 968 { 969 my %Tree = (); 970 registerTypeUsage($Tid, \%Tree, $LVer); 971 972 foreach (sort {$a<=>$b} keys(%Tree)) 973 { 974 if(defined $In::ABI{$LVer}{"TypeInfo"}{$_}{"Template"} 975 or $In::ABI{$LVer}{"TypeInfo"}{$_}{"Type"} eq "TemplateParam") 976 { 977 $Delete{$Tid} = 1; 978 last; 979 } 980 } 981 } 982 else 983 { 984 # remove type 985 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}); 986 } 987 } 988 989 if($Kind eq "Extra") 990 { # remove duplicates 991 foreach my $Tid (sort {$a<=>$b} keys(%{$In::ABI{$LVer}{"TypeInfo"}})) 992 { 993 if($UsedType{$Tid}) 994 { # All & Extended 995 next; 996 } 997 998 my $Name = $In::ABI{$LVer}{"TypeInfo"}{$Tid}{"Name"}; 999 1000 if($In::ABI{$LVer}{"TName_Tid"}{$Name} ne $Tid) { 1001 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}); 1002 } 1003 } 1004 } 1005 1006 foreach my $Tid (keys(%Delete)) 1007 { 1008 delete($In::ABI{$LVer}{"TypeInfo"}{$Tid}); 1009 } 1010} 1011 1012sub getFirst($$) 1013{ 1014 my ($Tid, $LVer) = @_; 1015 if(not $Tid) { 1016 return $Tid; 1017 } 1018 1019 if(my $Name = $In::ABI{$LVer}{"TypeInfo"}{$Tid}{"Name"}) 1020 { 1021 if($In::ABI{$LVer}{"TName_Tid"}{$Name}) { 1022 return $In::ABI{$LVer}{"TName_Tid"}{$Name}; 1023 } 1024 } 1025 1026 return $Tid; 1027} 1028 1029sub registerSymbolUsage($$$) 1030{ 1031 my ($InfoId, $UsedType, $LVer) = @_; 1032 1033 my %FuncInfo = %{$In::ABI{$LVer}{"SymbolInfo"}{$InfoId}}; 1034 if(my $RTid = getFirst($FuncInfo{"Return"}, $LVer)) 1035 { 1036 registerTypeUsage($RTid, $UsedType, $LVer); 1037 $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Return"} = $RTid; 1038 } 1039 if(my $FCid = getFirst($FuncInfo{"Class"}, $LVer)) 1040 { 1041 registerTypeUsage($FCid, $UsedType, $LVer); 1042 $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}{"Class"} = $FCid; 1043 1044 if(my $ThisId = getTypeIdByName($In::ABI{$LVer}{"TypeInfo"}{$FCid}{"Name"}."*const", $LVer)) 1045 { # register "this" pointer 1046 registerTypeUsage($ThisId, $UsedType, $LVer); 1047 } 1048 if(my $ThisId_C = getTypeIdByName($In::ABI{$LVer}{"TypeInfo"}{$FCid}{"Name"}." const*const", $LVer)) 1049 { # register "this" pointer (const method) 1050 registerTypeUsage($ThisId_C, $UsedType, $LVer); 1051 } 1052 } 1053 foreach my $PPos (sort {$a<=>$b} keys(%{$FuncInfo{"Param"}})) 1054 { 1055 if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LVer)) 1056 { 1057 registerTypeUsage($PTid, $UsedType, $LVer); 1058 $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; 1059 } 1060 } 1061 foreach my $TPos (sort {$a<=>$b} keys(%{$FuncInfo{"TParam"}})) 1062 { 1063 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; 1064 if(my $TTid = $In::ABI{$LVer}{"TName_Tid"}{$TPName}) { 1065 registerTypeUsage($TTid, $UsedType, $LVer); 1066 } 1067 } 1068} 1069 1070sub registerTypeUsage($$$) 1071{ 1072 my ($TypeId, $UsedType, $LVer) = @_; 1073 if(not $TypeId) { 1074 return; 1075 } 1076 if($UsedType->{$TypeId}) 1077 { # already registered 1078 return; 1079 } 1080 1081 my %TInfo = getType($TypeId, $LVer); 1082 if($TInfo{"Type"}) 1083 { 1084 if(my $NS = $TInfo{"NameSpace"}) 1085 { 1086 if(my $NSTid = $In::ABI{$LVer}{"TName_Tid"}{$NS}) { 1087 registerTypeUsage($NSTid, $UsedType, $LVer); 1088 } 1089 } 1090 1091 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) 1092 { 1093 $UsedType->{$TypeId} = 1; 1094 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) 1095 { 1096 foreach my $BaseId (sort {$a<=>$b} keys(%{$TInfo{"Base"}})) { 1097 registerTypeUsage($BaseId, $UsedType, $LVer); 1098 } 1099 foreach my $TPos (sort {$a<=>$b} keys(%{$TInfo{"TParam"}})) 1100 { 1101 my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; 1102 if(my $TTid = $In::ABI{$LVer}{"TName_Tid"}{$TPName}) { 1103 registerTypeUsage($TTid, $UsedType, $LVer); 1104 } 1105 } 1106 } 1107 foreach my $Memb_Pos (sort {$a<=>$b} keys(%{$TInfo{"Memb"}})) 1108 { 1109 if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LVer)) 1110 { 1111 registerTypeUsage($MTid, $UsedType, $LVer); 1112 $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; 1113 } 1114 } 1115 if($TInfo{"Type"} eq "FuncPtr" 1116 or $TInfo{"Type"} eq "MethodPtr" 1117 or $TInfo{"Type"} eq "Func") 1118 { 1119 if(my $RTid = $TInfo{"Return"}) { 1120 registerTypeUsage($RTid, $UsedType, $LVer); 1121 } 1122 foreach my $PPos (sort {$a<=>$b} keys(%{$TInfo{"Param"}})) 1123 { 1124 if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { 1125 registerTypeUsage($PTid, $UsedType, $LVer); 1126 } 1127 } 1128 } 1129 if($TInfo{"Type"} eq "FieldPtr") 1130 { 1131 if(my $RTid = $TInfo{"Return"}) { 1132 registerTypeUsage($RTid, $UsedType, $LVer); 1133 } 1134 if(my $CTid = $TInfo{"Class"}) { 1135 registerTypeUsage($CTid, $UsedType, $LVer); 1136 } 1137 } 1138 if($TInfo{"Type"} eq "MethodPtr") 1139 { 1140 if(my $CTid = $TInfo{"Class"}) { 1141 registerTypeUsage($CTid, $UsedType, $LVer); 1142 } 1143 } 1144 } 1145 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) 1146 { 1147 $UsedType->{$TypeId} = 1; 1148 if(my $BTid = getFirst($TInfo{"BaseType"}, $LVer)) 1149 { 1150 registerTypeUsage($BTid, $UsedType, $LVer); 1151 $In::ABI{$LVer}{"TypeInfo"}{$TypeId}{"BaseType"} = $BTid; 1152 } 1153 } 1154 else 1155 { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. 1156 $UsedType->{$TypeId} = 1; 1157 } 1158 } 1159} 1160 1161sub detectWordSize($) 1162{ 1163 my $LVer = $_[0]; 1164 1165 my $Size = undef; 1166 1167 # speed up detection 1168 if(my $Arch = $In::ABI{$LVer}{"Arch"}) 1169 { 1170 if($Arch=~/\A(x86_64|s390x|ppc64|ia64|alpha)\Z/) { 1171 $Size = "8"; 1172 } 1173 elsif($Arch=~/\A(x86|s390|ppc32)\Z/) { 1174 $Size = "4"; 1175 } 1176 } 1177 1178 if(my $GccPath = $In::Opt{"GccPath"}) 1179 { 1180 my $TmpDir = $In::Opt{"Tmp"}; 1181 writeFile("$TmpDir/empty.h", ""); 1182 1183 my $Cmd = $GccPath." -E -dD empty.h"; 1184 if(my $Opts = getGccOptions($LVer)) 1185 { # user-defined options 1186 $Cmd .= " ".$Opts; 1187 } 1188 1189 chdir($TmpDir); 1190 my $Defines = `$Cmd`; 1191 chdir($In::Opt{"OrigDir"}); 1192 1193 unlink("$TmpDir/empty.h"); 1194 1195 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/) 1196 { # GCC 4 1197 $Size = $1; 1198 } 1199 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/) 1200 { # GCC 3 1201 my $PTRDIFF = $1; 1202 if($PTRDIFF=~/long/) { 1203 $Size = "8"; 1204 } 1205 else { 1206 $Size = "4"; 1207 } 1208 } 1209 } 1210 1211 if(not $Size) { 1212 exitStatus("Error", "can't check WORD size"); 1213 } 1214 1215 return $Size; 1216} 1217 1218sub getLibPath($$) 1219{ 1220 my ($LVer, $Name) = @_; 1221 if(defined $Cache{"getLibPath"}{$LVer}{$Name}) { 1222 return $Cache{"getLibPath"}{$LVer}{$Name}; 1223 } 1224 return ($Cache{"getLibPath"}{$LVer}{$Name} = getLibPath_I($LVer, $Name)); 1225} 1226 1227sub getLibPath_I($$) 1228{ 1229 my ($LVer, $Name) = @_; 1230 if(isAbsPath($Name)) 1231 { 1232 if(-f $Name) 1233 { # absolute path 1234 return $Name; 1235 } 1236 else 1237 { # broken 1238 return ""; 1239 } 1240 } 1241 if(defined $RegisteredObj{$LVer}{$Name}) 1242 { # registered paths 1243 return $RegisteredObj{$LVer}{$Name}; 1244 } 1245 if(defined $RegisteredSoname{$LVer}{$Name}) 1246 { # registered paths 1247 return $RegisteredSoname{$LVer}{$Name}; 1248 } 1249 if(my $DefaultPath = $In::Opt{"LibDefaultPath"}{$Name}) 1250 { # ldconfig default paths 1251 return $DefaultPath; 1252 } 1253 foreach my $Dir (@{$In::Opt{"DefaultLibPaths"}}, @{$In::Opt{"SysPaths"}{"lib"}}) 1254 { # search in default linker directories 1255 # and then in all system paths 1256 if(-f $Dir."/".$Name) { 1257 return join_P($Dir,$Name); 1258 } 1259 } 1260 1261 checkSystemFiles(); 1262 1263 if(my @AllObjects = keys(%{$In::Opt{"SystemObjects"}{$Name}})) { 1264 return $AllObjects[0]; 1265 } 1266 if(my $ShortName = libPart($Name, "name+ext")) 1267 { 1268 if($ShortName ne $Name) 1269 { # FIXME: check this case 1270 if(my $Path = getLibPath($LVer, $ShortName)) { 1271 return $Path; 1272 } 1273 } 1274 } 1275 # can't find 1276 return ""; 1277} 1278 1279my %Prefix_Lib_Map=( 1280 # symbols for autodetecting library dependencies (by prefix) 1281 "pthread_" => ["libpthread"], 1282 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"], 1283 "cairo_" => ["libcairo"], 1284 "gtk_" => ["libgtk-x11-2.0"], 1285 "atk_" => ["libatk-1.0"], 1286 "gdk_" => ["libgdk-x11-2.0"], 1287 "gl" => ["libGL"], 1288 "glu" => ["libGLU"], 1289 "popt" => ["libpopt"], 1290 "Py" => ["libpython"], 1291 "jpeg_" => ["libjpeg"], 1292 "BZ2_" => ["libbz2"], 1293 "Fc" => ["libfontconfig"], 1294 "Xft" => ["libXft"], 1295 "SSL_" => ["libssl"], 1296 "sem_" => ["libpthread"], 1297 "snd_" => ["libasound"], 1298 "art_" => ["libart_lgpl_2"], 1299 "dbus_g" => ["libdbus-glib-1"], 1300 "GOMP_" => ["libgomp"], 1301 "omp_" => ["libgomp"], 1302 "cms" => ["liblcms"] 1303); 1304 1305my %Pattern_Lib_Map=( 1306 "SL[a-z]" => ["libslang"] 1307); 1308 1309my %Symbol_Lib_Map=( 1310 # symbols for autodetecting library dependencies (by name) 1311 "pow" => "libm", 1312 "fmod" => "libm", 1313 "sin" => "libm", 1314 "floor" => "libm", 1315 "cos" => "libm", 1316 "dlopen" => "libdl", 1317 "deflate" => "libz", 1318 "inflate" => "libz", 1319 "move_panel" => "libpanel", 1320 "XOpenDisplay" => "libX11", 1321 "resize_term" => "libncurses", 1322 "clock_gettime" => "librt", 1323 "crypt" => "libcrypt" 1324); 1325 1326sub find_SymbolLibs($$) 1327{ 1328 my ($LVer, $Symbol) = @_; 1329 1330 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/) 1331 { # debug symbols 1332 return (); 1333 } 1334 1335 my $LibExt = $In::Opt{"Ext"}; 1336 1337 my %Paths = (); 1338 1339 if(my $LibName = $Symbol_Lib_Map{$Symbol}) 1340 { 1341 if(my $Path = getLibPath($LVer, $LibName.".".$LibExt)) { 1342 $Paths{$Path} = 1; 1343 } 1344 } 1345 1346 if(my $SymbolPrefix = getPrefix($Symbol)) 1347 { 1348 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) { 1349 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}}; 1350 } 1351 1352 if(not keys(%Paths)) 1353 { 1354 if(defined $Prefix_Lib_Map{$SymbolPrefix}) 1355 { 1356 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}}) 1357 { 1358 if(my $Path = getLibPath($LVer, $LibName.".".$LibExt)) { 1359 $Paths{$Path} = 1; 1360 } 1361 } 1362 } 1363 } 1364 1365 if(not keys(%Paths)) 1366 { 1367 foreach my $Prefix (sort keys(%Pattern_Lib_Map)) 1368 { 1369 if($Symbol=~/\A$Prefix/) 1370 { 1371 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}}) 1372 { 1373 if(my $Path = getLibPath($LVer, $LibName.".".$LibExt)) { 1374 $Paths{$Path} = 1; 1375 } 1376 } 1377 } 1378 } 1379 } 1380 1381 if(not keys(%Paths)) 1382 { 1383 if($SymbolPrefix) 1384 { # try to find a library by symbol prefix 1385 if($SymbolPrefix eq "inotify" and 1386 index($Symbol, "\@GLIBC")!=-1) 1387 { 1388 if(my $Path = getLibPath($LVer, "libc.$LibExt")) { 1389 $Paths{$Path} = 1; 1390 } 1391 } 1392 else 1393 { 1394 if(my $Path = getLibPathPrefix($LVer, $SymbolPrefix)) { 1395 $Paths{$Path} = 1; 1396 } 1397 } 1398 } 1399 } 1400 1401 if(my @Paths = keys(%Paths)) { 1402 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths; 1403 } 1404 } 1405 return keys(%Paths); 1406} 1407 1408sub getLibPathPrefix($$) 1409{ 1410 my ($LVer, $Prefix) = @_; 1411 my $LibExt = $In::Opt{"Ext"}; 1412 1413 $Prefix = lc($Prefix); 1414 $Prefix=~s/[_]+\Z//g; 1415 1416 foreach ("-2", "2", "-1", "1", "") 1417 { # libgnome-2.so 1418 # libxml2.so 1419 # libdbus-1.so 1420 if(my $Path = getLibPath($LVer, "lib".$Prefix.$_.".".$LibExt)) { 1421 return $Path; 1422 } 1423 } 1424 return ""; 1425} 1426 1427return 1; 1428