abi-dumper.pl revision 99c7c2ea0f0b5ccefa76185eeb751e3ebd30cee6
1#!/usr/bin/perl
2###########################################################################
3# ABI Dumper 0.99.3
4# Dump ABI of an ELF object containing DWARF debug info
5#
6# Copyright (C) 2013 ROSA Laboratory
7#
8# Written by Andrey Ponomarenko
9#
10# PLATFORMS
11# =========
12#  Linux, FreeBSD
13#
14# REQUIREMENTS
15# ============
16#  Elfutils (eu-readelf)
17#  Perl 5 (5.8 or newer)
18#  Vtable-Dumper (1.0 or newer)
19#
20# COMPATIBILITY
21# =============
22#  ABI Compliance Checker >= 1.99.8
23#
24#
25# This program is free software: you can redistribute it and/or modify
26# it under the terms of the GNU General Public License or the GNU Lesser
27# General Public License as published by the Free Software Foundation.
28#
29# This program is distributed in the hope that it will be useful,
30# but WITHOUT ANY WARRANTY; without even the implied warranty of
31# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32# GNU General Public License for more details.
33#
34# You should have received a copy of the GNU General Public License
35# and the GNU Lesser General Public License along with this program.
36# If not, see <http://www.gnu.org/licenses/>.
37###########################################################################
38use Getopt::Long;
39Getopt::Long::Configure ("posix_default", "no_ignore_case", "permute");
40use File::Path qw(mkpath rmtree);
41use File::Temp qw(tempdir);
42use Cwd qw(abs_path cwd realpath);
43use Storable qw(dclone);
44use Data::Dumper;
45
46my $TOOL_VERSION = "0.99.3";
47my $ABI_DUMP_VERSION = "3.2";
48my $ORIG_DIR = cwd();
49my $TMP_DIR = tempdir(CLEANUP=>1);
50
51my $VTABLE_DUMPER = "vtable-dumper";
52my $VTABLE_DUMPER_VERSION = "1.0";
53
54my ($Help, $ShowVersion, $DumpVersion, $OutputDump, $SortDump, $StdOut,
55$TargetVersion, $ExtraInfo, $FullDump, $AllTypes, $AllSymbols, $BinOnly,
56$SkipCxx, $Loud, $AddrToName, $DumpStatic, $Compare, $AltDebugInfo);
57
58my $CmdName = get_filename($0);
59
60my %ERROR_CODE = (
61    "Success"=>0,
62    "Error"=>2,
63    # System command is not found
64    "Not_Found"=>3,
65    # Cannot access input files
66    "Access_Error"=>4,
67    # Cannot find a module
68    "Module_Error"=>9,
69    # No debug-info
70    "No_DWARF"=>10,
71    # Invalid debug-info
72    "Invalid_DWARF"=>11
73);
74
75my $ShortUsage = "ABI Dumper $TOOL_VERSION
76Dump ABI of an ELF object containing DWARF debug info
77Copyright (C) 2013 ROSA Laboratory
78License: GNU LGPL or GNU GPL
79
80Usage: $CmdName [options] [object]
81Example:
82  $CmdName libTest.so -o ABI.dump
83  $CmdName Module.ko.debug -o ABI.dump
84
85More info: $CmdName --help\n";
86
87if($#ARGV==-1)
88{
89    printMsg("INFO", $ShortUsage);
90    exit(0);
91}
92
93GetOptions("h|help!" => \$Help,
94  "v|version!" => \$ShowVersion,
95  "dumpversion!" => \$DumpVersion,
96# general options
97  "o|output|dump-path=s" => \$OutputDump,
98  "sort!" => \$SortDump,
99  "stdout!" => \$StdOut,
100  "loud!" => \$Loud,
101  "lver|lv=s" => \$TargetVersion,
102  "extra-info=s" => \$ExtraInfo,
103  "all-types!" => \$AllTypes,
104  "all-symbols!" => \$AllSymbols,
105  "skip-cxx!" => \$SkipCxx,
106  "all!" => \$FullDump,
107  "bin-only!" => \$BinOnly,
108  "dump-static!" => \$DumpStatic,
109  "compare!" => \$Compare,
110  "alt=s" => \$AltDebugInfo,
111# internal options
112  "addr2name!" => \$AddrToName
113) or ERR_MESSAGE();
114
115sub ERR_MESSAGE()
116{
117    printMsg("INFO", "\n".$ShortUsage);
118    exit($ERROR_CODE{"Error"});
119}
120
121my $HelpMessage="
122NAME:
123  ABI Dumper ($CmdName)
124  Dump ABI of an ELF object containing DWARF debug info
125
126DESCRIPTION:
127  ABI Dumper is a tool for dumping ABI information of an ELF object
128  containing DWARF debug info.
129
130  The tool is intended to be used with ABI Compliance Checker tool for tracking
131  ABI changes of a C/C++ library or kernel module.
132
133  This tool is free software: you can redistribute it and/or modify it
134  under the terms of the GNU LGPL or GNU GPL.
135
136USAGE:
137  $CmdName [options] [object]
138
139EXAMPLES:
140  $CmdName libTest.so -o ABI.dump
141  $CmdName Module.ko.debug -o ABI.dump
142
143INFORMATION OPTIONS:
144  -h|-help
145      Print this help.
146
147  -v|-version
148      Print version information.
149
150  -dumpversion
151      Print the tool version ($TOOL_VERSION) and don't do anything else.
152
153GENERAL OPTIONS:
154  -o|-output PATH
155      Path to the output ABI dump file.
156      Default: ./ABI.dump
157
158  -sort
159      Sort data in ABI dump.
160
161  -stdout
162      Print ABI dump to stdout.
163
164  -loud
165      Print all warnings.
166
167  -lv|-lver NUM
168      Set version of the library to NUM.
169
170  -extra-info DIR
171      Dump extra analysis info to DIR.
172
173  -bin-only
174      Do not dump information about inline functions,
175      pure virtual functions and non-exported global data.
176
177  -all-types
178      Dump unused data types.
179
180  -all-symbols
181      Dump symbols not exported by the object.
182
183  -skip-cxx
184      Do not dump stdc++ and gnu c++ symbols.
185
186  -all
187      Equal to: -all-types -all-symbols.
188
189  -dump-static
190      Dump static (local) symbols.
191
192  -compare OLD.dump NEW.dump
193      Show added/removed symbols between two ABI dumps.
194";
195
196sub HELP_MESSAGE() {
197    printMsg("INFO", $HelpMessage);
198}
199
200my %Cache;
201
202# Input
203my %DWARF_Info;
204
205# Alternate
206my %ImportedUnit;
207
208# Output
209my %SymbolInfo;
210my %TypeInfo;
211
212# Reader
213my %TypeMember;
214my %ArrayCount;
215my %FuncParam;
216my %Inheritance;
217my %NameSpace;
218my %SpecElem;
219my %ClassMethods;
220my %TypeSpec;
221my %ClassChild;
222
223my %MergedTypes;
224my %LocalType;
225
226my %SourceFile;
227my %DebugLoc;
228my %TName_Tid;
229my %TName_Tids;
230my %RegName;
231
232my $STDCXX_TARGET = 0;
233my $GLOBAL_ID = 0;
234
235my %Mangled_ID;
236my %Checked_Spec;
237my %SelectedSymbols;
238
239my %TypeType = (
240    "class_type"=>"Class",
241    "structure_type"=>"Struct",
242    "union_type"=>"Union",
243    "enumeration_type"=>"Enum",
244    "array_type"=>"Array",
245    "base_type"=>"Intrinsic",
246    "const_type"=>"Const",
247    "pointer_type"=>"Pointer",
248    "reference_type"=>"Ref",
249    "volatile_type"=>"Volatile",
250    "typedef"=>"Typedef",
251    "ptr_to_member_type"=>"FieldPtr"
252);
253
254my %Qual = (
255    "Pointer"=>"*",
256    "Ref"=>"&",
257    "Volatile"=>"volatile",
258    "Const"=>"const"
259);
260
261my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
262my $SRC_EXT = "c|cpp|cxx|c\\+\\+";
263
264# Other
265my %NestedNameSpaces;
266my $TargetName;
267my %SysInfo;
268my %HeadersInfo;
269my %SourcesInfo;
270my %SymVer;
271my %UsedType;
272
273# ELF
274my %Library_Symbol;
275my %Library_UndefSymbol;
276my %Library_Needed;
277my %SymbolTable;
278my %SectionInfo;
279
280# VTables
281my %VirtualTable;
282
283# Env
284my $SYS_ARCH;
285my $SYS_WORD;
286my $SYS_GCCV;
287my $SYS_COMP;
288
289my $LIB_LANG;
290
291sub printMsg($$)
292{
293    my ($Type, $Msg) = @_;
294    if($Type!~/\AINFO/) {
295        $Msg = $Type.": ".$Msg;
296    }
297    if($Type!~/_C\Z/) {
298        $Msg .= "\n";
299    }
300    if($Type eq "ERROR") {
301        print STDERR $Msg;
302    }
303    else {
304        print $Msg;
305    }
306}
307
308sub exitStatus($$)
309{
310    my ($Code, $Msg) = @_;
311    printMsg("ERROR", $Msg);
312    exit($ERROR_CODE{$Code});
313}
314
315sub cmpVersions($$)
316{ # compare two versions in dotted-numeric format
317    my ($V1, $V2) = @_;
318    return 0 if($V1 eq $V2);
319    return undef if($V1!~/\A\d+[\.\d+]*\Z/);
320    return undef if($V2!~/\A\d+[\.\d+]*\Z/);
321    my @V1Parts = split(/\./, $V1);
322    my @V2Parts = split(/\./, $V2);
323    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
324        return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
325        return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
326    }
327    return -1 if($#V1Parts < $#V2Parts);
328    return 1 if($#V1Parts > $#V2Parts);
329    return 0;
330}
331
332sub writeFile($$)
333{
334    my ($Path, $Content) = @_;
335    return if(not $Path);
336    if(my $Dir = get_dirname($Path)) {
337        mkpath($Dir);
338    }
339    open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
340    print FILE $Content;
341    close(FILE);
342}
343
344sub readFile($)
345{
346    my $Path = $_[0];
347    return "" if(not $Path or not -f $Path);
348    open(FILE, $Path);
349    local $/ = undef;
350    my $Content = <FILE>;
351    close(FILE);
352    return $Content;
353}
354
355sub get_filename($)
356{ # much faster than basename() from File::Basename module
357    if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
358        return $1;
359    }
360    return "";
361}
362
363sub get_dirname($)
364{ # much faster than dirname() from File::Basename module
365    if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
366        return $1;
367    }
368    return "";
369}
370
371sub check_Cmd($)
372{
373    my $Cmd = $_[0];
374    return "" if(not $Cmd);
375    if(defined $Cache{"check_Cmd"}{$Cmd}) {
376        return $Cache{"check_Cmd"}{$Cmd};
377    }
378    foreach my $Path (sort {length($a)<=>length($b)} split(/:/, $ENV{"PATH"}))
379    {
380        if(-x $Path."/".$Cmd) {
381            return ($Cache{"check_Cmd"}{$Cmd} = 1);
382        }
383    }
384    return ($Cache{"check_Cmd"}{$Cmd} = 0);
385}
386
387my %ELF_BIND = map {$_=>1} (
388    "WEAK",
389    "GLOBAL",
390    "LOCAL"
391);
392
393my %ELF_TYPE = map {$_=>1} (
394    "FUNC",
395    "IFUNC",
396    "OBJECT",
397    "COMMON"
398);
399
400my %ELF_VIS = map {$_=>1} (
401    "DEFAULT",
402    "PROTECTED"
403);
404
405sub readline_ELF($)
406{ # read the line of 'eu-readelf' output corresponding to the symbol
407    my @Info = split(/\s+/, $_[0]);
408    #  Num:   Value      Size Type   Bind   Vis       Ndx  Name
409    #  3629:  000b09c0   32   FUNC   GLOBAL DEFAULT   13   _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
410    #  135:   00000000    0   FUNC   GLOBAL DEFAULT   UNDEF  av_image_fill_pointers@LIBAVUTIL_52 (3)
411    shift(@Info) if($Info[0] eq ""); # spaces
412    shift(@Info); # num
413
414    if($#Info==7)
415    { # UNDEF SYMBOL (N)
416        if($Info[7]=~/\(\d+\)/) {
417            pop(@Info);
418        }
419    }
420
421    if($#Info!=6)
422    { # other lines
423        return ();
424    }
425    return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UNDEF");
426    return () if(not defined $ELF_BIND{$Info[3]});
427    return () if(not defined $ELF_VIS{$Info[4]});
428    if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
429    { # 1272: 00000000     0 OBJECT  GLOBAL DEFAULT  ABS CXXABI_1.3
430        return ();
431    }
432    if(index($Info[2], "0x") == 0)
433    { # size == 0x3d158
434        $Info[2] = hex($Info[2]);
435    }
436    return @Info;
437}
438
439sub read_Symbols($)
440{
441    my $Lib_Path = $_[0];
442    my $Lib_Name = get_filename($Lib_Path);
443
444    my $Dynamic = ($Lib_Name=~/\.so(\.|\Z)/);
445    my $Dbg = ($Lib_Name=~/\.debug\Z/);
446
447    my $Readelf = "eu-readelf";
448    if(not check_Cmd($Readelf)) {
449        exitStatus("Not_Found", "can't find \"eu-readelf\"");
450    }
451
452    my $Cmd = $Readelf." -S \"$Lib_Path\" 2>\"$TMP_DIR/error\"";
453    foreach (split(/\n/, `$Cmd`))
454    {
455        if(/\[\s*(\d+)\]\s+([\w\.]+)/)
456        {
457            $SectionInfo{$1} = $2;
458        }
459    }
460
461    if($Dynamic)
462    { # dynamic library specifics
463        $Cmd = $Readelf." -d \"$Lib_Path\" 2>\"$TMP_DIR/error\"";
464        foreach (split(/\n/, `$Cmd`))
465        {
466            if(/NEEDED.+\[([^\[\]]+)\]/)
467            { # dependencies:
468              # 0x00000001 (NEEDED) Shared library: [libc.so.6]
469                $Library_Needed{$1} = 1;
470            }
471        }
472    }
473
474    my $ExtraPath = "";
475
476    if($ExtraInfo)
477    {
478        $ExtraPath = $ExtraInfo."/".$Lib_Name;
479        mkpath($ExtraPath);
480        $ExtraPath .= "/elf-info";
481    }
482
483    $Cmd = $Readelf." -s \"$Lib_Path\" 2>\"$TMP_DIR/error\"";
484
485    if($ExtraPath)
486    { # debug mode
487        # write to file
488        system($Cmd." >\"$ExtraPath\"");
489        open(LIB, $ExtraPath);
490    }
491    else
492    { # write to pipe
493        open(LIB, $Cmd." |");
494    }
495
496    my (%Symbol_Value, %Value_Symbol) = ();
497
498    my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
499    while(<LIB>)
500    {
501        if($Dynamic and not $Dbg)
502        { # dynamic library specifics
503            if(defined $symtab)
504            {
505                if(index($_, "'.dynsym'")!=-1)
506                { # dynamic table
507                    $symtab = undef;
508                }
509                if(not $AllSymbols)
510                { # do nothing with symtab
511                    next;
512                }
513            }
514            elsif(index($_, "'.symtab'")!=-1)
515            { # symbol table
516                $symtab = 1;
517                next;
518            }
519        }
520        if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
521        { # read ELF entry
522            if(not $symtab)
523            {
524                if(skipSymbol($Symbol)) {
525                    next;
526                }
527
528                if($Ndx eq "UNDEF")
529                { # ignore interfaces that are imported from somewhere else
530                    $Library_UndefSymbol{$TargetName}{$Symbol} = 0;
531                    next;
532                }
533
534                $Library_Symbol{$TargetName}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
535
536                $Symbol_Value{$Symbol} = $Value;
537                $Value_Symbol{$Value}{$Symbol} = 1;
538            }
539
540            foreach ($SectionInfo{$Ndx}, "")
541            {
542                my $Val = $Value;
543
544                $SymbolTable{$_}{$Val}{$Symbol} = 1;
545
546                if($Val=~s/\A[0]+//)
547                {
548                    if($Val eq "") {
549                        $Val = "0";
550                    }
551                    $SymbolTable{$_}{$Val}{$Symbol} = 1;
552                }
553            }
554        }
555    }
556    close(LIB);
557
558    my %Found = ();
559    foreach my $Symbol (keys(%{$Library_Symbol{$TargetName}}))
560    {
561        next if(index($Symbol,"\@")==-1);
562        if(my $Value = $Symbol_Value{$Symbol})
563        {
564            foreach my $Symbol_SameValue (keys(%{$Value_Symbol{$Value}}))
565            {
566                if($Symbol_SameValue ne $Symbol
567                and index($Symbol_SameValue,"\@")==-1)
568                {
569                    $SymVer{$Symbol_SameValue} = $Symbol;
570                    $Found{$Symbol} = 1;
571                    last;
572                }
573            }
574        }
575    }
576
577    # default
578    foreach my $Symbol (keys(%{$Library_Symbol{$TargetName}}))
579    {
580        next if(defined $Found{$Symbol});
581        next if(index($Symbol,"\@\@")==-1);
582
583        if($Symbol=~/\A([^\@]*)\@\@/
584        and not $SymVer{$1})
585        {
586            $SymVer{$1} = $Symbol;
587            $Found{$Symbol} = 1;
588        }
589    }
590
591    # non-default
592    foreach my $Symbol (keys(%{$Library_Symbol{$TargetName}}))
593    {
594        next if(defined $Found{$Symbol});
595        next if(index($Symbol,"\@")==-1);
596
597        if($Symbol=~/\A([^\@]*)\@([^\@]*)/
598        and not $SymVer{$1})
599        {
600            $SymVer{$1} = $Symbol;
601            $Found{$Symbol} = 1;
602        }
603    }
604}
605
606sub read_Alt_Info($)
607{
608    my $Path = $_[0];
609    my $Name = get_filename($Path);
610
611    my $Readelf = "eu-readelf";
612    if(not check_Cmd($Readelf)) {
613        exitStatus("Not_Found", "can't find \"$Readelf\" command");
614    }
615
616    printMsg("INFO", "Reading alternate debug-info");
617
618    my $ExtraPath = undef;
619
620    if($ExtraInfo)
621    {
622        $ExtraPath = $ExtraInfo."/".$Name;
623        mkpath($ExtraPath);
624        $ExtraPath .= "/debug_info";
625    }
626
627    if($ExtraPath)
628    {
629        system("$Readelf -N --debug-dump=info \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
630        open(INFO, $ExtraPath);
631    }
632    else {
633        open(INFO, "$Readelf -N --debug-dump=info \"$Path\" 2>\"$TMP_DIR/error\" |");
634    }
635
636    my $ID = undef;
637    my $Num = 0;
638
639    while(<INFO>)
640    {
641
642        if(/\[\s*(\w+?)\]  (\w+)/)
643        {
644            if($2 eq "partial_unit")
645            {
646                $ID = $1;
647                $Num = 0;
648                $ImportedUnit{$ID}{0} = $_;
649            }
650            else {
651                $ID = undef;
652            }
653        }
654        elsif(defined $ID)
655        {
656            if(not /\A \w/) {
657                $ImportedUnit{$ID}{$Num++} = $_;
658            }
659        }
660    }
661}
662
663sub read_DWARF_Info($)
664{
665    my $Path = $_[0];
666
667    my $Dir = get_dirname($Path);
668    my $Name = get_filename($Path);
669
670    my $Readelf = "eu-readelf";
671    if(not check_Cmd($Readelf)) {
672        exitStatus("Not_Found", "can't find \"$Readelf\" command");
673    }
674
675    my $AddOpt = "";
676    if(not defined $AddrToName)
677    { # disable search of symbol names
678        $AddOpt .= " -N";
679    }
680
681    my $Sect = `$Readelf -S \"$Path\" 2>\"$TMP_DIR/error\"`;
682
683    if($Sect!~/\.debug_info/)
684    { # No DWARF info
685        return 0;
686    }
687
688    printMsg("INFO", "Reading debug-info");
689
690    my $ExtraPath = "";
691
692    # ELF header
693    if($ExtraInfo)
694    {
695        $ExtraPath = $ExtraInfo."/".$Name;
696        mkpath($ExtraPath);
697        $ExtraPath .= "/elf-header";
698    }
699
700    if($ExtraPath)
701    {
702        system($Readelf." -h \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
703        open(HEADER, $ExtraPath);
704    }
705    else {
706        open(HEADER, $Readelf." -h \"$Path\" 2>\"$TMP_DIR/error\" |");
707    }
708
709    my %Header = ();
710    while(<HEADER>)
711    {
712        if(/\A\s*([\w ]+?)\:\s*(.+?)\Z/) {
713            $Header{$1} = $2;
714        }
715    }
716    close(HEADER);
717
718    $SYS_ARCH = $Header{"Machine"};
719
720    if($SYS_ARCH=~/80\d86/
721    or $SYS_ARCH=~/i\d86/)
722    { # i386, i586, etc.
723        $SYS_ARCH = "x86";
724    }
725
726    if($SYS_ARCH=~/amd64/i
727    or $SYS_ARCH=~/x86\-64/i)
728    { # amd64
729        $SYS_ARCH = "x86_64";
730    }
731
732    # source info
733    if($ExtraInfo)
734    {
735        $ExtraPath = $ExtraInfo."/".$Name;
736        mkpath($ExtraPath);
737        $ExtraPath .= "/debug_line";
738    }
739
740    if($ExtraPath)
741    {
742        system("$Readelf $AddOpt --debug-dump=line \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
743        open(SRC, $ExtraPath);
744    }
745    else {
746        open(SRC, "$Readelf $AddOpt --debug-dump=line \"$Path\" 2>\"$TMP_DIR/error\" |");
747    }
748
749    my $Offset = undef;
750
751    while(<SRC>)
752    {
753        if(/Table at offset (\w+)/)
754        {
755            $Offset = $1;
756        }
757        elsif(defined $Offset
758        and /(\d+)\s+\d+\s+\d+\s+\d+\s+([^ ]+)/)
759        {
760            my ($Num, $File) = ($1, $2);
761            chomp($File);
762
763            $SourceFile{$Offset}{$Num} = $File;
764
765            if($File=~/\.($HEADER_EXT)\Z/) {
766                $HeadersInfo{$File} = 1;
767            }
768            elsif($File ne "<built-in>") {
769                $SourcesInfo{$File} = 1;
770            }
771        }
772    }
773    close(SRC);
774
775    # debug_loc
776    if($ExtraInfo)
777    {
778        $ExtraPath = $ExtraInfo."/".$Name;
779        mkpath($ExtraPath);
780        $ExtraPath .= "/debug_loc";
781    }
782
783    if($ExtraPath)
784    {
785        system("$Readelf $AddOpt --debug-dump=loc \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
786        open(LOC, $ExtraPath);
787    }
788    else {
789        open(LOC, "$Readelf $AddOpt --debug-dump=loc \"$Path\" 2>\"$TMP_DIR/error\" |");
790    }
791
792    while(<LOC>)
793    {
794        if(/\[\s*(\w+)\].*\[\s*\w+\]\s*(.+)\Z/) {
795            $DebugLoc{$1} = $2;
796        }
797    }
798    close(LOC);
799
800    # dwarf
801    if($ExtraInfo)
802    {
803        $ExtraPath = $ExtraInfo."/".$Name;
804        mkpath($ExtraPath);
805        $ExtraPath .= "/debug_info";
806    }
807
808    if($Dir)
809    { # to find ".dwz" directory (Fedora)
810        chdir($Dir);
811    }
812    if($ExtraPath)
813    {
814        system("$Readelf $AddOpt --debug-dump=info \"$Name\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
815        open(INFO, $ExtraPath);
816    }
817    else {
818        open(INFO, "$Readelf $AddOpt --debug-dump=info \"$Name\" 2>\"$TMP_DIR/error\" |");
819    }
820    chdir($ORIG_DIR);
821
822    my %TypeUnit = ();
823    my %Post_Change = ();
824    my $TypeUnit_Sign = undef;
825    my $TypeUnit_Offset = undef;
826    my $Type_Offset = undef;
827
828    my $Shift_Enabled = 1;
829    my $ID_Shift = undef;
830
831
832    my $CUnit = undef;
833    my $CUnit_F = undef;
834
835    my $ID = undef;
836    my $Kind = undef;
837    my $NS = undef;
838
839    my $MAX_ID = undef;
840
841    my %Shift = map {$_=>1} (
842        "specification",
843        "type",
844        "sibling",
845        "object_pointer",
846        "containing_type",
847        "abstract_origin",
848        "import",
849        "signature"
850    );
851
852    my $Line = undef;
853    my $Import = undef;
854    my $Import_Num = 0;
855
856    while(($Import and $Line = $ImportedUnit{$Import}{$Import_Num}) or $Line = <INFO>)
857    {
858        if(not defined $ImportedUnit{$Import}{$Import_Num})
859        {
860            $Import_Num = 0;
861            delete($ImportedUnit{$Import});
862            $Import = undef;
863        }
864
865        if($Import) {
866            $Import_Num++;
867        }
868        if($ID and $Line=~/\A\s*(\w+)\s*(.+?)\s*\Z/)
869        {
870            my ($Attr, $Val) = ($1, $2);
871
872            if($Kind eq "imported_unit")
873            {
874                if($Attr eq "import")
875                {
876                    if($Val=~/\(GNU_ref_alt\)\s*\[\s*(\w+?)\]/)
877                    {
878                        if(defined $ImportedUnit{$1})
879                        {
880                            $Import = $1;
881                            $Import_Num = 0;
882                        }
883                    }
884                }
885            }
886
887            if($Attr eq "Type")
888            {
889                if($Line=~/Type\s+signature:\s*0x(\w+)/) {
890                    $TypeUnit_Sign = $1;
891                }
892                if($Line=~/Type\s+offset:\s*0x(\w+)/) {
893                    $Type_Offset = hex($1);
894                }
895                if($Line=~/Type\s+unit\s+at\s+offset\s+(\d+)/) {
896                    $TypeUnit_Offset = $1;
897                }
898                next;
899            }
900
901            if($Attr eq "encoding")
902            { # unused
903                next;
904            }
905
906            if($Val=~/\A\s*\(([^()]*)\)\s*\[\s*(\w+)\]\s*\Z/)
907            { # ref4, ref_udata, ref_addr, etc.
908                $Val = hex($2);
909
910                if($1 eq "GNU_ref_alt")
911                {
912                    $Val = -$Val;
913                }
914            }
915            elsif($Attr eq "name")
916            {
917                $Val=~s/\A\([^()]*\)\s*\"(.*)\"\Z/$1/;
918            }
919            elsif(index($Attr, "linkage_name")!=-1)
920            {
921                $Val=~s/\A\([^()]*\)\s*\"(.*)\"\Z/$1/;
922                $Attr = "linkage_name";
923            }
924            elsif(index($Attr, "location")!=-1)
925            {
926                if($Val=~/\)\s*\Z/)
927                { # value on the next line
928                    $Val .= <INFO>;
929                }
930
931                if($Val=~/\A\(\w+\)\s*(-?)(\w+)\Z/)
932                { # (data1) 1c
933                    $Val = hex($2);
934                    if($1) {
935                        $Val = -$Val;
936                    }
937                }
938                else
939                {
940                    if($Val=~/ (-?\d+)\Z/) {
941                        $Val = $1;
942                    }
943                    else
944                    {
945                        if($Attr eq "location"
946                        and $Kind eq "formal_parameter")
947                        {
948                            if($Val=~/location list\s+\[\s*(\w+)\]\Z/)
949                            {
950                                $Attr = "location_list";
951                                $Val = $1;
952                            }
953                            elsif($Val=~/ reg(\d+)\Z/)
954                            {
955                                $Attr = "register";
956                                $Val = $1;
957                            }
958                        }
959                    }
960                }
961            }
962            elsif($Attr eq "accessibility")
963            {
964                $Val=~s/\A\(.+?\)\s*//;
965                $Val=~s/\s*\(.+?\)\Z//;
966                if($Val eq "public") {
967                    next;
968                }
969            }
970            else
971            {
972                $Val=~s/\A\(\w+\)\s*//;
973
974                if(substr($Val, 0, 1) eq "{"
975                and $Val=~/{(.+)}/)
976                { # {ID}
977                    $Val = $1;
978                    $Post_Change{$ID} = 1;
979                }
980            }
981
982            if($Shift_Enabled and $ID_Shift)
983            {
984                if(defined $Shift{$Attr}
985                and not $Post_Change{$ID}) {
986                    $Val += $ID_Shift;
987                }
988
989                $DWARF_Info{$ID}{"rID"} = $ID-$ID_Shift;
990            }
991
992            if($Import)
993            {
994                if(defined $Shift{$Attr})
995                {
996                    $Val = -$Val;
997                }
998            }
999
1000            $DWARF_Info{$ID}{$Attr} = "$Val";
1001
1002            if($Kind eq "compile_unit")
1003            {
1004                if($Attr eq "stmt_list") {
1005                    $CUnit = $Val;
1006                }
1007
1008                if(not defined $CUnit_F) {
1009                    $CUnit_F = $ID;
1010                }
1011            }
1012
1013            if($Kind eq "type_unit")
1014            {
1015                if($Attr eq "stmt_list") {
1016                    $CUnit = $Val;
1017                }
1018            }
1019
1020            if($Kind eq "partial_unit")
1021            { # support for dwz
1022                if($Attr eq "stmt_list") {
1023                    $CUnit = $Val;
1024                }
1025            }
1026        }
1027        elsif($Line=~/\A\s{0,4}\[\s*(\w+)\](\s*)(\w+)/)
1028        {
1029            $ID = hex($1);
1030            $NS = $2;
1031            $Kind = $3;
1032
1033            if($Import)
1034            {
1035                $ID = -$ID;
1036            }
1037
1038            if($Shift_Enabled)
1039            {
1040                if($Kind eq "type_unit")
1041                {
1042                    if(not defined $ID_Shift)
1043                    {
1044                        if($ID_Shift<=$MAX_ID) {
1045                            $ID_Shift = $MAX_ID;
1046                        }
1047                        else {
1048                            $ID_Shift = 0;
1049                        }
1050                    }
1051                }
1052
1053                if($ID_Shift) {
1054                    $ID += $ID_Shift;
1055                }
1056            }
1057
1058            if(defined $TypeUnit_Sign)
1059            {
1060                if($Kind ne "type_unit"
1061                and $Kind ne "namespace")
1062                {
1063                    if($TypeUnit_Offset+$Type_Offset+$ID_Shift==$ID)
1064                    {
1065                        $TypeUnit{$TypeUnit_Sign} = "$ID";
1066                        $TypeUnit_Sign = undef;
1067                    }
1068                }
1069            }
1070
1071            $DWARF_Info{$ID}{"Kind"} = $Kind;
1072            $DWARF_Info{$ID}{"NS"} = length($NS);
1073
1074
1075            if(defined $CUnit) {
1076                $DWARF_Info{$ID}{"CompUnit"} = $CUnit;
1077            }
1078
1079            if(not defined $ID_Shift) {
1080                $MAX_ID = $ID;
1081            }
1082        }
1083        elsif(not defined $SYS_WORD
1084        and $Line=~/Address\s*size:\s*(\d+)/i)
1085        {
1086            $SYS_WORD = $1;
1087        }
1088    }
1089    close(INFO);
1090
1091    if(my $Err = readFile("$TMP_DIR/error"))
1092    { # eu-readelf: cannot get next DIE: invalid DWARF
1093        if($Err=~/invalid DWARF/i) {
1094            exitStatus("Invalid_DWARF", "invalid DWARF info");
1095        }
1096    }
1097
1098    foreach my $ID (keys(%Post_Change))
1099    {
1100        if(my $Type = $DWARF_Info{$ID}{"type"})
1101        {
1102            if(my $To = $TypeUnit{$Type}) {
1103                $DWARF_Info{$ID}{"type"} = $To;
1104            }
1105        }
1106        if(my $Signature = $DWARF_Info{$ID}{"signature"})
1107        {
1108            if(my $To = $TypeUnit{$Signature}) {
1109                $DWARF_Info{$ID}{"signature"} = $To;
1110            }
1111        }
1112    }
1113
1114    %TypeUnit = ();
1115    %Post_Change = ();
1116
1117    if(defined $CUnit_F)
1118    {
1119        if(my $Compiler= $DWARF_Info{$CUnit_F}{"producer"})
1120        {
1121            $Compiler=~s/\A\"//;
1122            $Compiler=~s/\"\Z//;
1123
1124            if($Compiler=~/GNU\s+(C|C\+\+)\s+(.+)\Z/)
1125            {
1126                $SYS_GCCV = $2;
1127                $SYS_GCCV=~s/\d+\s+\(.+\).*//; # 4.6.1 20110627 (Mandriva)
1128            }
1129            else {
1130                $SYS_COMP = $Compiler;
1131            }
1132        }
1133        if(my $Lang = $DWARF_Info{$CUnit_F}{"language"})
1134        {
1135            $Lang=~s/\s*\(.+?\)\Z//;
1136            if($Lang=~/C\d/i) {
1137                $LIB_LANG = "C";
1138            }
1139            elsif($Lang=~/C\+\+/i) {
1140                $LIB_LANG = "C++";
1141            }
1142            else {
1143                $LIB_LANG = $Lang;
1144            }
1145        }
1146    }
1147
1148    return 1;
1149}
1150
1151sub read_Vtables($)
1152{
1153    my $Path = $_[0];
1154
1155    my $Name = get_filename($Path);
1156    $Path = abs_path($Path);
1157
1158
1159    if(index($LIB_LANG, "C++")!=-1)
1160    {
1161        if(check_Cmd($VTABLE_DUMPER))
1162        {
1163            if(my $Version = `$VTABLE_DUMPER -dumpversion`)
1164            {
1165                if(cmpVersions($Version, $VTABLE_DUMPER_VERSION)<0)
1166                {
1167                    printMsg("ERROR", "the version of Vtable-Dumper should be $VTABLE_DUMPER_VERSION or newer");
1168                    return;
1169                }
1170            }
1171        }
1172        else
1173        {
1174            printMsg("ERROR", "cannot find \'$VTABLE_DUMPER\'");
1175            return;
1176        }
1177
1178        my $ExtraPath = $TMP_DIR."/v-tables";
1179
1180        if($ExtraInfo)
1181        {
1182            $ExtraPath = $ExtraInfo."/".$Name;
1183            mkpath($ExtraPath);
1184            $ExtraPath .= "/v-tables";
1185        }
1186
1187        system("$VTABLE_DUMPER \"$Path\" 2>\"$TMP_DIR/error\" >\"$ExtraPath\"");
1188
1189        my $Content = readFile($ExtraPath);
1190        foreach my $ClassInfo (split(/\n\n\n/, $Content))
1191        {
1192            if($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
1193            {
1194                my ($CName, $VTable) = ($1, $2);
1195                my @Entries = split(/\n/, $VTable);
1196                foreach (1 .. $#Entries)
1197                {
1198                    my $Entry = $Entries[$_];
1199                    if($Entry=~/\A(\d+)\s+(.+)\Z/) {
1200                        $VirtualTable{$CName}{$1} = $2;
1201                    }
1202                }
1203            }
1204        }
1205    }
1206}
1207
1208sub dump_ABI()
1209{
1210    printMsg("INFO", "Creating ABI dump");
1211
1212    my %ABI = (
1213        "TypeInfo" => \%TypeInfo,
1214        "SymbolInfo" => \%SymbolInfo,
1215        "Symbols" => \%Library_Symbol,
1216        "UndefinedSymbols" => \%Library_UndefSymbol,
1217        "Needed" => \%Library_Needed,
1218        "SymbolVersion" => \%SymVer,
1219        "LibraryVersion" => $TargetVersion,
1220        "LibraryName" => $TargetName,
1221        "Language" => $LIB_LANG,
1222        "Headers" => \%HeadersInfo,
1223        "Sources" => \%SourcesInfo,
1224        "NameSpaces" => \%NestedNameSpaces,
1225        "Target" => "unix",
1226        "Arch" => $SYS_ARCH,
1227        "WordSize" => $SYS_WORD,
1228        "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
1229        "ABI_DUMPER_VERSION" => $TOOL_VERSION,
1230    );
1231
1232    if($SYS_GCCV) {
1233        $ABI{"GccVersion"} = $SYS_GCCV;
1234    }
1235    else {
1236        $ABI{"Compiler"} = $SYS_COMP;
1237    }
1238
1239    my $ABI_DUMP = Dumper(\%ABI);
1240
1241    if($StdOut)
1242    { # --stdout option
1243        print STDOUT $ABI_DUMP;
1244    }
1245    else
1246    {
1247        mkpath(get_dirname($OutputDump));
1248
1249        open(DUMP, ">", $OutputDump) || die ("can't open file \'$OutputDump\': $!\n");
1250        print DUMP $ABI_DUMP;
1251        close(DUMP);
1252
1253        printMsg("INFO", "\nThe object ABI has been dumped to:\n  $OutputDump");
1254    }
1255}
1256
1257sub unmangleString($)
1258{
1259    my $Str = $_[0];
1260
1261    $Str=~s/\AN(.+)E\Z/$1/;
1262    while($Str=~s/\A(\d+)//)
1263    {
1264        if(length($Str)==$1) {
1265            last;
1266        }
1267
1268        $Str = substr($Str, $1, length($Str) - $1);
1269    }
1270
1271    return $Str;
1272}
1273
1274sub read_ABI()
1275{
1276    printMsg("INFO", "Extracting ABI information");
1277
1278    my %CurID = ();
1279
1280    my @IDs = sort {int($a) <=> int($b)} keys(%DWARF_Info);
1281
1282    if($AltDebugInfo) {
1283        @IDs = sort {$b>0 <=> $a>0} sort {abs(int($a)) <=> abs(int($b))} @IDs;
1284    }
1285
1286    foreach my $ID (@IDs)
1287    {
1288        $ID = "$ID";
1289
1290        my $Kind = $DWARF_Info{$ID}{"Kind"};
1291        my $NS = $DWARF_Info{$ID}{"NS"};
1292        my $Scope = $CurID{$NS-2};
1293
1294        my $IsType = ($Kind=~/(struct|structure|class|union|enumeration|subroutine|array)_type/);
1295
1296        if($IsType
1297        or $Kind eq "typedef"
1298        or $Kind eq "subprogram"
1299        or $Kind eq "inlined_subroutine"
1300        or $Kind eq "lexical_block"
1301        or $Kind eq "variable"
1302        or $Kind eq "namespace")
1303        {
1304            if($Kind ne "variable"
1305            and $Kind ne "typedef")
1306            {
1307                $CurID{$NS} = $ID;
1308            }
1309
1310            if($Scope)
1311            {
1312                $NameSpace{$ID} = $Scope;
1313                if($Kind eq "subprogram"
1314                or $Kind eq "variable")
1315                {
1316                    if($DWARF_Info{$Scope}{"Kind"}=~/class|struct/)
1317                    {
1318                        $ClassMethods{$Scope}{$ID} = 1;
1319                        if(my $Sp = $DWARF_Info{$Scope}{"specification"}) {
1320                            $ClassMethods{$Sp}{$ID} = 1;
1321                        }
1322                    }
1323                }
1324            }
1325
1326            if(my $Spec = $DWARF_Info{$ID}{"specification"}) {
1327                $SpecElem{$Spec} = $ID;
1328            }
1329
1330            if($IsType)
1331            {
1332                if(not $DWARF_Info{$ID}{"name"}
1333                and $DWARF_Info{$ID}{"linkage_name"}) {
1334                    $DWARF_Info{$ID}{"name"} = unmangleString($DWARF_Info{$ID}{"linkage_name"});
1335                }
1336            }
1337        }
1338        elsif($Kind eq "member")
1339        {
1340            if($Scope)
1341            {
1342                $NameSpace{$ID} = $Scope;
1343
1344                if($DWARF_Info{$Scope}{"Kind"}=~/class|struct/
1345                and not defined $DWARF_Info{$ID}{"data_member_location"})
1346                { # variable (global data)
1347                    next;
1348                }
1349            }
1350
1351            $TypeMember{$Scope}{keys(%{$TypeMember{$Scope}})} = $ID;
1352        }
1353        elsif($Kind eq "enumerator")
1354        {
1355            $TypeMember{$Scope}{keys(%{$TypeMember{$Scope}})} = $ID;
1356        }
1357        elsif($Kind eq "inheritance")
1358        {
1359            my %In = (
1360                "id" => $DWARF_Info{$ID}{"type"},
1361                "access" => $DWARF_Info{$ID}{"accessibility"}
1362            );
1363            if(defined $DWARF_Info{$ID}{"virtuality"}) {
1364                $In{"virtual"} = 1;
1365            }
1366            $Inheritance{$Scope}{keys(%{$Inheritance{$Scope}})} = \%In;
1367        }
1368        elsif($Kind eq "formal_parameter")
1369        {
1370            $FuncParam{$Scope}{keys(%{$FuncParam{$Scope}})} = $ID;
1371        }
1372        elsif($Kind eq "unspecified_parameters")
1373        {
1374            $FuncParam{$Scope}{keys(%{$FuncParam{$Scope}})} = $ID;
1375            $DWARF_Info{$ID}{"type"} = "-1"; # "..."
1376        }
1377        elsif($Kind eq "subrange_type")
1378        {
1379            if((my $Bound = $DWARF_Info{$ID}{"upper_bound"}) ne "") {
1380                $ArrayCount{$Scope} = $Bound + 1;
1381            }
1382        }
1383    }
1384
1385    # register "void" type
1386    %{$TypeInfo{"1"}} = (
1387        "Name"=>"void",
1388        "Type"=>"Intrinsic"
1389    );
1390    $TName_Tid{"Intrinsic"}{"void"} = "1";
1391    $TName_Tids{"Intrinsic"}{"void"}{"1"} = 1;
1392    $Cache{"getTypeInfo"}{"1"} = 1;
1393
1394    # register "..." type
1395    %{$TypeInfo{"-1"}} = (
1396        "Name"=>"...",
1397        "Type"=>"Intrinsic"
1398    );
1399    $TName_Tid{"Intrinsic"}{"..."} = "-1";
1400    $TName_Tids{"Intrinsic"}{"..."}{"-1"} = 1;
1401    $Cache{"getTypeInfo"}{"-1"} = 1;
1402
1403    my @IDs = sort {int($a) <=> int($b)} keys(%DWARF_Info);
1404
1405    if($AltDebugInfo) {
1406        @IDs = sort {$b>0 <=> $a>0} sort {abs(int($a)) <=> abs(int($b))} @IDs;
1407    }
1408
1409    foreach my $ID (@IDs)
1410    {
1411        if(my $Kind = $DWARF_Info{$ID}{"Kind"})
1412        {
1413            if(defined $TypeType{$Kind}) {
1414                getTypeInfo($ID);
1415            }
1416        }
1417    }
1418
1419    foreach my $Tid (sort {int($a) <=> int($b)} keys(%TypeInfo))
1420    {
1421        my $Type = $TypeInfo{$Tid}{"Type"};
1422
1423        if(not defined $TypeInfo{$Tid}{"Memb"})
1424        {
1425            if($Type=~/Struct|Class|Union|Enum/)
1426            {
1427                if(my $Signature = $DWARF_Info{$Tid}{"signature"})
1428                {
1429                    if(defined $TypeInfo{$Signature})
1430                    {
1431                        foreach my $Attr (keys(%{$TypeInfo{$Signature}}))
1432                        {
1433                            if(not defined $TypeInfo{$Tid}{$Attr}) {
1434                                $TypeInfo{$Tid}{$Attr} = $TypeInfo{$Signature}{$Attr};
1435                            }
1436                        }
1437                    }
1438                }
1439            }
1440        }
1441    }
1442
1443    my %Incomplete = ();
1444    my %Incomplete_TN = ();
1445
1446    my @IDs = sort {int($a) <=> int($b)} keys(%TypeInfo);
1447
1448    if($AltDebugInfo) {
1449        @IDs = sort {$b>0 <=> $a>0} sort {abs(int($a)) <=> abs(int($b))} @IDs;
1450    }
1451
1452    foreach my $Tid (@IDs)
1453    {
1454        my $Name = $TypeInfo{$Tid}{"Name"};
1455        my $Type = $TypeInfo{$Tid}{"Type"};
1456
1457        if(not defined $SpecElem{$Tid}
1458        and not defined $Incomplete_TN{$Type}{$Name})
1459        {
1460            if(not defined $TypeInfo{$Tid}{"Size"})
1461            {
1462                if($Type=~/Struct|Class|Union|Enum/)
1463                {
1464                    $Incomplete{$Tid} = 1;
1465                }
1466            }
1467        }
1468
1469        $Incomplete_TN{$Type}{$Name} = 1;
1470    }
1471
1472    foreach my $Tid (sort {int($a) <=> int($b)} keys(%Incomplete))
1473    {
1474        my $Name = $TypeInfo{$Tid}{"Name"};
1475        my $Type = $TypeInfo{$Tid}{"Type"};
1476
1477        my @Adv_IDs = sort {int($a) <=> int($b)} keys(%{$TName_Tids{$Type}{$Name}});
1478
1479        if($AltDebugInfo) {
1480            @Adv_IDs = sort {$b>0 <=> $a>0} sort {abs(int($a)) <=> abs(int($b))} @Adv_IDs;
1481        }
1482
1483        foreach my $Tid_Adv (@Adv_IDs)
1484        {
1485            if($Tid_Adv!=$Tid)
1486            {
1487                if(defined $SpecElem{$Tid_Adv}
1488                or defined $TypeInfo{$Tid_Adv}{"Size"})
1489                {
1490                    foreach my $Attr (keys(%{$TypeInfo{$Tid_Adv}}))
1491                    {
1492                        if(not defined $TypeInfo{$Tid}{$Attr})
1493                        {
1494                            if(ref($TypeInfo{$Tid_Adv}{$Attr}) eq "HASH") {
1495                                $TypeInfo{$Tid}{$Attr} = dclone($TypeInfo{$Tid_Adv}{$Attr});
1496                            }
1497                            else {
1498                                $TypeInfo{$Tid}{$Attr} = $TypeInfo{$Tid_Adv}{$Attr};
1499                            }
1500
1501                        }
1502                    }
1503                    last;
1504                }
1505            }
1506        }
1507    }
1508
1509    my %Delete = ();
1510
1511    foreach my $Tid (sort {int($a) <=> int($b)} keys(%TypeInfo))
1512    {
1513        if(defined $TypeInfo{$Tid}
1514        and $TypeInfo{$Tid}{"Type"} eq "Typedef")
1515        {
1516            my $TN = $TypeInfo{$Tid}{"Name"};
1517            my $TL = $TypeInfo{$Tid}{"Line"};
1518            my $NS = $TypeInfo{$Tid}{"NameSpace"};
1519
1520            if(my $BTid = $TypeInfo{$Tid}{"BaseType"})
1521            {
1522                if(defined $TypeInfo{$BTid}
1523                and $TypeInfo{$BTid}{"Name"}=~/\Aanon\-(\w+)\-/)
1524                {
1525                    %{$TypeInfo{$Tid}} = %{$TypeInfo{$BTid}};
1526                    $TypeInfo{$Tid}{"Name"} = $1." ".$TN;
1527                    $TypeInfo{$Tid}{"Line"} = $TL;
1528
1529                    my $Name = $TypeInfo{$Tid}{"Name"};
1530                    my $Type = $TypeInfo{$Tid}{"Type"};
1531
1532                    if(not defined $TName_Tid{$Type}{$Name}
1533                    or ($Tid>0 and $Tid<$TName_Tid{$Type}{$Name})
1534                    or ($Tid>0 and $TName_Tid{$Type}{$Name}<0)) {
1535                        $TName_Tid{$Type}{$Name} = $Tid;
1536                    }
1537                    $TName_Tids{$Type}{$Name}{$Tid} = 1;
1538
1539                    if($NS) {
1540                        $TypeInfo{$Tid}{"NameSpace"} = $NS;
1541                    }
1542                    $Delete{$BTid} = 1;
1543                }
1544            }
1545        }
1546    }
1547
1548    foreach my $Tid (keys(%Delete))
1549    {
1550        my $TN = $TypeInfo{$Tid}{"Name"};
1551        my $TT = $TypeInfo{$Tid}{"Type"};
1552
1553        delete($TName_Tid{$TT}{$TN});
1554        delete($TName_Tids{$TT}{$TN}{$Tid});
1555        if(my @IDs = sort {int($a) <=> int($b)} keys(%{$TName_Tids{$TT}{$TN}}))
1556        { # minimal ID
1557            $TName_Tid{$TT}{$TN} = $IDs[0];
1558        }
1559
1560        delete($TypeInfo{$Tid});
1561    }
1562
1563    foreach my $ID (sort {int($a) <=> int($b)} keys(%DWARF_Info))
1564    {
1565        if($DWARF_Info{$ID}{"Kind"} eq "subprogram"
1566        or $DWARF_Info{$ID}{"Kind"} eq "variable")
1567        {
1568            getSymbolInfo($ID);
1569        }
1570    }
1571
1572    foreach my $ID (sort {int($a) <=> int($b)} keys(%SymbolInfo))
1573    {
1574        # add missed c-tors
1575        if($SymbolInfo{$ID}{"Constructor"})
1576        {
1577            if($SymbolInfo{$ID}{"MnglName"}=~/(C[1-2])([EI]).+/)
1578            {
1579                my ($K1, $K2) = ($1, $2);
1580                foreach ("C1", "C2")
1581                {
1582                    if($K1 ne $_)
1583                    {
1584                        my $Name = $SymbolInfo{$ID}{"MnglName"};
1585                        $Name=~s/$K1$K2/$_$K2/;
1586
1587                        if(not defined $Mangled_ID{$Name}) {
1588                            cloneSymbol($ID, $Name);
1589                        }
1590                    }
1591                }
1592            }
1593        }
1594
1595        # add missed d-tors
1596        if($SymbolInfo{$ID}{"Destructor"})
1597        {
1598            if($SymbolInfo{$ID}{"MnglName"}=~/(D[0-2])([EI]).+/)
1599            {
1600                my ($K1, $K2) = ($1, $2);
1601                foreach ("D0", "D1", "D2")
1602                {
1603                    if($K1 ne $_)
1604                    {
1605                        my $Name = $SymbolInfo{$ID}{"MnglName"};
1606                        $Name=~s/$K1$K2/$_$K2/;
1607
1608                        if(not defined $Mangled_ID{$Name}) {
1609                            cloneSymbol($ID, $Name);
1610                        }
1611                    }
1612                }
1613            }
1614        }
1615    }
1616
1617    foreach my $ID (sort {int($a) <=> int($b)} keys(%SymbolInfo))
1618    {
1619        if($LIB_LANG eq "C++")
1620        {
1621            if(not $SymbolInfo{$ID}{"MnglName"})
1622            {
1623                if($SymbolInfo{$ID}{"Artificial"}
1624                or index($SymbolInfo{$ID}{"ShortName"}, "~")==0)
1625                {
1626                    delete($SymbolInfo{$ID});
1627                    next;
1628                }
1629            }
1630        }
1631
1632        if($SymbolInfo{$ID}{"Class"}
1633        and not $SymbolInfo{$ID}{"Data"}
1634        and not $SymbolInfo{$ID}{"Constructor"}
1635        and not $SymbolInfo{$ID}{"Destructor"}
1636        and not $SymbolInfo{$ID}{"Virt"}
1637        and not $SymbolInfo{$ID}{"PureVirt"})
1638        {
1639            if(not defined $SymbolInfo{$ID}{"Param"}
1640            or $SymbolInfo{$ID}{"Param"}{0}{"name"} ne "this")
1641            {
1642                $SymbolInfo{$ID}{"Static"} = 1;
1643            }
1644        }
1645
1646        if(not $SymbolInfo{$ID}{"Return"})
1647        { # void
1648            if(not $SymbolInfo{$ID}{"Constructor"}
1649            and not $SymbolInfo{$ID}{"Destructor"})
1650            {
1651                $SymbolInfo{$ID}{"Return"} = "1";
1652            }
1653        }
1654
1655        if(defined $SymbolInfo{$ID}{"Source"})
1656        {
1657            if(not defined $SymbolInfo{$ID}{"Header"}) {
1658                $SymbolInfo{$ID}{"Line"} = $SymbolInfo{$ID}{"SourceLine"};
1659            }
1660            delete($SymbolInfo{$ID}{"SourceLine"});
1661        }
1662
1663        my $S = selectSymbol($ID);
1664
1665        if($S==0)
1666        {
1667            if(defined $AllSymbols)
1668            {
1669                if($SymbolInfo{$ID}{"External"})
1670                {
1671                    $S = 1;
1672                }
1673                else
1674                { # local
1675                    if(defined $DumpStatic) {
1676                        $S = 1;
1677                    }
1678                }
1679            }
1680        }
1681
1682        if($S==0)
1683        {
1684            delete($SymbolInfo{$ID});
1685            next;
1686        }
1687        $SelectedSymbols{$ID} = $S;
1688
1689        delete($SymbolInfo{$ID}{"External"});
1690    }
1691}
1692
1693sub cloneSymbol($$)
1694{
1695    my ($ID, $Symbol) = @_;
1696
1697    my $nID = undef;
1698    if(not defined $SymbolInfo{$ID + 1}) {
1699        $nID = $ID + 1;
1700    }
1701    else {
1702        $nID = ++$GLOBAL_ID;
1703    }
1704    foreach my $Attr (keys(%{$SymbolInfo{$ID}}))
1705    {
1706        if(ref($SymbolInfo{$ID}{$Attr}) eq "HASH") {
1707            $SymbolInfo{$nID}{$Attr} = dclone($SymbolInfo{$ID}{$Attr});
1708        }
1709        else {
1710            $SymbolInfo{$nID}{$Attr} = $SymbolInfo{$ID}{$Attr};
1711        }
1712    }
1713    $SymbolInfo{$nID}{"MnglName"} = $Symbol;
1714}
1715
1716sub selectSymbol($)
1717{
1718    my $ID = $_[0];
1719
1720    my $MnglName = $SymbolInfo{$ID}{"MnglName"};
1721
1722    if(not $MnglName) {
1723        $MnglName = $SymbolInfo{$ID}{"ShortName"};
1724    }
1725
1726    my $Exp = 0;
1727
1728    if($Library_Symbol{$TargetName}{$MnglName}
1729    or $Library_Symbol{$TargetName}{$SymVer{$MnglName}})
1730    {
1731        $Exp = 1;
1732    }
1733
1734    if(my $Alias = $SymbolInfo{$ID}{"Alias"})
1735    {
1736        if($Library_Symbol{$TargetName}{$Alias}
1737        or $Library_Symbol{$TargetName}{$SymVer{$Alias}})
1738        {
1739            $Exp = 1;
1740        }
1741    }
1742
1743    if(not $Exp)
1744    {
1745        if(defined $Library_UndefSymbol{$TargetName}{$MnglName}
1746        or defined $Library_UndefSymbol{$TargetName}{$SymVer{$MnglName}})
1747        {
1748            return 0;
1749        }
1750        if($SymbolInfo{$ID}{"Data"}
1751        or $SymbolInfo{$ID}{"InLine"}
1752        or $SymbolInfo{$ID}{"PureVirt"})
1753        {
1754            if(defined $BinOnly)
1755            { # data, inline, pure
1756                return 0;
1757            }
1758            elsif(not defined $SymbolInfo{$ID}{"Header"})
1759            { # defined in source files
1760                return 0;
1761            }
1762            else {
1763                return 2;
1764            }
1765        }
1766        else
1767        {
1768            return 0;
1769        }
1770    }
1771
1772    return 1;
1773}
1774
1775sub formatName($$)
1776{ # type name correction
1777    if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
1778        return $Cache{"formatName"}{$_[1]}{$_[0]};
1779    }
1780
1781    my $N = $_[0];
1782
1783    if($_[1] ne "S")
1784    {
1785        $N=~s/\A[ ]+//g;
1786        $N=~s/[ ]+\Z//g;
1787        $N=~s/[ ]{2,}/ /g;
1788    }
1789
1790    $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
1791
1792    $N=~s/\b(const|volatile) ([\w\:]+)([\*&,>]|\Z)/$2 $1$3/g; # "const void" to "void const"
1793
1794    $N=~s/\bvolatile const\b/const volatile/g;
1795
1796    $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
1797    $N=~s/\b(short|long) int\b/$1/g;
1798
1799    $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
1800
1801    while($N=~s/>>/> >/g) {};
1802
1803    if($_[1] eq "S")
1804    {
1805        if(index($N, "operator")!=-1) {
1806            $N=~s/\b(operator[ ]*)> >/$1>>/;
1807        }
1808    }
1809
1810    $N=~s/,/, /g;
1811
1812    return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
1813}
1814
1815sub separate_Params($)
1816{
1817    my $Str = $_[0];
1818    my @Parts = ();
1819    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
1820    my $Part = 0;
1821    foreach my $Pos (0 .. length($Str) - 1)
1822    {
1823        my $S = substr($Str, $Pos, 1);
1824        if(defined $B{$S}) {
1825            $B{$S} += 1;
1826        }
1827        if($S eq "," and
1828        $B{"("}==$B{")"} and $B{"<"}==$B{">"}) {
1829            $Part += 1;
1830        }
1831        else {
1832            $Parts[$Part] .= $S;
1833        }
1834    }
1835    # remove spaces
1836    foreach (@Parts)
1837    {
1838        s/\A //g;
1839        s/ \Z//g;
1840    }
1841    return @Parts;
1842}
1843
1844sub init_FuncType($$$)
1845{
1846    my ($TInfo, $FTid, $Type) = @_;
1847
1848    $TInfo->{"Type"} = $Type;
1849
1850    if($TInfo->{"Return"} = $DWARF_Info{$FTid}{"type"}) {
1851        getTypeInfo($TInfo->{"Return"});
1852    }
1853    else
1854    { # void
1855        $TInfo->{"Return"} = "1";
1856    }
1857    delete($TInfo->{"BaseType"});
1858
1859    my @Prms = ();
1860    my $PPos = 0;
1861    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$FuncParam{$FTid}}))
1862    {
1863        my $ParamId = $FuncParam{$FTid}{$Pos};
1864        my %PInfo = %{$DWARF_Info{$ParamId}};
1865
1866        if(defined $PInfo{"artificial"})
1867        { # this
1868            next;
1869        }
1870
1871        if(my $PTypeId = $PInfo{"type"})
1872        {
1873            $TInfo->{"Param"}{$PPos}{"type"} = $PTypeId;
1874            getTypeInfo($PTypeId);
1875            push(@Prms, $TypeInfo{$PTypeId}{"Name"});
1876        }
1877
1878        $PPos += 1;
1879    }
1880
1881    $TInfo->{"Name"} = $TypeInfo{$TInfo->{"Return"}}{"Name"};
1882    if($Type eq "FuncPtr") {
1883        $TInfo->{"Name"} .= "(*)";
1884    }
1885    else {
1886        $TInfo->{"Name"} .= "()";
1887    }
1888    $TInfo->{"Name"} .= "(".join(",", @Prms).")";
1889}
1890
1891sub get_TParams($)
1892{
1893    my $Name = $_[0];
1894    if(my $Cent = find_center($Name, "<"))
1895    {
1896        my $TParams = substr($Name, $Cent);
1897        $TParams=~s/\A<|>\Z//g;
1898
1899        $TParams = simpleName($TParams);
1900
1901        my $Short = substr($Name, 0, $Cent);
1902
1903        my @Params = separate_Params($TParams);
1904        foreach my $Pos (0 .. $#Params)
1905        {
1906            my $Param = $Params[$Pos];
1907            if($Param=~/\A(.+>)(.*?)\Z/)
1908            {
1909                my ($Tm, $Suf) = ($1, $2);
1910                my ($Sh, @Prm) = get_TParams($Tm);
1911                $Param = $Sh."<".join(", ", @Prm).">".$Suf;
1912            }
1913            $Params[$Pos] = formatName($Param, "T");
1914        }
1915
1916        # default arguments
1917        if($Short eq "std::vector")
1918        {
1919            if($#Params==1)
1920            {
1921                if($Params[1] eq "std::allocator<".$Params[0].">")
1922                { # std::vector<T, std::allocator<T> >
1923                    splice(@Params, 1, 1);
1924                }
1925            }
1926        }
1927        elsif($Short eq "std::set")
1928        {
1929            if($#Params==2)
1930            {
1931                if($Params[1] eq "std::less<".$Params[0].">"
1932                and $Params[2] eq "std::allocator<".$Params[0].">")
1933                { # std::set<T, std::less<T>, std::allocator<T> >
1934                    splice(@Params, 1, 2);
1935                }
1936            }
1937        }
1938        elsif($Short eq "std::basic_string")
1939        {
1940            if($#Params==2)
1941            {
1942                if($Params[1] eq "std::char_traits<".$Params[0].">"
1943                and $Params[2] eq "std::allocator<".$Params[0].">")
1944                { # std::basic_string<T, std::char_traits<T>, std::allocator<T> >
1945                    splice(@Params, 1, 2);
1946                }
1947            }
1948        }
1949
1950        return ($Short, @Params);
1951    }
1952
1953    return $Name; # error
1954}
1955
1956sub getTypeInfo($)
1957{
1958    my $ID = $_[0];
1959    my $Kind = $DWARF_Info{$ID}{"Kind"};
1960
1961    if(defined $Cache{"getTypeInfo"}{$ID}) {
1962        return;
1963    }
1964
1965    if(my $N = $NameSpace{$ID})
1966    {
1967        if($DWARF_Info{$N}{"Kind"} eq "subprogram")
1968        { # local code
1969          # template instances are declared in the subprogram (constructor)
1970            my $Tmpl = 0;
1971            if(my $ObjP = $DWARF_Info{$N}{"object_pointer"})
1972            {
1973                while($DWARF_Info{$ObjP}{"type"}) {
1974                    $ObjP = $DWARF_Info{$ObjP}{"type"};
1975                }
1976                my $CName = $DWARF_Info{$ObjP}{"name"};
1977                $CName=~s/<.*//g;
1978                if($CName eq $DWARF_Info{$N}{"name"}) {
1979                    $Tmpl = 1;
1980                }
1981            }
1982            if(not $Tmpl)
1983            { # local types
1984                $LocalType{$ID} = 1;
1985            }
1986        }
1987        elsif($DWARF_Info{$N}{"Kind"} eq "lexical_block")
1988        { # local code
1989            return;
1990        }
1991    }
1992
1993    $Cache{"getTypeInfo"}{$ID} = 1;
1994
1995    my %TInfo = ();
1996
1997    $TInfo{"Type"} = $TypeType{$Kind};
1998
1999    if(not $TInfo{"Type"})
2000    {
2001        if($DWARF_Info{$ID}{"Kind"} eq "subroutine_type") {
2002            $TInfo{"Type"} = "Func";
2003        }
2004    }
2005
2006    if(defined $ClassMethods{$ID})
2007    {
2008        if($TInfo{"Type"} eq "Struct") {
2009            $TInfo{"Type"} = "Class";
2010        }
2011    }
2012
2013    if(my $BaseType = $DWARF_Info{$ID}{"type"})
2014    {
2015        $TInfo{"BaseType"} = "$BaseType";
2016
2017        if(defined $TypeType{$DWARF_Info{$BaseType}{"Kind"}})
2018        {
2019            getTypeInfo($TInfo{"BaseType"});
2020
2021            if(not defined $TypeInfo{$TInfo{"BaseType"}}
2022            or not $TypeInfo{$TInfo{"BaseType"}}{"Name"})
2023            { # local code
2024                delete($TypeInfo{$ID});
2025                return;
2026            }
2027        }
2028    }
2029    if($TInfo{"Type"} eq "Class") {
2030        $TInfo{"Copied"} = 1; # will be changed in getSymbolInfo()
2031    }
2032
2033    if(defined $TypeMember{$ID})
2034    {
2035        my $Unnamed = 0;
2036        foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TypeMember{$ID}}))
2037        {
2038            my $MemId = $TypeMember{$ID}{$Pos};
2039            my %MInfo = %{$DWARF_Info{$MemId}};
2040
2041            if(my $Name = $MInfo{"name"})
2042            {
2043                if(index($Name, "_vptr.")==0)
2044                { # v-table pointer
2045                    $Name="_vptr";
2046                }
2047                $TInfo{"Memb"}{$Pos}{"name"} = $Name;
2048            }
2049            else
2050            {
2051                $TInfo{"Memb"}{$Pos}{"name"} = "unnamed".$Unnamed;
2052                $Unnamed += 1;
2053            }
2054            if($TInfo{"Type"} eq "Enum") {
2055                $TInfo{"Memb"}{$Pos}{"value"} = $MInfo{"const_value"};
2056            }
2057            else
2058            {
2059                $TInfo{"Memb"}{$Pos}{"type"} = $MInfo{"type"};
2060                if(my $Access = $MInfo{"accessibility"}) {
2061                    $TInfo{"Memb"}{$Pos}{"access"} = $Access;
2062                }
2063                if($TInfo{"Type"} eq "Union") {
2064                    $TInfo{"Memb"}{$Pos}{"offset"} = "0";
2065                }
2066                elsif(defined $MInfo{"data_member_location"}) {
2067                    $TInfo{"Memb"}{$Pos}{"offset"} = $MInfo{"data_member_location"};
2068                }
2069            }
2070
2071            if((my $BitSize = $MInfo{"bit_size"}) ne "") {
2072                $TInfo{"Memb"}{$Pos}{"bitfield"} = $BitSize;
2073            }
2074        }
2075    }
2076
2077    if(my $Access = $DWARF_Info{$ID}{"accessibility"}) {
2078        $TInfo{ucfirst($Access)} = 1;
2079    }
2080
2081    if(my $Size = $DWARF_Info{$ID}{"byte_size"}) {
2082        $TInfo{"Size"} = $Size;
2083    }
2084
2085    setSource(\%TInfo, $ID, $DWARF_Info{$ID}{"decl_file"}, $DWARF_Info{$ID}{"decl_line"});
2086
2087    if(not $DWARF_Info{$ID}{"name"}
2088    and my $Spec = $DWARF_Info{$ID}{"specification"}) {
2089        $DWARF_Info{$ID}{"name"} = $DWARF_Info{$Spec}{"name"};
2090    }
2091
2092    if(my $Name = $DWARF_Info{$ID}{"name"})
2093    {
2094        $TInfo{"Name"} = $Name;
2095
2096        my $NS = $NameSpace{$ID};
2097        if(not $NS)
2098        {
2099            if(my $Sp = $DWARF_Info{$ID}{"specification"}) {
2100                $NS = $NameSpace{$Sp};
2101            }
2102        }
2103
2104        if($NS)
2105        {
2106            if($DWARF_Info{$NS}{"Kind"} eq "namespace")
2107            {
2108                if(my $NS_F = completeNS($ID))
2109                {
2110                    $TInfo{"NameSpace"} = $NS_F;
2111                    $TInfo{"Name"} = $TInfo{"NameSpace"}."::".$TInfo{"Name"};
2112                }
2113            }
2114            elsif($DWARF_Info{$NS}{"Kind"} eq "class_type"
2115            or $DWARF_Info{$NS}{"Kind"} eq "structure_type")
2116            { # class
2117                getTypeInfo($NS);
2118
2119                $TInfo{"NameSpace"} = $TypeInfo{$NS}{"Name"};
2120                $TInfo{"NameSpace"}=~s/\Astruct //;
2121                $TInfo{"Name"} = $TInfo{"NameSpace"}."::".$TInfo{"Name"};
2122            }
2123        }
2124
2125        if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
2126        {
2127            if(defined $VirtualTable{$TInfo{"Name"}}) {
2128                %{$TInfo{"VTable"}} = %{$VirtualTable{$TInfo{"Name"}}};
2129            }
2130        }
2131
2132        if($TInfo{"Type"}=~/\A(Struct|Enum|Union)\Z/) {
2133            $TInfo{"Name"} = lc($TInfo{"Type"})." ".$TInfo{"Name"};
2134        }
2135    }
2136
2137    if($TInfo{"Type"} eq "Pointer")
2138    {
2139        if($DWARF_Info{$TInfo{"BaseType"}}{"Kind"} eq "subroutine_type")
2140        {
2141            init_FuncType(\%TInfo, $TInfo{"BaseType"}, "FuncPtr");
2142        }
2143    }
2144    elsif($TInfo{"Type"}=~/Typedef|Const|Volatile/)
2145    {
2146        if($DWARF_Info{$TInfo{"BaseType"}}{"Kind"} eq "subroutine_type")
2147        {
2148            getTypeInfo($TInfo{"BaseType"});
2149        }
2150    }
2151    elsif($TInfo{"Type"} eq "Func")
2152    {
2153        init_FuncType(\%TInfo, $ID, "Func");
2154    }
2155    elsif($TInfo{"Type"} eq "Struct")
2156    {
2157        if(not $TInfo{"Name"}
2158        and my $Sb = $DWARF_Info{$ID}{"sibling"})
2159        {
2160            if($DWARF_Info{$Sb}{"Kind"} eq "subroutine_type"
2161            and defined $TInfo{"Memb"}
2162            and $TInfo{"Memb"}{0}{"name"} eq "__pfn")
2163            { # __pfn and __delta
2164                $TInfo{"Type"} = "MethodPtr";
2165
2166                my @Prms = ();
2167                my $PPos = 0;
2168                foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$FuncParam{$Sb}}))
2169                {
2170                    my $ParamId = $FuncParam{$Sb}{$Pos};
2171                    my %PInfo = %{$DWARF_Info{$ParamId}};
2172
2173                    if(defined $PInfo{"artificial"})
2174                    { # this
2175                        next;
2176                    }
2177
2178                    if(my $PTypeId = $PInfo{"type"})
2179                    {
2180                        $TInfo{"Param"}{$PPos}{"type"} = $PTypeId;
2181                        getTypeInfo($PTypeId);
2182                        push(@Prms, $TypeInfo{$PTypeId}{"Name"});
2183                    }
2184
2185                    $PPos += 1;
2186                }
2187
2188                if(my $ClassId = $DWARF_Info{$Sb}{"object_pointer"})
2189                {
2190                    while($DWARF_Info{$ClassId}{"type"}) {
2191                        $ClassId = $DWARF_Info{$ClassId}{"type"};
2192                    }
2193                    $TInfo{"Class"} = $ClassId;
2194                    getTypeInfo($TInfo{"Class"});
2195                }
2196
2197                if($TInfo{"Return"} = $DWARF_Info{$Sb}{"type"}) {
2198                    getTypeInfo($TInfo{"Return"});
2199                }
2200                else
2201                { # void
2202                    $TInfo{"Return"} = "1";
2203                }
2204
2205                $TInfo{"Name"} = $TypeInfo{$TInfo{"Return"}}{"Name"};
2206                $TInfo{"Name"} .= "(".$TypeInfo{$TInfo{"Class"}}{"Name"}."::*)";
2207                $TInfo{"Name"} .= "(".join(",", @Prms).")";
2208            }
2209        }
2210    }
2211    elsif($TInfo{"Type"} eq "FieldPtr")
2212    {
2213        $TInfo{"Return"} = $TInfo{"BaseType"};
2214        delete($TInfo{"BaseType"});
2215
2216        if(my $Class = $DWARF_Info{$ID}{"containing_type"})
2217        {
2218            $TInfo{"Class"} = $Class;
2219            getTypeInfo($TInfo{"Class"});
2220
2221            $TInfo{"Name"} = $TypeInfo{$TInfo{"Return"}}{"Name"}."(".$TypeInfo{$TInfo{"Class"}}{"Name"}."::*)";
2222        }
2223
2224        $TInfo{"Size"} = $SYS_WORD;
2225    }
2226
2227    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$Inheritance{$ID}}))
2228    {
2229        if(my $BaseId = $Inheritance{$ID}{$Pos}{"id"})
2230        {
2231            if(my $E = $SpecElem{$BaseId}) {
2232                $BaseId = $E;
2233            }
2234
2235            $TInfo{"Base"}{$BaseId}{"pos"} = "$Pos";
2236            if(my $Access = $Inheritance{$ID}{$Pos}{"access"}) {
2237                $TInfo{"Base"}{$BaseId}{"access"} = $Access;
2238            }
2239            if($Inheritance{$ID}{$Pos}{"virtual"}) {
2240                $TInfo{"Base"}{$BaseId}{"virtual"} = 1;
2241            }
2242
2243            $ClassChild{$BaseId}{$ID} = 1;
2244        }
2245    }
2246
2247    if($TInfo{"Type"} eq "Pointer")
2248    {
2249        if(not $TInfo{"BaseType"})
2250        {
2251            $TInfo{"Name"} = "void*";
2252            $TInfo{"BaseType"} = "1";
2253        }
2254    }
2255    if($TInfo{"Type"} eq "Const")
2256    {
2257        if(not $TInfo{"BaseType"})
2258        {
2259            $TInfo{"Name"} = "const void";
2260            $TInfo{"BaseType"} = "1";
2261        }
2262    }
2263    if($TInfo{"Type"} eq "Volatile")
2264    {
2265        if(not $TInfo{"BaseType"})
2266        {
2267            $TInfo{"Name"} = "volatile void";
2268            $TInfo{"BaseType"} = "1";
2269        }
2270    }
2271
2272    if(not $TInfo{"Name"})
2273    {
2274        my $ID_ = $ID;
2275        my $BaseID = undef;
2276        my $Name = "";
2277
2278        while($BaseID = $DWARF_Info{$ID_}{"type"})
2279        {
2280            my $Kind = $DWARF_Info{$ID_}{"Kind"};
2281            if(my $Q = $Qual{$TypeType{$Kind}})
2282            {
2283                $Name = $Q.$Name;
2284                if($Q=~/\A\w/) {
2285                    $Name = " ".$Name;
2286                }
2287            }
2288            if(my $BName = $TypeInfo{$BaseID}{"Name"})
2289            {
2290                $Name = $BName.$Name;
2291                last;
2292            }
2293            elsif(my $BName2 = $DWARF_Info{$BaseID}{"name"})
2294            {
2295                $Name = $BName2.$Name;
2296            }
2297            $ID_ = $BaseID;
2298        }
2299
2300        if($Name) {
2301            $TInfo{"Name"} = $Name;
2302        }
2303
2304        if($TInfo{"Type"} eq "Array")
2305        {
2306            if(my $Count = $ArrayCount{$ID})
2307            {
2308                $TInfo{"Name"} .= "[".$Count."]";
2309                if(my $BType = $TInfo{"BaseType"})
2310                {
2311                    if(my $BSize = $TypeInfo{$BType}{"Size"})
2312                    {
2313                        if(my $Size = $Count*$BSize)
2314                        {
2315                            $TInfo{"Size"} = "$Size";
2316                        }
2317                    }
2318                }
2319            }
2320            else
2321            {
2322                $TInfo{"Name"} .= "[]";
2323                $TInfo{"Size"} = $SYS_WORD;
2324            }
2325        }
2326    }
2327
2328    if(my $Bid = $TInfo{"BaseType"})
2329    {
2330        if(not $TInfo{"Size"}
2331        and $TypeInfo{$Bid}{"Size"}) {
2332            $TInfo{"Size"} = $TypeInfo{$Bid}{"Size"};
2333        }
2334    }
2335    if($TInfo{"Name"}) {
2336        $TInfo{"Name"} = formatName($TInfo{"Name"}, "T"); # simpleName()
2337    }
2338
2339    if($TInfo{"Name"}=~/>\Z/)
2340    {
2341        my ($Short, @TParams) = get_TParams($TInfo{"Name"});
2342
2343        if(@TParams)
2344        {
2345            delete($TInfo{"TParam"});
2346            foreach my $Pos (0 .. $#TParams) {
2347                $TInfo{"TParam"}{$Pos}{"name"} = $TParams[$Pos];
2348            }
2349            $TInfo{"Name"} = formatName($Short."<".join(", ", @TParams).">", "T");
2350        }
2351    }
2352
2353    if(not $TInfo{"Name"})
2354    {
2355        if($TInfo{"Type"}=~/\A(Struct|Enum|Union)\Z/)
2356        {
2357            if($TInfo{"Header"}) {
2358                $TInfo{"Name"} = "anon-".lc($TInfo{"Type"})."-".$TInfo{"Header"}."-".$TInfo{"Line"};
2359            }
2360            elsif($TInfo{"Source"}) {
2361                $TInfo{"Name"} = "anon-".lc($TInfo{"Type"})."-".$TInfo{"Source"}."-".$TInfo{"SourceLine"};
2362            }
2363        }
2364    }
2365
2366    if($TInfo{"Name"})
2367    {
2368        if(not defined $TName_Tid{$TInfo{"Type"}}{$TInfo{"Name"}}
2369        or ($ID>0 and $ID<$TName_Tid{$TInfo{"Type"}}{$TInfo{"Name"}})
2370        or ($ID>0 and $TName_Tid{$TInfo{"Type"}}{$TInfo{"Name"}}<0))
2371        {
2372            $TName_Tid{$TInfo{"Type"}}{$TInfo{"Name"}} = "$ID";
2373        }
2374        $TName_Tids{$TInfo{"Type"}}{$TInfo{"Name"}}{$ID} = 1;
2375    }
2376
2377    if(defined $TInfo{"Source"})
2378    {
2379        if(not defined $TInfo{"Header"}) {
2380            $TInfo{"Line"} = $TInfo{"SourceLine"};
2381        }
2382        delete($TInfo{"SourceLine"});
2383    }
2384
2385    foreach my $Attr (keys(%TInfo)) {
2386        $TypeInfo{$ID}{$Attr} = $TInfo{$Attr};
2387    }
2388
2389    if(my $BASE_ID = $DWARF_Info{$ID}{"specification"})
2390    {
2391        foreach my $Attr (keys(%{$TypeInfo{$BASE_ID}}))
2392        {
2393            if($Attr ne "Type") {
2394                $TypeInfo{$ID}{$Attr} = $TypeInfo{$BASE_ID}{$Attr};
2395            }
2396        }
2397
2398        foreach my $Attr (keys(%{$TypeInfo{$ID}})) {
2399            $TypeInfo{$BASE_ID}{$Attr} = $TypeInfo{$ID}{$Attr};
2400        }
2401
2402        $TypeSpec{$ID} = $BASE_ID;
2403    }
2404}
2405
2406sub setSource($$$$)
2407{
2408    my ($R, $ID, $File, $Line) = @_;
2409
2410    my $Unit = $DWARF_Info{$ID}{"CompUnit"};
2411
2412    if(defined $File)
2413    {
2414        if($SourceFile{$Unit}{$File}=~/\.($HEADER_EXT)\Z/)
2415        {
2416            $R->{"Header"} = $SourceFile{$Unit}{$File};
2417            if(defined $Line) {
2418                $R->{"Line"} = $Line;
2419            }
2420        }
2421        elsif($SourceFile{$Unit}{$File} ne "<built-in>")
2422        {
2423            $R->{"Source"} = $SourceFile{$Unit}{$File};
2424            if(defined $Line) {
2425                $R->{"SourceLine"} = $Line;
2426            }
2427        }
2428    }
2429}
2430
2431sub skipSymbol($)
2432{
2433    if($SkipCxx and not $STDCXX_TARGET)
2434    {
2435        if($_[0]=~/\A(_ZS|_ZNS|_ZNKS|_ZN9__gnu_cxx|_ZNK9__gnu_cxx|_ZTIS|_ZTSS)/)
2436        { # stdc++ symbols
2437            return 1;
2438        }
2439    }
2440    return 0;
2441}
2442
2443sub find_center($$)
2444{
2445    my ($Name, $Target) = @_;
2446    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
2447    foreach my $Pos (0 .. length($Name)-1)
2448    {
2449        my $S = substr($Name, length($Name)-1-$Pos, 1);
2450        if(defined $B{$S}) {
2451            $B{$S}+=1;
2452        }
2453        if($S eq $Target)
2454        {
2455            if($B{"("}==$B{")"}
2456            and $B{"<"}==$B{">"}) {
2457                return length($Name)-1-$Pos;
2458            }
2459        }
2460    }
2461    return 0;
2462}
2463
2464sub isExternal($)
2465{
2466    my $ID = $_[0];
2467
2468    if($DWARF_Info{$ID}{"external"}) {
2469        return 1;
2470    }
2471    elsif(my $Spec = $DWARF_Info{$ID}{"specification"})
2472    {
2473        if($DWARF_Info{$Spec}{"external"}) {
2474            return 1;
2475        }
2476    }
2477
2478    return 0;
2479}
2480
2481sub symByAddr($)
2482{
2483    my $Loc = $_[0];
2484
2485    my ($Addr, $Sect) = ("", "");
2486    if($Loc=~/\+(.+)/)
2487    {
2488        $Addr = $1;
2489        if(not $Addr=~s/\A0x//)
2490        {
2491            $Addr=~s/\A00//;
2492        }
2493    }
2494    if($Loc=~/([\w\.]+)\+/) {
2495        $Sect = $1;
2496    }
2497
2498    if($Addr ne "")
2499    {
2500        foreach ($Sect, "")
2501        {
2502            if(defined $SymbolTable{$_}{$Addr})
2503            {
2504                if(my @Symbols = sort keys(%{$SymbolTable{$_}{$Addr}})) {
2505                    return $Symbols[0];
2506                }
2507            }
2508        }
2509    }
2510
2511    return undef;
2512}
2513
2514sub get_Mangled($)
2515{
2516    my $ID = $_[0];
2517
2518    if(not defined $AddrToName)
2519    {
2520        if(my $Link = $DWARF_Info{$ID}{"linkage_name"})
2521        {
2522            return $Link;
2523        }
2524    }
2525
2526    if(my $Low_Pc = $DWARF_Info{$ID}{"low_pc"})
2527    {
2528        if($Low_Pc=~/<([\w\@\.]+)>/) {
2529            return $1;
2530        }
2531        else
2532        {
2533            if(my $Symbol = symByAddr($Low_Pc)) {
2534                return $Symbol;
2535            }
2536        }
2537    }
2538
2539    if(my $Loc = $DWARF_Info{$ID}{"location"})
2540    {
2541        if($Loc=~/<([\w\@\.]+)>/) {
2542            return $1;
2543        }
2544        else
2545        {
2546            if(my $Symbol = symByAddr($Loc)) {
2547                return $Symbol;
2548            }
2549        }
2550    }
2551
2552    if(my $Link = $DWARF_Info{$ID}{"linkage_name"})
2553    {
2554        return $Link;
2555    }
2556
2557    return undef;
2558}
2559
2560sub completeNS($)
2561{
2562    my $ID = $_[0];
2563
2564    my $NS = undef;
2565    my $ID_ = $ID;
2566    my @NSs = ();
2567
2568    while($NS = $NameSpace{$ID_}
2569    or $NS = $NameSpace{$DWARF_Info{$ID_}{"specification"}})
2570    {
2571        if(my $N = $DWARF_Info{$NS}{"name"}) {
2572            push(@NSs, $N);
2573        }
2574        $ID_ = $NS;
2575    }
2576
2577    if(@NSs)
2578    {
2579        my $N = join("::", reverse(@NSs));
2580        $NestedNameSpaces{$N} = 1;
2581        return $N;
2582    }
2583
2584    return undef;
2585}
2586
2587sub getSymbolInfo($)
2588{
2589    my $ID = $_[0];
2590
2591    if(my $N = $NameSpace{$ID})
2592    {
2593        if($DWARF_Info{$N}{"Kind"} eq "lexical_block"
2594        or $DWARF_Info{$N}{"Kind"} eq "subprogram")
2595        { # local variables
2596            return;
2597        }
2598    }
2599
2600    if(my $Loc = $DWARF_Info{$ID}{"location"})
2601    {
2602        if($Loc=~/ reg\d+\Z/)
2603        { # local variables
2604            return;
2605        }
2606    }
2607
2608    my $ShortName = $DWARF_Info{$ID}{"name"};
2609    my $MnglName = get_Mangled($ID);
2610
2611    if(not $MnglName)
2612    {
2613        if(my $Sp = $SpecElem{$ID}) {
2614            $MnglName = get_Mangled($Sp);
2615        }
2616    }
2617
2618    if(not $MnglName)
2619    {
2620        if(index($ShortName, "<")!=-1)
2621        { # template
2622            return;
2623        }
2624        $MnglName = $ShortName;
2625    }
2626
2627    if(skipSymbol($MnglName)) {
2628        return;
2629    }
2630
2631    if(index($MnglName, "\@")!=-1) {
2632        $MnglName=~s/([\@]+.*?)\Z//;
2633    }
2634
2635    if(not $MnglName) {
2636        return;
2637    }
2638
2639    if(index($MnglName, ".")!=-1)
2640    { # foo.part.14
2641      # bar.isra.15
2642        return;
2643    }
2644
2645    if($MnglName=~/\W/)
2646    { # unmangled operators, etc.
2647        return;
2648    }
2649
2650    if($MnglName)
2651    {
2652        if(my $OLD_ID = $Mangled_ID{$MnglName})
2653        { # duplicates
2654            if(defined $Checked_Spec{$MnglName}
2655            or not $DWARF_Info{$ID}{"specification"})
2656            { # add spec info
2657                if(not defined $SymbolInfo{$OLD_ID}{"Header"}
2658                or not defined $SymbolInfo{$OLD_ID}{"Source"})
2659                {
2660                    if($DWARF_Info{$ID}{"decl_file"} ne $DWARF_Info{$OLD_ID}{"decl_file"})
2661                    {
2662                        setSource($SymbolInfo{$OLD_ID}, $ID, $DWARF_Info{$ID}{"decl_file"}, $DWARF_Info{$ID}{"decl_line"});
2663                    }
2664                }
2665                return;
2666            }
2667        }
2668    }
2669
2670    my %SInfo = ();
2671
2672    if($ShortName) {
2673        $SInfo{"ShortName"} = $ShortName;
2674    }
2675    $SInfo{"MnglName"} = $MnglName;
2676
2677    if($MnglName eq $ShortName)
2678    {
2679        delete($SInfo{"MnglName"});
2680        $MnglName = $ShortName;
2681    }
2682    elsif(index($MnglName, "_Z")!=0)
2683    {
2684        if($SInfo{"ShortName"})
2685        {
2686            $SInfo{"Alias"} = $SInfo{"ShortName"};
2687            $SInfo{"ShortName"} = $SInfo{"MnglName"};
2688        }
2689
2690        delete($SInfo{"MnglName"});
2691        $MnglName = $ShortName;
2692    }
2693
2694    if(isExternal($ID)) {
2695        $SInfo{"External"} = 1;
2696    }
2697
2698    if(index($MnglName, "_ZNVK")==0)
2699    {
2700        $SInfo{"Const"} = 1;
2701        $SInfo{"Volatile"} = 1;
2702    }
2703    elsif(index($MnglName, "_ZNV")==0) {
2704        $SInfo{"Volatile"} = 1;
2705    }
2706    elsif(index($MnglName, "_ZNK")==0) {
2707        $SInfo{"Const"} = 1;
2708    }
2709
2710    if($DWARF_Info{$ID}{"artificial"}) {
2711        $SInfo{"Artificial"} = 1;
2712    }
2713
2714    my ($C, $D) = ();
2715
2716    if($MnglName=~/C[1-2][EI].+/)
2717    {
2718        $C = 1;
2719        $SInfo{"Constructor"} = 1;
2720    }
2721
2722    if($MnglName=~/D[0-2][EI].+/)
2723    {
2724        $D = 1;
2725        $SInfo{"Destructor"} = 1;
2726    }
2727
2728    if($C or $D)
2729    {
2730        if(my $Orig = $DWARF_Info{$ID}{"abstract_origin"})
2731        {
2732            if(my $InLine = $DWARF_Info{$Orig}{"inline"})
2733            {
2734                if(index($InLine, "declared_not_inlined")==0)
2735                {
2736                    $SInfo{"InLine"} = 1;
2737                    $SInfo{"Artificial"} = 1;
2738                }
2739            }
2740
2741            my %OrigInfo = %{$DWARF_Info{$Orig}};
2742
2743            setSource(\%SInfo, $Orig, $OrigInfo{"decl_file"}, $OrigInfo{"decl_line"});
2744
2745            if(my $Spec = $DWARF_Info{$Orig}{"specification"})
2746            {
2747                my %SpecInfo = %{$DWARF_Info{$Spec}};
2748                setSource(\%SInfo, $Spec, $SpecInfo{"decl_file"}, $SpecInfo{"decl_line"});
2749
2750                $SInfo{"ShortName"} = $SpecInfo{"name"};
2751                if($D) {
2752                    $SInfo{"ShortName"}=~s/\A\~//g;
2753                }
2754
2755                if(my $Class = $NameSpace{$Spec}) {
2756                    $SInfo{"Class"} = $Class;
2757                }
2758
2759                if(my $Virt = $DWARF_Info{$Spec}{"virtuality"})
2760                {
2761                    if(index($Virt, "virtual")!=-1) {
2762                        $SInfo{"Virt"} = 1;
2763                    }
2764                }
2765
2766                if(my $Access = $DWARF_Info{$Spec}{"accessibility"}) {
2767                    $SInfo{ucfirst($Access)} = 1;
2768                }
2769
2770                # clean origin
2771                delete($SymbolInfo{$Spec});
2772            }
2773        }
2774    }
2775    else
2776    {
2777        if(my $InLine = $DWARF_Info{$ID}{"inline"})
2778        {
2779            if(index($InLine, "declared_inlined")==0) {
2780                $SInfo{"InLine"} = 1;
2781            }
2782        }
2783    }
2784
2785    if(defined $AddrToName)
2786    {
2787        if(not $SInfo{"Alias"}
2788        and not $SInfo{"Constructor"}
2789        and not $SInfo{"Destructor"})
2790        {
2791            if(my $Linkage = $DWARF_Info{$ID}{"linkage_name"})
2792            {
2793                if($Linkage ne $MnglName) {
2794                    $SInfo{"Alias"} = $Linkage;
2795                }
2796            }
2797        }
2798    }
2799
2800    if($DWARF_Info{$ID}{"Kind"} eq "variable")
2801    { # global data
2802        $SInfo{"Data"} = 1;
2803
2804        if(my $Spec = $DWARF_Info{$ID}{"specification"})
2805        {
2806            if($DWARF_Info{$Spec}{"Kind"} eq "member")
2807            {
2808                my %SpecInfo = %{$DWARF_Info{$Spec}};
2809                setSource(\%SInfo, $Spec, $SpecInfo{"decl_file"}, $SpecInfo{"decl_line"});
2810                $SInfo{"ShortName"} = $SpecInfo{"name"};
2811
2812                if(my $NSp = $NameSpace{$Spec})
2813                {
2814                    if($DWARF_Info{$NSp}{"Kind"} eq "namespace") {
2815                        $SInfo{"NameSpace"} = completeNS($Spec);
2816                    }
2817                    else {
2818                        $SInfo{"Class"} = $NSp;
2819                    }
2820                }
2821            }
2822        }
2823    }
2824
2825    if(my $Access = $DWARF_Info{$ID}{"accessibility"})
2826    {
2827        $SInfo{ucfirst($Access)} = 1;
2828    }
2829
2830    if(my $Class = $DWARF_Info{$ID}{"containing_type"})
2831    {
2832        $SInfo{"Class"} = $Class;
2833    }
2834    if(my $NS = $NameSpace{$ID})
2835    {
2836        if($DWARF_Info{$NS}{"Kind"} eq "namespace") {
2837            $SInfo{"NameSpace"} = completeNS($ID);
2838        }
2839        else {
2840            $SInfo{"Class"} = $NS;
2841        }
2842    }
2843
2844    if($SInfo{"Class"} and $MnglName
2845    and index($MnglName, "_Z")!=0)
2846    {
2847        return;
2848    }
2849
2850    if(my $Return = $DWARF_Info{$ID}{"type"})
2851    {
2852        $SInfo{"Return"} = $Return;
2853    }
2854    if(my $Spec = $DWARF_Info{$ID}{"specification"})
2855    {
2856        if(not $DWARF_Info{$ID}{"type"}) {
2857            $SInfo{"Return"} = $DWARF_Info{$Spec}{"type"};
2858        }
2859        if(my $Value = $DWARF_Info{$Spec}{"const_value"})
2860        {
2861            if($Value=~/ block:\s*(.*?)\Z/) {
2862                $Value = $1;
2863            }
2864            $SInfo{"Value"} = $Value;
2865        }
2866    }
2867
2868    if($SInfo{"ShortName"}=~/>\Z/)
2869    { # foo<T1, T2, ...>
2870        my ($Short, @TParams) = get_TParams($SInfo{"ShortName"});
2871        if(@TParams)
2872        {
2873            foreach my $Pos (0 .. $#TParams) {
2874                $SInfo{"TParam"}{$Pos}{"name"} = formatName($TParams[$Pos], "T");
2875            }
2876            # simplify short name
2877            $SInfo{"ShortName"} = $Short.formatName("<".join(", ", @TParams).">", "T");
2878        }
2879    }
2880    elsif($SInfo{"ShortName"}=~/\Aoperator (\w.*)\Z/)
2881    { # operator type<T1>::name
2882        $SInfo{"ShortName"} = "operator ".simpleName($1);
2883    }
2884
2885    if(my $Virt = $DWARF_Info{$ID}{"virtuality"})
2886    {
2887        if(index($Virt, "virtual")!=-1)
2888        {
2889            if($D) {
2890                $SInfo{"Virt"} = 1;
2891            }
2892            else {
2893                $SInfo{"PureVirt"} = 1;
2894            }
2895        }
2896
2897        if((my $VirtPos = $DWARF_Info{$ID}{"vtable_elem_location"}) ne "")
2898        {
2899            $SInfo{"VirtPos"} = $VirtPos;
2900        }
2901    }
2902
2903    setSource(\%SInfo, $ID, $DWARF_Info{$ID}{"decl_file"}, $DWARF_Info{$ID}{"decl_line"});
2904
2905    my $PPos = 0;
2906
2907    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$FuncParam{$ID}}))
2908    {
2909        my $ParamId = $FuncParam{$ID}{$Pos};
2910        my $Offset = undef;
2911        my $Reg = undef;
2912
2913        if(my $Sp = $SpecElem{$ID})
2914        {
2915            if(defined $FuncParam{$Sp}) {
2916                $ParamId = $FuncParam{$Sp}{$Pos};
2917            }
2918        }
2919
2920        if((my $Loc = $DWARF_Info{$ParamId}{"location"}) ne "") {
2921            $Offset = $Loc;
2922        }
2923        elsif((my $R = $DWARF_Info{$ParamId}{"register"}) ne "") {
2924            $Reg = $RegName{$R};
2925        }
2926        elsif((my $LL = $DWARF_Info{$ParamId}{"location_list"}) ne "")
2927        {
2928            if(my $L = $DebugLoc{$LL})
2929            {
2930                if($L=~/reg(\d+)/) {
2931                    $Reg = $RegName{$1};
2932                }
2933                elsif($L=~/fbreg\s+(-?\w+)\Z/) {
2934                    $Offset = $1;
2935                }
2936            }
2937        }
2938
2939        if(my $Orig = $DWARF_Info{$ParamId}{"abstract_origin"}) {
2940            $ParamId = $Orig;
2941        }
2942
2943        my %PInfo = %{$DWARF_Info{$ParamId}};
2944
2945        if(defined $Offset) {
2946            $SInfo{"Param"}{$Pos}{"offset"} = $Offset;
2947        }
2948
2949        $SInfo{"Param"}{$Pos}{"type"} = $PInfo{"type"};
2950
2951        if(defined $PInfo{"name"}) {
2952            $SInfo{"Param"}{$Pos}{"name"} = $PInfo{"name"};
2953        }
2954        elsif($TypeInfo{$PInfo{"type"}}{"Name"} ne "...") {
2955            $SInfo{"Param"}{$Pos}{"name"} = "p".($PPos+1);
2956        }
2957        if(defined $Reg)
2958        { # FIXME: 0+8, 1+16, etc. (for partially distributed parameters)
2959            $SInfo{"Reg"}{$Pos} = $Reg;
2960        }
2961
2962        if($DWARF_Info{$ParamId}{"artificial"} and $Pos==0)
2963        {
2964            if($SInfo{"Param"}{$Pos}{"name"} eq "p1") {
2965                $SInfo{"Param"}{$Pos}{"name"} = "this";
2966            }
2967        }
2968
2969        if($SInfo{"Param"}{$Pos}{"name"} ne "this")
2970        { # this, p1, p2, etc.
2971            $PPos += 1;
2972        }
2973    }
2974
2975    if($SInfo{"Constructor"} and not $SInfo{"InLine"}
2976    and $SInfo{"Class"}) {
2977        delete($TypeInfo{$SInfo{"Class"}}{"Copied"});
2978    }
2979
2980    if(my $BASE_ID = $Mangled_ID{$MnglName})
2981    {
2982        $ID = $BASE_ID;
2983
2984        if(defined $SymbolInfo{$ID}{"PureVirt"})
2985        {
2986            delete($SymbolInfo{$ID}{"PureVirt"});
2987            $SymbolInfo{$ID}{"Virt"} = 1;
2988        }
2989    }
2990    $Mangled_ID{$MnglName} = $ID;
2991
2992    if($DWARF_Info{$ID}{"specification"}) {
2993        $Checked_Spec{$MnglName} = 1;
2994    }
2995
2996    foreach my $Attr (keys(%SInfo)) {
2997        $SymbolInfo{$ID}{$Attr} = $SInfo{$Attr};
2998    }
2999
3000    if($ID>$GLOBAL_ID) {
3001        $GLOBAL_ID = $ID;
3002    }
3003}
3004
3005sub getTypeIdByName($$)
3006{
3007    my ($Type, $Name) = @_;
3008    return $TName_Tid{$Type}{formatName($Name, "T")};
3009}
3010
3011sub getFirst($)
3012{
3013    my $Tid = $_[0];
3014    if(not $Tid) {
3015        return $Tid;
3016    }
3017
3018    if(defined $TypeSpec{$Tid}) {
3019        $Tid = $TypeSpec{$Tid};
3020    }
3021
3022    my $F = 0;
3023
3024    if(my $Name = $TypeInfo{$Tid}{"Name"})
3025    {
3026        my $Type = $TypeInfo{$Tid}{"Type"};
3027        if($Name=~s/\Astruct //)
3028        { # search for class or derived types (const, *, etc.)
3029            $F = 1;
3030        }
3031
3032        my $FTid = undef;
3033        if($F)
3034        {
3035            foreach my $Type ("Class", "Const", "Ref", "Pointer")
3036            {
3037                if($FTid = $TName_Tid{$Type}{$Name})
3038                {
3039                    if($FTid ne $Tid)
3040                    {
3041                        $MergedTypes{$Tid} = 1;
3042                    }
3043                    return "$FTid";
3044                }
3045            }
3046
3047            $Name = "struct ".$Name;
3048        }
3049
3050        if(not $FTid) {
3051            $FTid = $TName_Tid{$Type}{$Name};
3052        }
3053
3054        if($FTid) {
3055            return "$FTid";
3056        }
3057        printMsg("ERROR", "internal error (missed type id $Tid)");
3058    }
3059
3060    return $Tid;
3061}
3062
3063sub searchTypeID($)
3064{
3065    my $Name = $_[0];
3066
3067    my %Pr = map {$_=>1} (
3068        "Struct",
3069        "Union",
3070        "Enum"
3071    );
3072
3073    foreach my $Type ("Class", "Struct", "Union", "Enum", "Typedef", "Const",
3074    "Volatile", "Ref", "Pointer", "FuncPtr", "MethodPtr", "FieldPtr")
3075    {
3076        my $Tid = $TName_Tid{$Type}{$Name};
3077
3078        if(not $Tid)
3079        {
3080            my $P = "";
3081            if(defined $Pr{$Type})
3082            {
3083                $P = lc($Type)." ";
3084            }
3085
3086            $Tid = $TName_Tid{$Type}{$P.$Name}
3087        }
3088        if($Tid) {
3089            return $Tid;
3090        }
3091    }
3092    return undef;
3093}
3094
3095sub remove_Unused()
3096{ # remove unused data types from the ABI dump
3097    %HeadersInfo = ();
3098    %SourcesInfo = ();
3099
3100    my (%SelectedHeaders, %SelectedSources) = ();
3101
3102    foreach my $ID (sort {int($a)<=>int($b)} keys(%SymbolInfo))
3103    {
3104        if($SelectedSymbols{$ID}==2)
3105        { # data, inline, pure
3106            next;
3107        }
3108
3109        register_SymbolUsage($ID);
3110
3111        if(my $H = $SymbolInfo{$ID}{"Header"}) {
3112            $SelectedHeaders{$H} = 1;
3113        }
3114        if(my $S = $SymbolInfo{$ID}{"Source"}) {
3115            $SelectedSources{$S} = 1;
3116        }
3117    }
3118
3119    foreach my $ID (sort {int($a)<=>int($b)} keys(%SymbolInfo))
3120    {
3121        if($SelectedSymbols{$ID}==2)
3122        { # data, inline, pure
3123            my $Save = 0;
3124            if(my $Class = $SymbolInfo{$ID}{"Class"})
3125            {
3126                if(defined $UsedType{$Class}) {
3127                    $Save = 1;
3128                }
3129                else
3130                {
3131                    foreach (keys(%{$ClassChild{$Class}}))
3132                    {
3133                        if(defined $UsedType{$_})
3134                        {
3135                            $Save = 1;
3136                            last;
3137                        }
3138                    }
3139                }
3140            }
3141            if(my $Header = $SymbolInfo{$ID}{"Header"})
3142            {
3143                if(defined $SelectedHeaders{$Header}) {
3144                    $Save = 1;
3145                }
3146            }
3147            if(my $Source = $SymbolInfo{$ID}{"Source"})
3148            {
3149                if(defined $SelectedSources{$Source}) {
3150                    $Save = 1;
3151                }
3152            }
3153            if($Save) {
3154                register_SymbolUsage($ID);
3155            }
3156            else {
3157                delete($SymbolInfo{$ID});
3158            }
3159        }
3160    }
3161
3162    if(defined $AllTypes)
3163    {
3164        # register all data types (except anon structs and unions)
3165        foreach my $Tid (keys(%TypeInfo))
3166        {
3167            if(defined $LocalType{$Tid})
3168            { # except local code
3169                next;
3170            }
3171            if($TypeInfo{$Tid}{"Type"} eq "Enum"
3172            or index($TypeInfo{$Tid}{"Name"}, "anon-")!=0) {
3173                register_TypeUsage($Tid);
3174            }
3175        }
3176
3177        # remove unused anons (except enums)
3178        foreach my $Tid (keys(%TypeInfo))
3179        {
3180            if(not $UsedType{$Tid})
3181            {
3182                if($TypeInfo{$Tid}{"Type"} ne "Enum")
3183                {
3184                    if(index($TypeInfo{$Tid}{"Name"}, "anon-")==0) {
3185                        delete($TypeInfo{$Tid});
3186                    }
3187                }
3188            }
3189        }
3190
3191        # remove duplicates
3192        foreach my $Tid (keys(%TypeInfo))
3193        {
3194            my $Name = $TypeInfo{$Tid}{"Name"};
3195            my $Type = $TypeInfo{$Tid}{"Type"};
3196
3197            if($TName_Tid{$Type}{$Name} ne $Tid) {
3198                delete($TypeInfo{$Tid});
3199            }
3200        }
3201    }
3202    else
3203    {
3204        foreach my $Tid (keys(%TypeInfo))
3205        { # remove unused types
3206            if(not $UsedType{$Tid}) {
3207                delete($TypeInfo{$Tid});
3208            }
3209        }
3210    }
3211
3212    foreach my $Tid (keys(%MergedTypes)) {
3213        delete($TypeInfo{$Tid});
3214    }
3215
3216    foreach my $Tid (keys(%LocalType))
3217    {
3218        if(not $UsedType{$Tid}) {
3219            delete($TypeInfo{$Tid});
3220        }
3221    }
3222
3223    # completeness
3224    foreach my $Tid (keys(%TypeInfo)) {
3225        check_Completeness($TypeInfo{$Tid});
3226    }
3227
3228    foreach my $Sid (keys(%SymbolInfo)) {
3229        check_Completeness($SymbolInfo{$Sid});
3230    }
3231
3232    # clean memory
3233    %UsedType = ();
3234}
3235
3236sub simpleName($)
3237{
3238    my $N = $_[0];
3239
3240    if(index($N, "std::basic_string")!=-1)
3241    {
3242        $N=~s/std::basic_string<char, std::char_traits<char>, std::allocator<char> >/std::string /g;
3243        $N=~s/std::basic_string<char>/std::string /g;
3244    }
3245
3246    return formatName($N, "T");
3247}
3248
3249sub register_SymbolUsage($)
3250{
3251    my $InfoId = $_[0];
3252
3253    my %FuncInfo = %{$SymbolInfo{$InfoId}};
3254
3255    if(my $S = $FuncInfo{"Source"}) {
3256        $SourcesInfo{$S} = 1;
3257    }
3258    if(my $H = $FuncInfo{"Header"}) {
3259        $HeadersInfo{$H} = 1;
3260    }
3261    if(my $RTid = getFirst($FuncInfo{"Return"}))
3262    {
3263        register_TypeUsage($RTid);
3264        $SymbolInfo{$InfoId}{"Return"} = $RTid;
3265    }
3266    if(my $FCid = getFirst($FuncInfo{"Class"}))
3267    {
3268        register_TypeUsage($FCid);
3269        $SymbolInfo{$InfoId}{"Class"} = $FCid;
3270
3271        if(my $ThisId = getTypeIdByName("Const", $TypeInfo{$FCid}{"Name"}."*const"))
3272        { # register "this" pointer
3273            register_TypeUsage($ThisId);
3274        }
3275        if(my $ThisId_C = getTypeIdByName("Const", $TypeInfo{$FCid}{"Name"}." const*const"))
3276        { # register "this" pointer (const method)
3277            register_TypeUsage($ThisId_C);
3278        }
3279    }
3280    foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
3281    {
3282        if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}))
3283        {
3284            register_TypeUsage($PTid);
3285            $SymbolInfo{$InfoId}{"Param"}{$PPos}{"type"} = $PTid;
3286        }
3287    }
3288    foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
3289    {
3290        my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
3291        if(my $TTid = searchTypeID($TPName))
3292        {
3293            if(my $FTTid = getFirst($TTid)) {
3294                register_TypeUsage($FTTid);
3295            }
3296        }
3297    }
3298}
3299
3300sub register_TypeUsage($)
3301{
3302    my $TypeId = $_[0];
3303    if(not $TypeId) {
3304        return 0;
3305    }
3306    if($UsedType{$TypeId})
3307    { # already registered
3308        return 1;
3309    }
3310    my %TInfo = %{$TypeInfo{$TypeId}};
3311
3312    if(my $S = $TInfo{"Source"}) {
3313        $SourcesInfo{$S} = 1;
3314    }
3315    if(my $H = $TInfo{"Header"}) {
3316        $HeadersInfo{$H} = 1;
3317    }
3318
3319    if($TInfo{"Type"})
3320    {
3321        if(my $NS = $TInfo{"NameSpace"})
3322        {
3323            if(my $NSTid = searchTypeID($NS))
3324            {
3325                if(my $FNSTid = getFirst($NSTid)) {
3326                    register_TypeUsage($FNSTid);
3327                }
3328            }
3329        }
3330
3331        if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/)
3332        {
3333            $UsedType{$TypeId} = 1;
3334            if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
3335            {
3336                foreach my $BaseId (keys(%{$TInfo{"Base"}}))
3337                { # register base classes
3338                    if(my $FBaseId = getFirst($BaseId))
3339                    {
3340                        register_TypeUsage($FBaseId);
3341                        if($FBaseId ne $BaseId)
3342                        {
3343                            %{$TypeInfo{$TypeId}{"Base"}{$FBaseId}} = %{$TypeInfo{$TypeId}{"Base"}{$BaseId}};
3344                            delete($TypeInfo{$TypeId}{"Base"}{$BaseId});
3345                        }
3346                    }
3347                }
3348                foreach my $TPos (keys(%{$TInfo{"TParam"}}))
3349                {
3350                    my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
3351                    if(my $TTid = searchTypeID($TPName))
3352                    {
3353                        if(my $FTTid = getFirst($TTid)) {
3354                            register_TypeUsage($FTTid);
3355                        }
3356                    }
3357                }
3358            }
3359            foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
3360            {
3361                if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}))
3362                {
3363                    register_TypeUsage($MTid);
3364                    $TypeInfo{$TypeId}{"Memb"}{$Memb_Pos}{"type"} = $MTid;
3365                }
3366            }
3367            if($TInfo{"Type"} eq "FuncPtr"
3368            or $TInfo{"Type"} eq "MethodPtr"
3369            or $TInfo{"Type"} eq "Func")
3370            {
3371                if(my $RTid = getFirst($TInfo{"Return"}))
3372                {
3373                    register_TypeUsage($RTid);
3374                    $TypeInfo{$TypeId}{"Return"} = $RTid;
3375                }
3376                foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
3377                {
3378                    if(my $MTid = getFirst($TInfo{"Param"}{$Memb_Pos}{"type"}))
3379                    {
3380                        register_TypeUsage($MTid);
3381                        $TypeInfo{$TypeId}{"Param"}{$Memb_Pos}{"type"} = $MTid;
3382                    }
3383                }
3384            }
3385            if($TInfo{"Type"} eq "FieldPtr")
3386            {
3387                if(my $RTid = getFirst($TInfo{"Return"}))
3388                {
3389                    register_TypeUsage($RTid);
3390                    $TypeInfo{$TypeId}{"Return"} = $RTid;
3391                }
3392                if(my $CTid = getFirst($TInfo{"Class"}))
3393                {
3394                    register_TypeUsage($CTid);
3395                    $TypeInfo{$TypeId}{"Class"} = $CTid;
3396                }
3397            }
3398            if($TInfo{"Type"} eq "MethodPtr")
3399            {
3400                if(my $CTid = getFirst($TInfo{"Class"}))
3401                {
3402                    register_TypeUsage($CTid);
3403                    $TypeInfo{$TypeId}{"Class"} = $CTid;
3404                }
3405            }
3406            return 1;
3407        }
3408        elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
3409        {
3410            $UsedType{$TypeId} = 1;
3411            if(my $BTid = getFirst($TInfo{"BaseType"}))
3412            {
3413                register_TypeUsage($BTid);
3414                $TypeInfo{$TypeId}{"BaseType"} = $BTid;
3415            }
3416            return 1;
3417        }
3418        elsif($TInfo{"Type"} eq "Intrinsic")
3419        {
3420            $UsedType{$TypeId} = 1;
3421            return 1;
3422        }
3423    }
3424    return 0;
3425}
3426
3427my %CheckedType = ();
3428
3429sub check_Completeness($)
3430{
3431    my $Info = $_[0];
3432
3433    # data types
3434    if(defined $Info->{"Memb"})
3435    {
3436        foreach my $Pos (keys(%{$Info->{"Memb"}}))
3437        {
3438            if(defined $Info->{"Memb"}{$Pos}{"type"}) {
3439                check_TypeInfo($Info->{"Memb"}{$Pos}{"type"});
3440            }
3441        }
3442    }
3443    if(defined $Info->{"Base"})
3444    {
3445        foreach my $Bid (keys(%{$Info->{"Base"}})) {
3446            check_TypeInfo($Bid);
3447        }
3448    }
3449    if(defined $Info->{"BaseType"}) {
3450        check_TypeInfo($Info->{"BaseType"});
3451    }
3452    if(defined $Info->{"TParam"})
3453    {
3454        foreach my $Pos (keys(%{$Info->{"TParam"}}))
3455        {
3456            my $TName = $Info->{"TParam"}{$Pos}{"name"};
3457            if($TName=~/\A(true|false|\d.*)\Z/) {
3458                next;
3459            }
3460
3461            if(my $Tid = searchTypeID($TName)) {
3462                check_TypeInfo($Tid);
3463            }
3464            else
3465            {
3466                if(defined $Loud) {
3467                    printMsg("WARNING", "missed type $TName");
3468                }
3469            }
3470        }
3471    }
3472
3473    # symbols
3474    if(defined $Info->{"Param"})
3475    {
3476        foreach my $Pos (keys(%{$Info->{"Param"}}))
3477        {
3478            if(defined $Info->{"Param"}{$Pos}{"type"}) {
3479                check_TypeInfo($Info->{"Param"}{$Pos}{"type"});
3480            }
3481        }
3482    }
3483    if(defined $Info->{"Return"}) {
3484        check_TypeInfo($Info->{"Return"});
3485    }
3486    if(defined $Info->{"Class"}) {
3487        check_TypeInfo($Info->{"Class"});
3488    }
3489}
3490
3491sub check_TypeInfo($)
3492{
3493    my $Tid = $_[0];
3494
3495    if(defined $CheckedType{$Tid}) {
3496        return;
3497    }
3498    $CheckedType{$Tid} = 1;
3499
3500    if(defined $TypeInfo{$Tid})
3501    {
3502        if(not $TypeInfo{$Tid}{"Name"}) {
3503            printMsg("ERROR", "missed type name ($Tid)");
3504        }
3505        check_Completeness($TypeInfo{$Tid});
3506    }
3507    else {
3508        printMsg("ERROR", "missed type id $Tid");
3509    }
3510}
3511
3512sub init_Registers()
3513{
3514    if($SYS_ARCH eq "x86")
3515    {
3516        %RegName = (
3517        # integer registers
3518        # 32 bits
3519            "0"=>"eax",
3520            "1"=>"ecx",
3521            "2"=>"edx",
3522            "3"=>"ebx",
3523            "4"=>"esp",
3524            "5"=>"ebp",
3525            "6"=>"esi",
3526            "7"=>"edi",
3527            "8"=>"eip",
3528            "9"=>"eflags",
3529            "10"=>"trapno",
3530        # FPU-control registers
3531        # 16 bits
3532            "37"=>"fctrl",
3533            "38"=>"fstat",
3534        # 32 bits
3535            "39"=>"mxcsr",
3536        # MMX registers
3537        # 64 bits
3538            "29"=>"mm0",
3539            "30"=>"mm1",
3540            "31"=>"mm2",
3541            "32"=>"mm3",
3542            "33"=>"mm4",
3543            "34"=>"mm5",
3544            "35"=>"mm6",
3545            "36"=>"mm7",
3546        # SSE registers
3547        # 128 bits
3548            "21"=>"xmm0",
3549            "22"=>"xmm1",
3550            "23"=>"xmm2",
3551            "24"=>"xmm3",
3552            "25"=>"xmm4",
3553            "26"=>"xmm5",
3554            "27"=>"xmm6",
3555            "28"=>"xmm7",
3556        # segment registers
3557        # 16 bits
3558            "40"=>"es",
3559            "41"=>"cs",
3560            "42"=>"ss",
3561            "43"=>"ds",
3562            "44"=>"fs",
3563            "45"=>"gs",
3564        # x87 registers
3565        # 80 bits
3566            "11"=>"st0",
3567            "12"=>"st1",
3568            "13"=>"st2",
3569            "14"=>"st3",
3570            "15"=>"st4",
3571            "16"=>"st5",
3572            "17"=>"st6",
3573            "18"=>"st7"
3574        );
3575    }
3576    elsif($SYS_ARCH eq "x86_64")
3577    {
3578        %RegName = (
3579        # integer registers
3580        # 64 bits
3581            "1"=>"rdx",
3582            "2"=>"rcx",
3583            "3"=>"rbx",
3584            "4"=>"rsi",
3585            "5"=>"rdi",
3586            "6"=>"rbp",
3587            "7"=>"rsp",
3588            "8"=>"r8",
3589            "9"=>"r9",
3590            "10"=>"r10",
3591            "11"=>"r11",
3592            "12"=>"r12",
3593            "13"=>"r13",
3594            "14"=>"r14",
3595            "15"=>"r15",
3596            "16"=>"rip",
3597            "49"=>"rflags",
3598        # MMX registers
3599        # 64 bits
3600            "41"=>"mm0",
3601            "42"=>"mm1",
3602            "43"=>"mm2",
3603            "44"=>"mm3",
3604            "45"=>"mm4",
3605            "46"=>"mm5",
3606            "47"=>"mm6",
3607            "48"=>"mm7",
3608        # SSE registers
3609        # 128 bits
3610            "17"=>"xmm0",
3611            "18"=>"xmm1",
3612            "19"=>"xmm2",
3613            "20"=>"xmm3",
3614            "21"=>"xmm4",
3615            "22"=>"xmm5",
3616            "23"=>"xmm6",
3617            "24"=>"xmm7",
3618            "25"=>"xmm8",
3619            "26"=>"xmm9",
3620            "27"=>"xmm10",
3621            "28"=>"xmm11",
3622            "29"=>"xmm12",
3623            "30"=>"xmm13",
3624            "31"=>"xmm14",
3625            "32"=>"xmm15",
3626        # control registers
3627        # 64 bits
3628            "62"=>"tr",
3629            "63"=>"ldtr",
3630            "64"=>"mxcsr",
3631        # 16 bits
3632            "65"=>"fcw",
3633            "66"=>"fsw",
3634        # segment registers
3635        # 16 bits
3636            "50"=>"es",
3637            "51"=>"cs",
3638            "52"=>"ss",
3639            "53"=>"ds",
3640            "54"=>"fs",
3641            "55"=>"gs",
3642        # 64 bits
3643            "58"=>"fs.base",
3644            "59"=>"gs.base",
3645        # x87 registers
3646        # 80 bits
3647            "33"=>"st0",
3648            "34"=>"st1",
3649            "35"=>"st2",
3650            "36"=>"st3",
3651            "37"=>"st4",
3652            "38"=>"st5",
3653            "39"=>"st6",
3654            "40"=>"st7"
3655        );
3656    }
3657    elsif($SYS_ARCH eq "arm")
3658    {
3659        %RegName = (
3660        # integer registers
3661        # 32-bit
3662            "0"=>"r0",
3663            "1"=>"r1",
3664            "2"=>"r2",
3665            "3"=>"r3",
3666            "4"=>"r4",
3667            "5"=>"r5",
3668            "6"=>"r6",
3669            "7"=>"r7",
3670            "8"=>"r8",
3671            "9"=>"r9",
3672            "10"=>"r10",
3673            "11"=>"r11",
3674            "12"=>"r12",
3675            "13"=>"r13",
3676            "14"=>"r14",
3677            "15"=>"r15"
3678        );
3679    }
3680}
3681
3682sub dump_sorting($)
3683{
3684    my $Hash = $_[0];
3685    return [] if(not $Hash);
3686    my @Keys = keys(%{$Hash});
3687    return [] if($#Keys<0);
3688    if($Keys[0]=~/\A\d+\Z/)
3689    { # numbers
3690        return [sort {int($a)<=>int($b)} @Keys];
3691    }
3692    else
3693    { # strings
3694        return [sort {$a cmp $b} @Keys];
3695    }
3696}
3697
3698sub scenario()
3699{
3700    if($Help)
3701    {
3702        HELP_MESSAGE();
3703        exit(0);
3704    }
3705    if($ShowVersion)
3706    {
3707        printMsg("INFO", "ABI Dumper $TOOL_VERSION\nCopyright (C) 2013 ROSA 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.");
3708        exit(0);
3709    }
3710    if($DumpVersion)
3711    {
3712        printMsg("INFO", $TOOL_VERSION);
3713        exit(0);
3714    }
3715
3716    $Data::Dumper::Sortkeys = 1;
3717
3718    if($SortDump) {
3719        $Data::Dumper::Sortkeys = \&dump_sorting;
3720    }
3721
3722    if(defined $Compare)
3723    {
3724        my $P1 = $ARGV[0];
3725        my $P2 = $ARGV[1];
3726
3727        if(not $P1) {
3728            exitStatus("Error", "arguments are not specified");
3729        }
3730        elsif(not -e $P1) {
3731            exitStatus("Access_Error", "can't access \'$P1\'");
3732        }
3733
3734        if(not $P2) {
3735            exitStatus("Error", "second argument is not specified");
3736        }
3737        elsif(not -e $P2) {
3738            exitStatus("Access_Error", "can't access \'$P2\'");
3739        }
3740
3741        my %ABI = ();
3742
3743        $ABI{1} = eval(readFile($P1));
3744        $ABI{2} = eval(readFile($P2));
3745
3746        my %SymInfo = ();
3747
3748        foreach (1, 2)
3749        {
3750            foreach my $ID (keys(%{$ABI{$_}->{"SymbolInfo"}}))
3751            {
3752                my $Info = $ABI{$_}->{"SymbolInfo"}{$ID};
3753
3754                if(my $MnglName = $Info->{"MnglName"}) {
3755                    $SymInfo{$_}{$MnglName} = $Info;
3756                }
3757                elsif(my $ShortName = $Info->{"MnglName"}) {
3758                    $SymInfo{$_}{$ShortName} = $Info;
3759                }
3760            }
3761        }
3762
3763        foreach my $Symbol (sort keys(%{$SymInfo{1}}))
3764        {
3765            if(not defined $SymInfo{2}{$Symbol}) {
3766                printMsg("INFO", "Removed $Symbol");
3767            }
3768        }
3769
3770        foreach my $Symbol (sort keys(%{$SymInfo{2}}))
3771        {
3772            if(not defined $SymInfo{1}{$Symbol}) {
3773                printMsg("INFO", "Added $Symbol");
3774            }
3775        }
3776
3777        exit(0);
3778    }
3779
3780    if(not $TargetVersion) {
3781        printMsg("WARNING", "module version is not specified (-lver NUM)");
3782    }
3783
3784    if($FullDump)
3785    {
3786        $AllTypes = 1;
3787        $AllSymbols = 1;
3788    }
3789
3790    if(not $OutputDump) {
3791        $OutputDump = "./ABI.dump";
3792    }
3793
3794    if(not @ARGV) {
3795        exitStatus("Error", "object path is not specified");
3796    }
3797
3798    foreach my $Obj (@ARGV)
3799    {
3800        if(not -e $Obj) {
3801            exitStatus("Access_Error", "can't access \'$Obj\'");
3802        }
3803    }
3804
3805    if($AltDebugInfo)
3806    {
3807        if(not -e $AltDebugInfo) {
3808            exitStatus("Access_Error", "can't access \'$AltDebugInfo\'");
3809        }
3810    }
3811    else
3812    {
3813        my $Readelf = "eu-readelf";
3814        if(not check_Cmd($Readelf)) {
3815            exitStatus("Not_Found", "can't find \"$Readelf\" command");
3816        }
3817        foreach my $Obj (@ARGV)
3818        {
3819            my $Sect = `$Readelf -S \"$Obj\" 2>\"$TMP_DIR/error\"`;
3820
3821            if($Sect=~/\.debug_info/)
3822            {
3823                if($Sect=~/\.gnu_debugaltlink/)
3824                {
3825                    my $Str = `$Readelf --strings=.gnu_debugaltlink \"$Obj\" 2>\"$TMP_DIR/error\"`;
3826
3827                    if($Str=~/0\]\s*(.+)/)
3828                    {
3829                        my $AltObj = get_dirname($Obj)."/".$1;
3830
3831                        while($AltObj=~s/\/[^\/]+\/..\//\//g){};
3832
3833                        if(-e $AltObj)
3834                        {
3835                            printMsg("INFO", "Set alternate debug-info file to \'$AltObj\' (use -alt option to change it)");
3836                            $AltDebugInfo = $AltObj;
3837                        }
3838                        else
3839                        {
3840                            printMsg("WARNING", "can't access \'$AltObj\'");
3841                        }
3842                    }
3843                }
3844                last;
3845            }
3846        }
3847    }
3848
3849    if($AltDebugInfo) {
3850        read_Alt_Info($AltDebugInfo);
3851    }
3852
3853    if($ExtraInfo)
3854    {
3855        mkpath($ExtraInfo);
3856        $ExtraInfo = abs_path($ExtraInfo);
3857    }
3858
3859    my $Res = 0;
3860
3861    foreach my $Obj (@ARGV)
3862    {
3863        $TargetName = get_filename(realpath($Obj));
3864        $TargetName=~s/\.debug\Z//; # nouveau.ko.debug
3865
3866        if(index($TargetName, "libstdc++.so")==0) {
3867            $STDCXX_TARGET = 1;
3868        }
3869
3870        read_Symbols($Obj);
3871        $Res += read_DWARF_Info($Obj);
3872        read_Vtables($Obj);
3873    }
3874
3875    if(not $Res) {
3876        exitStatus("No_DWARF", "can't find debug info in object(s)");
3877    }
3878
3879    init_Registers();
3880    read_ABI();
3881
3882    %DWARF_Info = ();
3883
3884    remove_Unused();
3885
3886    dump_ABI();
3887
3888    exit(0);
3889}
3890
3891scenario();
3892