1########################################################################### 2# A module to mangle C++ symbols 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 25my %Cache; 26 27my %IntrinsicMangling = ( 28 "void" => "v", 29 "bool" => "b", 30 "wchar_t" => "w", 31 "char" => "c", 32 "signed char" => "a", 33 "unsigned char" => "h", 34 "short" => "s", 35 "unsigned short" => "t", 36 "int" => "i", 37 "unsigned int" => "j", 38 "long" => "l", 39 "unsigned long" => "m", 40 "long long" => "x", 41 "__int64" => "x", 42 "unsigned long long" => "y", 43 "__int128" => "n", 44 "unsigned __int128" => "o", 45 "float" => "f", 46 "double" => "d", 47 "long double" => "e", 48 "__float80" => "e", 49 "__float128" => "g", 50 "..." => "z" 51); 52 53my %StdcxxMangling = ( 54 "3std"=>"St", 55 "3std9allocator"=>"Sa", 56 "3std12basic_string"=>"Sb", 57 "3std12basic_stringIcE"=>"Ss", 58 "3std13basic_istreamIcE"=>"Si", 59 "3std13basic_ostreamIcE"=>"So", 60 "3std14basic_iostreamIcE"=>"Sd" 61); 62 63my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; 64 65my %ConstantSuffixR = ( 66 "u"=>"unsigned int", 67 "l"=>"long", 68 "ul"=>"unsigned long", 69 "ll"=>"long long", 70 "ull"=>"unsigned long long" 71); 72 73my %OperatorMangling = ( 74 "~" => "co", 75 "=" => "aS", 76 "|" => "or", 77 "^" => "eo", 78 "&" => "an",#ad (addr) 79 "==" => "eq", 80 "!" => "nt", 81 "!=" => "ne", 82 "<" => "lt", 83 "<=" => "le", 84 "<<" => "ls", 85 "<<=" => "lS", 86 ">" => "gt", 87 ">=" => "ge", 88 ">>" => "rs", 89 ">>=" => "rS", 90 "()" => "cl", 91 "%" => "rm", 92 "[]" => "ix", 93 "&&" => "aa", 94 "||" => "oo", 95 "*" => "ml",#de (deref) 96 "++" => "pp",# 97 "--" => "mm",# 98 "new" => "nw", 99 "delete" => "dl", 100 "new[]" => "na", 101 "delete[]" => "da", 102 "+=" => "pL", 103 "+" => "pl",#ps (pos) 104 "-" => "mi",#ng (neg) 105 "-=" => "mI", 106 "*=" => "mL", 107 "/=" => "dV", 108 "&=" => "aN", 109 "|=" => "oR", 110 "%=" => "rM", 111 "^=" => "eO", 112 "/" => "dv", 113 "->*" => "pm", 114 "->" => "pt",#rf (ref) 115 "," => "cm", 116 "?" => "qu", 117 "." => "dt", 118 "sizeof"=> "sz"#st 119); 120 121my $MAX_CMD_ARG = 4096; 122my $MAX_CPPFILT_INPUT = 50000; 123my $CPPFILT_SUPPORT_FILE = undef; 124 125my %TrName; 126my %GccMangledName; 127my %MangledName; 128 129my $DisabledUnmangle_MSVC = undef; 130 131sub mangleSymbol($$$) 132{ # mangling for simple methods 133 # see gcc-4.6.0/gcc/cp/mangle.c 134 my ($InfoId, $Compiler, $LVer) = @_; 135 if($Cache{"mangleSymbol"}{$LVer}{$InfoId}{$Compiler}) { 136 return $Cache{"mangleSymbol"}{$LVer}{$InfoId}{$Compiler}; 137 } 138 my $Mangled = ""; 139 if($Compiler eq "GCC") { 140 $Mangled = mangleSymbol_GCC($InfoId, $LVer); 141 } 142 elsif($Compiler eq "MSVC") { 143 $Mangled = mangleSymbol_MSVC($InfoId, $LVer); 144 } 145 return ($Cache{"mangleSymbol"}{$LVer}{$InfoId}{$Compiler} = $Mangled); 146} 147 148sub mangleSymbol_MSVC($$) 149{ # TODO 150 my ($InfoId, $LVer) = @_; 151 return ""; 152} 153 154sub mangleSymbol_GCC($$) 155{ # see gcc-4.6.0/gcc/cp/mangle.c 156 my ($InfoId, $LVer) = @_; 157 158 my $SInfo = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}; 159 160 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, ""); 161 162 my $Return = $SInfo->{"Return"}; 163 my %Repl = (); # SN_ replacements 164 if($ClassId = $SInfo->{"Class"}) 165 { 166 my $MangledClass = mangleParam($ClassId, $LVer, \%Repl); 167 if($MangledClass!~/\AN/) { 168 $MangledClass = "N".$MangledClass; 169 } 170 else { 171 $MangledClass=~s/E\Z//; 172 } 173 if($SInfo->{"Const"}) { 174 $MangledClass=~s/\AN/NK/; 175 } 176 if($SInfo->{"Volatile"}) { 177 $MangledClass=~s/\AN/NV/; 178 } 179 $Mangled .= $MangledClass; 180 } 181 elsif($NameSpace = $SInfo->{"NameSpace"}) 182 { # mangled by name due to the absence of structured info 183 my $MangledNS = mangleNs($NameSpace, $LVer, \%Repl); 184 if($MangledNS!~/\AN/) { 185 $MangledNS = "N".$MangledNS; 186 } 187 else { 188 $MangledNS=~s/E\Z//; 189 } 190 $Mangled .= $MangledNS; 191 } 192 my ($ShortName, $TmplParams) = templateBase($SInfo->{"ShortName"}); 193 my @TParams = (); 194 if(my @TPos = sort {$a<=>$b} keys(%{$SInfo->{"TParam"}})) 195 { # parsing mode 196 foreach my $PPos (@TPos) { 197 push(@TParams, $SInfo->{"TParam"}{$PPos}{"name"}); 198 } 199 } 200 elsif($TmplParams) 201 { # remangling mode 202 # support for old ABI dumps 203 @TParams = sepParams($TmplParams, 0, 0); 204 } 205 if(my $Ctor = $SInfo->{"Constructor"}) 206 { 207 if($Ctor ne "1") { 208 $Mangled .= $Ctor; 209 } 210 else { 211 $Mangled .= "C1"; 212 } 213 } 214 elsif(my $Dtor = $SInfo->{"Destructor"}) 215 { 216 if($Dtor ne "1") { 217 $Mangled .= $Dtor; 218 } 219 else { 220 $Mangled .= "D0"; 221 } 222 } 223 elsif($ShortName) 224 { 225 if($SInfo->{"Data"}) 226 { 227 if(not $SInfo->{"Class"} 228 and isConstType($Return, $LVer)) 229 { # "const" global data is mangled as _ZL... 230 $Mangled .= "L"; 231 } 232 } 233 if($ShortName=~/\Aoperator(\W.*)\Z/) 234 { 235 my $Op = $1; 236 $Op=~s/\A[ ]+//g; 237 if(my $OpMngl = $OperatorMangling{$Op}) { 238 $Mangled .= $OpMngl; 239 } 240 else { # conversion operator 241 $Mangled .= "cv".mangleParam(getTypeIdByName($Op, $LVer), $LVer, \%Repl); 242 } 243 } 244 else { 245 $Mangled .= length($ShortName).$ShortName; 246 } 247 if(@TParams) 248 { # templates 249 $Mangled .= "I"; 250 foreach my $TParam (@TParams) { 251 $Mangled .= mangleTemplateParam($TParam, $LVer, \%Repl); 252 } 253 $Mangled .= "E"; 254 } 255 if(not $ClassId and @TParams) { 256 addSubst($ShortName, \%Repl, 0); 257 } 258 } 259 if($ClassId or $NameSpace) { 260 $Mangled .= "E"; 261 } 262 if(@TParams) 263 { 264 if($Return) { 265 $Mangled .= mangleParam($Return, $LVer, \%Repl); 266 } 267 } 268 if(not $SInfo->{"Data"}) 269 { 270 my @Params = (); 271 if(defined $SInfo->{"Param"} 272 and not $SInfo->{"Destructor"}) 273 { 274 @Params = sort {$a<=>$b} keys(%{$SInfo->{"Param"}}); 275 276 if($SInfo->{"Class"} 277 and not $SInfo->{"Static"}) 278 { 279 if($SInfo->{"Param"}{"0"}{"name"} eq "this") { 280 shift(@Params); 281 } 282 } 283 } 284 foreach my $PPos (sort {$a<=>$b} @Params) 285 { # checking parameters 286 my $PTid = $SInfo->{"Param"}{$PPos}{"type"}; 287 $Mangled .= mangleParam($PTid, $LVer, \%Repl); 288 } 289 if(not @Params) { 290 $Mangled .= "v"; 291 } 292 } 293 $Mangled = writeCxxSubstitution($Mangled); 294 if($Mangled eq "_Z") { 295 return ""; 296 } 297 return $Mangled; 298} 299 300sub templateBase($) 301{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl 302 # NOTE: operators: >>, << 303 my $Name = $_[0]; 304 if($Name!~/>\Z/ or $Name!~/</) { 305 return $Name; 306 } 307 my $TParams = $Name; 308 while(my $CPos = findCenter($TParams, "<")) 309 { # search for the last <T> 310 $TParams = substr($TParams, $CPos); 311 } 312 if($TParams=~s/\A<(.+)>\Z/$1/) { 313 $Name=~s/<\Q$TParams\E>\Z//; 314 } 315 else 316 { # error 317 $TParams = ""; 318 } 319 return ($Name, $TParams); 320} 321 322sub getSubNs($) 323{ 324 my $Name = $_[0]; 325 my @NS = (); 326 while(my $CPos = findCenter($Name, ":")) 327 { 328 push(@NS, substr($Name, 0, $CPos)); 329 $Name = substr($Name, $CPos); 330 $Name=~s/\A:://; 331 } 332 return (join("::", @NS), $Name); 333} 334 335sub mangleNs($$$) 336{ 337 my ($Name, $LVer, $Repl) = @_; 338 if(my $Tid = $In::ABI{$LVer}{"TName_Tid"}{$Name}) 339 { 340 my $Mangled = mangleParam($Tid, $LVer, $Repl); 341 $Mangled=~s/\AN(.+)E\Z/$1/; 342 return $Mangled; 343 344 } 345 else 346 { 347 my ($MangledNS, $SubNS) = ("", ""); 348 ($SubNS, $Name) = getSubNs($Name); 349 if($SubNS) { 350 $MangledNS .= mangleNs($SubNS, $LVer, $Repl); 351 } 352 $MangledNS .= length($Name).$Name; 353 addSubst($MangledNS, $Repl, 0); 354 return $MangledNS; 355 } 356} 357 358sub mangleParam($$$) 359{ 360 my ($PTid, $LVer, $Repl) = @_; 361 my ($MPrefix, $Mangled) = ("", ""); 362 my %ReplCopy = %{$Repl}; 363 my %BaseType = getBaseType($PTid, $LVer); 364 my $BaseType_Name = $BaseType{"Name"}; 365 $BaseType_Name=~s/\A(struct|union|enum) //g; 366 if(not $BaseType_Name) { 367 return ""; 368 } 369 my ($ShortName, $TmplParams) = templateBase($BaseType_Name); 370 my $Suffix = getBaseTypeQual($PTid, $LVer); 371 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){}; 372 while($Suffix=~/(&|\*|const)\Z/) 373 { 374 if($Suffix=~s/[ ]*&\Z//) { 375 $MPrefix .= "R"; 376 } 377 if($Suffix=~s/[ ]*\*\Z//) { 378 $MPrefix .= "P"; 379 } 380 if($Suffix=~s/[ ]*const\Z//) 381 { 382 if($MPrefix=~/R|P/ 383 or $Suffix=~/&|\*/) { 384 $MPrefix .= "K"; 385 } 386 } 387 if($Suffix=~s/[ ]*volatile\Z//) { 388 $MPrefix .= "V"; 389 } 390 #if($Suffix=~s/[ ]*restrict\Z//) { 391 #$MPrefix .= "r"; 392 #} 393 } 394 if(my $Token = $IntrinsicMangling{$BaseType_Name}) { 395 $Mangled .= $Token; 396 } 397 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/) 398 { 399 my @TParams = (); 400 if(my @TPos = sort {$a<=>$b} keys(%{$BaseType{"TParam"}})) 401 { # parsing mode 402 foreach (@TPos) { 403 push(@TParams, $BaseType{"TParam"}{$_}{"name"}); 404 } 405 } 406 elsif($TmplParams) 407 { # remangling mode 408 # support for old ABI dumps 409 @TParams = sepParams($TmplParams, 0, 0); 410 } 411 my $MangledNS = ""; 412 my ($SubNS, $SName) = getSubNs($ShortName); 413 if($SubNS) { 414 $MangledNS .= mangleNs($SubNS, $LVer, $Repl); 415 } 416 $MangledNS .= length($SName).$SName; 417 if(@TParams) { 418 addSubst($MangledNS, $Repl, 0); 419 } 420 $Mangled .= "N".$MangledNS; 421 if(@TParams) 422 { # templates 423 $Mangled .= "I"; 424 foreach my $TParam (@TParams) { 425 $Mangled .= mangleTemplateParam($TParam, $LVer, $Repl); 426 } 427 $Mangled .= "E"; 428 } 429 $Mangled .= "E"; 430 } 431 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/) 432 { 433 if($BaseType{"Type"} eq "MethodPtr") { 434 $Mangled .= "M".mangleParam($BaseType{"Class"}, $LVer, $Repl)."F"; 435 } 436 else { 437 $Mangled .= "PF"; 438 } 439 $Mangled .= mangleParam($BaseType{"Return"}, $LVer, $Repl); 440 my @Params = sort {$a<=>$b} keys(%{$BaseType{"Param"}}); 441 foreach my $Num (@Params) { 442 $Mangled .= mangleParam($BaseType{"Param"}{$Num}{"type"}, $LVer, $Repl); 443 } 444 if(not @Params) { 445 $Mangled .= "v"; 446 } 447 $Mangled .= "E"; 448 } 449 elsif($BaseType{"Type"} eq "FieldPtr") 450 { 451 $Mangled .= "M".mangleParam($BaseType{"Class"}, $LVer, $Repl); 452 $Mangled .= mangleParam($BaseType{"Return"}, $LVer, $Repl); 453 } 454 $Mangled = $MPrefix.$Mangled; # add prefix (RPK) 455 if(my $Optimized = writeSubstitution($Mangled, \%ReplCopy)) 456 { 457 if($Mangled eq $Optimized) 458 { 459 if($ShortName!~/::/) 460 { # remove "N ... E" 461 if($MPrefix) { 462 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g; 463 } 464 else { 465 $Mangled=~s/\AN(.+)E\Z/$1/g; 466 } 467 } 468 } 469 else { 470 $Mangled = $Optimized; 471 } 472 } 473 addSubst($Mangled, $Repl, 1); 474 return $Mangled; 475} 476 477sub mangleTemplateParam($$$) 478{ # types + literals 479 my ($TParam, $LVer, $Repl) = @_; 480 if(my $TPTid = $In::ABI{$LVer}{"TName_Tid"}{$TParam}) { 481 return mangleParam($TPTid, $LVer, $Repl); 482 } 483 elsif($TParam=~/\A(\d+)(\w+)\Z/) 484 { # class_name<1u>::method(...) 485 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E"; 486 } 487 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/) 488 { # class_name<(signed char)1>::method(...) 489 return "L".$IntrinsicMangling{$1}.$2."E"; 490 } 491 elsif($TParam eq "true") 492 { # class_name<true>::method(...) 493 return "Lb1E"; 494 } 495 elsif($TParam eq "false") 496 { # class_name<true>::method(...) 497 return "Lb0E"; 498 } 499 else { # internal error 500 return length($TParam).$TParam; 501 } 502} 503 504sub addSubst($$$) 505{ 506 my ($Value, $Repl, $Rec) = @_; 507 if($Rec) 508 { # subtypes 509 my @Subs = ($Value); 510 while($Value=~s/\A(R|P|K)//) { 511 push(@Subs, $Value); 512 } 513 foreach (reverse(@Subs)) { 514 addSubst($_, $Repl, 0); 515 } 516 return; 517 } 518 if($Value=~/\AS(\d*)_\Z/) { 519 return; 520 } 521 $Value=~s/\AN(.+)E\Z/$1/g; 522 if(defined $Repl->{$Value}) { 523 return; 524 } 525 if(length($Value)<=1) { 526 return; 527 } 528 if($StdcxxMangling{$Value}) { 529 return; 530 } 531 # check for duplicates 532 my $Base = $Value; 533 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 534 { 535 my $Num = $Repl->{$Type}; 536 my $Replace = macroMangle($Num); 537 $Base=~s/\Q$Replace\E/$Type/; 538 } 539 if(my $OldNum = $Repl->{$Base}) 540 { 541 $Repl->{$Value} = $OldNum; 542 return; 543 } 544 my @Repls = sort {$b<=>$a} values(%{$Repl}); 545 if(@Repls) { 546 $Repl->{$Value} = $Repls[0]+1; 547 } 548 else { 549 $Repl->{$Value} = -1; 550 } 551 # register duplicates 552 # upward 553 $Base = $Value; 554 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) 555 { 556 if($Base eq $Type) { 557 next; 558 } 559 my $Num = $Repl->{$Type}; 560 my $Replace = macroMangle($Num); 561 $Base=~s/\Q$Type\E/$Replace/; 562 $Repl->{$Base} = $Repl->{$Value}; 563 } 564} 565 566sub macroMangle($) 567{ 568 my $Num = $_[0]; 569 if($Num==-1) { 570 return "S_"; 571 } 572 else 573 { 574 my $Code = ""; 575 if($Num<10) 576 { # S0_, S1_, S2_, ... 577 $Code = $Num; 578 } 579 elsif($Num>=10 and $Num<=35) 580 { # SA_, SB_, SC_, ... 581 $Code = chr(55+$Num); 582 } 583 else 584 { # S10_, S11_, S12_ 585 $Code = $Num-26; # 26 is length of english alphabet 586 } 587 return "S".$Code."_"; 588 } 589} 590 591sub writeCxxSubstitution($) 592{ 593 my $Mangled = $_[0]; 594 if($StdcxxMangling{$Mangled}) { 595 return $StdcxxMangling{$Mangled}; 596 } 597 else 598 { 599 my @Repls = sort {$b cmp $a} keys(%StdcxxMangling); 600 @Repls = sort {length($b)<=>length($a)} @Repls; 601 foreach my $MangledType (@Repls) 602 { 603 my $Replace = $StdcxxMangling{$MangledType}; 604 #if($Mangled!~/$Replace/) { 605 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 606 $Mangled=~s/\Q$MangledType\E/$Replace/g; 607 #} 608 } 609 } 610 return $Mangled; 611} 612 613sub writeSubstitution($$) 614{ 615 my ($Mangled, $Repl) = @_; 616 if(defined $Repl->{$Mangled} 617 and my $MnglNum = $Repl->{$Mangled}) { 618 $Mangled = macroMangle($MnglNum); 619 } 620 else 621 { 622 my @Repls = keys(%{$Repl}); 623 624 # @Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls; 625 # FIXME: how to apply replacements? by num or by pos 626 627 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; 628 foreach my $MangledType (@Repls) 629 { 630 my $Replace = macroMangle($Repl->{$MangledType}); 631 if($Mangled!~/$Replace/) { 632 $Mangled=~s/N\Q$MangledType\EE/$Replace/g; 633 $Mangled=~s/\Q$MangledType\E/$Replace/g; 634 } 635 } 636 } 637 return $Mangled; 638} 639 640sub isDefaultStd($) { 641 return ($_[0]=~/\A$DEFAULT_STD_PARMS\</); 642} 643 644sub canonifyName($$) 645{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*) 646 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*) 647 my ($Name, $Type) = @_; 648 649 # single 650 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3) 651 { 652 my $P = $1; 653 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g; 654 } 655 656 # double 657 if($Name=~/$DEFAULT_STD_PARMS/) 658 { 659 if($Type eq "S") 660 { 661 my ($ShortName, $FuncParams) = splitSignature($Name); 662 663 foreach my $FParam (sepParams($FuncParams, 0, 0)) 664 { 665 if(index($FParam, "<")!=-1) 666 { 667 $FParam=~s/>([^<>]+)\Z/>/; # remove quals 668 my $FParam_N = canonifyName($FParam, "T"); 669 if($FParam_N ne $FParam) { 670 $Name=~s/\Q$FParam\E/$FParam_N/g; 671 } 672 } 673 } 674 } 675 elsif($Type eq "T") 676 { 677 my ($ShortTmpl, $TmplParams) = templateBase($Name); 678 679 my @TParams = sepParams($TmplParams, 0, 0); 680 if($#TParams>=1) 681 { 682 my $FParam = $TParams[0]; 683 foreach my $Pos (1 .. $#TParams) 684 { 685 my $TParam = $TParams[$Pos]; 686 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) { 687 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g; 688 } 689 } 690 } 691 } 692 } 693 if($Type eq "S") { 694 return formatName($Name, "S"); 695 } 696 return $Name; 697} 698 699sub getUnmangled($$) 700{ 701 if(defined $TrName{$_[1]}{$_[0]}) { 702 return $TrName{$_[1]}{$_[0]}; 703 } 704 705 return undef; 706} 707 708sub getMangled_GCC($$) 709{ 710 if(defined $GccMangledName{$_[1]}{$_[0]}) { 711 return $GccMangledName{$_[1]}{$_[0]}; 712 } 713 714 return undef; 715} 716 717sub getMangled_MSVC($$) 718{ 719 if(defined $MangledName{$_[1]}{$_[0]}) { 720 return $MangledName{$_[1]}{$_[0]}; 721 } 722 723 return $_[0]; 724} 725 726sub translateSymbols(@) 727{ 728 my $LVer = pop(@_); 729 my (@MnglNames1, @MnglNames2, @ZNames, @UnmangledNames) = (); 730 my %Versioned = (); 731 732 foreach my $Symbol (sort @_) 733 { 734 if(index($Symbol, "_Z")==0) 735 { 736 push(@ZNames, $Symbol); 737 if($TrName{$LVer}{$Symbol}) 738 { # already unmangled 739 next; 740 } 741 if($Symbol=~s/([\@\$]+.*)\Z//) { 742 $Versioned{$Symbol}{$Symbol.$1} = 1; 743 } 744 else { 745 $Versioned{$Symbol}{$Symbol} = 1; 746 } 747 push(@MnglNames1, $Symbol); 748 } 749 elsif(index($Symbol, "?")==0) 750 { 751 push(@MnglNames2, $Symbol); 752 } 753 } 754 if($#MnglNames1 > -1) 755 { # GCC names 756 @UnmangledNames = reverse(unmangleArray(@MnglNames1)); 757 foreach my $MnglName (@MnglNames1) 758 { 759 if(my $Unmangled = pop(@UnmangledNames)) 760 { 761 foreach my $M (keys(%{$Versioned{$MnglName}})) 762 { 763 $TrName{$LVer}{$M} = canonifyName($Unmangled, "S"); 764 if(not $GccMangledName{$LVer}{$TrName{$LVer}{$M}}) { 765 $GccMangledName{$LVer}{$TrName{$LVer}{$M}} = $M; 766 } 767 } 768 } 769 } 770 771 foreach my $Symbol (@ZNames) 772 { 773 if(index($Symbol, "_ZTV")==0 774 and $TrName{$LVer}{$Symbol}=~/vtable for (.+)/) 775 { # bind class name and v-table symbol 776 $In::ABI{$LVer}{"ClassVTable"}{$1} = $Symbol; 777 } 778 } 779 } 780 if($#MnglNames2 > -1) 781 { # MSVC names 782 @UnmangledNames = reverse(unmangleArray(@MnglNames2)); 783 foreach my $MnglName (@MnglNames2) 784 { 785 if(my $Unmangled = pop(@UnmangledNames)) 786 { 787 $TrName{$LVer}{$MnglName} = formatName($Unmangled, "S"); 788 $MangledName{$LVer}{$TrName{$LVer}{$MnglName}} = $MnglName; 789 } 790 } 791 } 792 return \%{$TrName{$LVer}}; 793} 794 795sub unmangleArray(@) 796{ 797 if($_[0]=~/\A\?/) 798 { # MSVC mangling 799 if(defined $DisabledUnmangle_MSVC) { 800 return @_; 801 } 802 my $UndNameCmd = getCmdPath("undname"); 803 if(not $UndNameCmd) 804 { 805 if($In::Opt{"OS"} eq "windows") { 806 exitStatus("Not_Found", "can't find \"undname\""); 807 } 808 elsif(not defined $DisabledUnmangle_MSVC) 809 { 810 printMsg("WARNING", "can't find \"undname\", disable MSVC unmangling"); 811 $DisabledUnmangle_MSVC = 1; 812 return @_; 813 } 814 } 815 my $TmpDir = $In::Opt{"Tmp"}; 816 writeFile("$TmpDir/unmangle", join("\n", @_)); 817 return split(/\n/, `$UndNameCmd 0x8386 \"$TmpDir/unmangle\"`); 818 } 819 else 820 { # GCC mangling 821 my $CppFiltCmd = getCmdPath("c++filt"); 822 if(not $CppFiltCmd) { 823 exitStatus("Not_Found", "can't find c++filt in PATH"); 824 } 825 if(not defined $CPPFILT_SUPPORT_FILE) 826 { 827 my $Info = `$CppFiltCmd -h 2>&1`; 828 $CPPFILT_SUPPORT_FILE = ($Info=~/\@<file>/); 829 } 830 my $NoStrip = ""; 831 832 if($In::Opt{"OS"}=~/macos|windows/) { 833 $NoStrip = "-n"; 834 } 835 836 if($CPPFILT_SUPPORT_FILE) 837 { # new versions of c++filt can take a file 838 if($#_>$MAX_CPPFILT_INPUT) 839 { # c++filt <= 2.22 may crash on large files (larger than 8mb) 840 # this is fixed in the oncoming version of Binutils 841 my @Half = splice(@_, 0, ($#_+1)/2); 842 return (unmangleArray(@Half), unmangleArray(@_)) 843 } 844 else 845 { 846 my $TmpDir = $In::Opt{"Tmp"}; 847 writeFile("$TmpDir/unmangle", join("\n", @_)); 848 my $Res = `$CppFiltCmd $NoStrip \@\"$TmpDir/unmangle\"`; 849 if($?==139) 850 { # segmentation fault 851 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant"); 852 } 853 return split(/\n/, $Res); 854 } 855 } 856 else 857 { # old-style unmangling 858 if($#_>$MAX_CMD_ARG) 859 { 860 my @Half = splice(@_, 0, ($#_+1)/2); 861 return (unmangleArray(@Half), unmangleArray(@_)) 862 } 863 else 864 { 865 my $Strings = join(" ", @_); 866 my $Res = `$CppFiltCmd $NoStrip $Strings`; 867 if($?==139) 868 { # segmentation fault 869 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant"); 870 } 871 return split(/\n/, $Res); 872 } 873 } 874 } 875} 876 877sub debugMangling($) 878{ 879 my $LVer = $_[0]; 880 881 printMsg("INFO", "Debug model mangling and unmangling ($LVer)"); 882 883 my %Mangled = (); 884 foreach my $InfoId (keys(%{$In::ABI{$LVer}{"SymbolInfo"}})) 885 { 886 my $SInfo = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}; 887 888 if(my $Mngl = $SInfo->{"MnglName"}) 889 { 890 if(my $Class = $SInfo->{"Class"}) 891 { 892 if(defined $In::ABI{$LVer}{"TypeInfo"}{$Class}{"TParam"}) 893 { # mngl names are not equal because of default tmpl args 894 next; 895 } 896 897 if(index($In::ABI{$LVer}{"TypeInfo"}{$Class}{"Name"}, "...")!=-1) 898 { # no info about tmpl args 899 next; 900 } 901 } 902 903 if($Mngl=~/\A(_Z|\?)/) { 904 $Mangled{$Mngl} = $InfoId; 905 } 906 } 907 } 908 909 translateSymbols(keys(%Mangled), $LVer); 910 911 my $Total = keys(%Mangled); 912 my ($GoodMangling, $GoodUnmangling) = (0, 0); 913 914 foreach my $Mngl (sort keys(%Mangled)) 915 { 916 my $InfoId = $Mangled{$Mngl}; 917 918 my $U1 = getUnmangled($Mngl, $LVer); 919 my $U2 = modelUnmangled($InfoId, "GCC", $LVer); 920 my $U3 = mangleSymbol($InfoId, "GCC", $LVer); 921 922 if($U1 ne $U2) { 923 printMsg("INFO", "Bad model unmangling:\n Orig: $Mngl\n Unmgl: $U1\n Model: $U2\n"); 924 } 925 else { 926 $GoodUnmangling += 1; 927 } 928 929 if($Mngl ne $U3) { 930 printMsg("INFO", "Bad model mangling:\n Orig: $Mngl\n Model: $U3\n"); 931 } 932 else { 933 $GoodMangling += 1; 934 } 935 } 936 937 printMsg("INFO", "Model unmangling: $GoodUnmangling/$Total"); 938 printMsg("INFO", "Model mangling: $GoodMangling/$Total"); 939} 940 941sub modelUnmangled($$$) 942{ 943 my ($InfoId, $Compiler, $LVer) = @_; 944 if($Cache{"modelUnmangled"}{$LVer}{$Compiler}{$InfoId}) { 945 return $Cache{"modelUnmangled"}{$LVer}{$Compiler}{$InfoId}; 946 } 947 948 my $SInfo = $In::ABI{$LVer}{"SymbolInfo"}{$InfoId}; 949 950 my $PureSignature = $SInfo->{"ShortName"}; 951 if($SInfo->{"Destructor"}) { 952 $PureSignature = "~".$PureSignature; 953 } 954 if(not $SInfo->{"Data"}) 955 { 956 my (@Params, @ParamTypes) = (); 957 if(defined $SInfo->{"Param"} 958 and not $SInfo->{"Destructor"}) 959 { 960 @Params = sort {$a<=>$b} keys(%{$SInfo->{"Param"}}); 961 962 if($SInfo->{"Class"} 963 and not $SInfo->{"Static"}) 964 { 965 if($SInfo->{"Param"}{"0"}{"name"} eq "this") { 966 shift(@Params); 967 } 968 } 969 } 970 foreach my $ParamPos (@Params) 971 { # checking parameters 972 my $PTid = $SInfo->{"Param"}{$ParamPos}{"type"}; 973 my $PTName = $In::ABI{$LVer}{"TypeInfo"}{$PTid}{"Name"}; 974 975 $PTName = unmangledFormat($PTName, $LVer); 976 $PTName=~s/\b(restrict|register)\b//g; 977 978 if($Compiler eq "MSVC") { 979 $PTName=~s/\blong long\b/__int64/; 980 } 981 @ParamTypes = (@ParamTypes, $PTName); 982 } 983 if(@ParamTypes) { 984 $PureSignature .= "(".join(", ", @ParamTypes).")"; 985 } 986 else 987 { 988 if($Compiler eq "MSVC") { 989 $PureSignature .= "(void)"; 990 } 991 else 992 { # GCC 993 $PureSignature .= "()"; 994 } 995 } 996 $PureSignature = deleteKeywords($PureSignature); 997 } 998 if(my $ClassId = $SInfo->{"Class"}) 999 { 1000 my $ClassName = unmangledFormat($In::ABI{$LVer}{"TypeInfo"}{$ClassId}{"Name"}, $LVer); 1001 $PureSignature = $ClassName."::".$PureSignature; 1002 } 1003 elsif(my $NS = $SInfo->{"NameSpace"}) { 1004 $PureSignature = $NS."::".$PureSignature; 1005 } 1006 if($SInfo->{"Const"}) { 1007 $PureSignature .= " const"; 1008 } 1009 if($SInfo->{"Volatile"}) { 1010 $PureSignature .= " volatile"; 1011 } 1012 my $ShowReturn = 0; 1013 if($Compiler eq "MSVC" 1014 and $SInfo->{"Data"}) { 1015 $ShowReturn = 1; 1016 } 1017 elsif(index($SInfo->{"ShortName"}, "<")!=-1) 1018 { # template instance 1019 $ShowReturn = 1; 1020 } 1021 if($ShowReturn) 1022 { # mangled names for template function specializations include return type 1023 if(my $ReturnId = $SInfo->{"Return"}) 1024 { 1025 my %RType = getPureType($ReturnId, $LVer); 1026 my $ReturnName = unmangledFormat($RType{"Name"}, $LVer); 1027 $PureSignature = $ReturnName." ".$PureSignature; 1028 } 1029 } 1030 return ($Cache{"modelUnmangled"}{$LVer}{$Compiler}{$InfoId} = formatName($PureSignature, "S")); 1031} 1032 1033sub unmangledFormat($$) 1034{ 1035 my ($Name, $LibVersion) = @_; 1036 $Name = uncoverTypedefs($Name, $LibVersion); 1037 while($Name=~s/([^\w>])(const|volatile)(,|>|\Z)/$1$3/g){}; 1038 $Name=~s/\(\w+\)(\d)/$1/; 1039 return $Name; 1040} 1041 1042sub isConstType($$) 1043{ 1044 my ($TypeId, $LVer) = @_; 1045 my %Base = getType($TypeId, $LVer); 1046 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { 1047 %Base = getOneStepBaseType($Base{"Tid"}, $LVer); 1048 } 1049 return ($Base{"Type"} eq "Const"); 1050} 1051 1052return 1; 1053