• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1###########################################################################
2# Module for ABI Compliance Checker to create ABI dumps in XML format
3#
4# Copyright (C) 2009-2011 Institute for System Programming, RAS
5# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
6# Copyright (C) 2011-2012 ROSA Laboratory
7# Copyright (C) 2012-2015 Andrey Ponomarenko's ABI Laboratory
8#
9# Written by Andrey Ponomarenko
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License or the GNU Lesser
13# General Public License as published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# and the GNU Lesser General Public License along with this program.
22# If not, see <http://www.gnu.org/licenses/>.
23###########################################################################
24use strict;
25
26my $TAG_ID = 0;
27my $INDENT = "    ";
28
29sub createXmlDump($)
30{
31    my $ABI = $_[0];
32    my $ABI_DUMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
33
34    $ABI_DUMP .= "<ABI_dump version=\"".$ABI->{"ABI_DUMP_VERSION"}."\"";
35    $ABI_DUMP .= " xml_format=\"".$ABI->{"XML_ABI_DUMP_VERSION"}."\"";
36    $ABI_DUMP .= " acc=\"".$ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}."\">\n";
37
38    $ABI_DUMP .= addTag("library", $ABI->{"LibraryName"});
39    $ABI_DUMP .= addTag("library_version", $ABI->{"LibraryVersion"});
40    $ABI_DUMP .= addTag("language", $ABI->{"Language"});
41
42    $ABI_DUMP .= addTag("gcc", $ABI->{"GccVersion"});
43    $ABI_DUMP .= addTag("architecture", $ABI->{"Arch"});
44    $ABI_DUMP .= addTag("target", $ABI->{"Target"});
45    $ABI_DUMP .= addTag("word_size", $ABI->{"WordSize"});
46
47    if($ABI->{"Mode"}) {
48        $ABI_DUMP .= addTag("mode", $ABI->{"Mode"});
49    }
50    if($ABI->{"SrcBin"}) {
51        $ABI_DUMP .= addTag("kind", "SrcBin");
52    }
53    elsif($ABI->{"BinOnly"}) {
54        $ABI_DUMP .= addTag("kind", "BinOnly");
55    }
56
57    if(my @Headers = keys(%{$ABI->{"Headers"}}))
58    {
59        @Headers = sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} @Headers;
60        $ABI_DUMP .= openTag("headers");
61        foreach my $Name (@Headers) {
62            $ABI_DUMP .= addTag("name", $Name);
63        }
64        $ABI_DUMP .= closeTag("headers");
65    }
66
67    if(my @NameSpaces = keys(%{$ABI->{"NameSpaces"}}))
68    {
69        $ABI_DUMP .= openTag("namespaces");
70        foreach my $NameSpace (sort {lc($a) cmp lc($b)} @NameSpaces) {
71            $ABI_DUMP .= addTag("name", $NameSpace);
72        }
73        $ABI_DUMP .= closeTag("namespaces");
74    }
75
76    if(my @TypeInfo = keys(%{$ABI->{"TypeInfo"}}))
77    {
78        $ABI_DUMP .= openTag("type_info");
79        foreach my $ID (sort {$a<=>$b} @TypeInfo)
80        {
81            my %TInfo = %{$ABI->{"TypeInfo"}{$ID}};
82            $ABI_DUMP .= openTag("data_type");
83            $ABI_DUMP .= addTag("id", $ID);
84            foreach my $Attr ("Name", "Type", "Size",
85            "Header", "Line", "NameSpace", "Class", "Return", "Algn")
86            {
87                if(defined $TInfo{$Attr}) {
88                    $ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr});
89                }
90            }
91            if($TInfo{"Private"}) {
92                $ABI_DUMP .= addTag("access", "private");
93            }
94            if($TInfo{"Protected"}) {
95                $ABI_DUMP .= addTag("access", "protected");
96            }
97            if(my @Positions = keys(%{$TInfo{"Memb"}}))
98            {
99                $ABI_DUMP .= openTag("members");
100                foreach my $Pos (sort { $a<=>$b } @Positions)
101                {
102                    $ABI_DUMP .= openTag("field");
103                    $ABI_DUMP .= addTag("name", $TInfo{"Memb"}{$Pos}{"name"});
104                    if(my $MTid = $TInfo{"Memb"}{$Pos}{"type"}) {
105                        $ABI_DUMP .= addTag("type", $MTid);
106                    }
107                    if(my $Access = $TInfo{"Memb"}{$Pos}{"access"}) {
108                        $ABI_DUMP .= addTag("access", $Access);
109                    }
110                    my $Val = $TInfo{"Memb"}{$Pos}{"value"};
111                    if(defined $Val) {
112                        $ABI_DUMP .= addTag("value", $Val);
113                    }
114                    if(my $Align = $TInfo{"Memb"}{$Pos}{"algn"}) {
115                        $ABI_DUMP .= addTag("algn", $Align);
116                    }
117                    if(my $Bitfield = $TInfo{"Memb"}{$Pos}{"bitfield"}) {
118                        $ABI_DUMP .= addTag("bitfield", $Bitfield);
119                    }
120                    if($TInfo{"Memb"}{$Pos}{"mutable"}) {
121                        $ABI_DUMP .= addTag("spec", "mutable");
122                    }
123                    $ABI_DUMP .= addTag("pos", $Pos);
124                    $ABI_DUMP .= closeTag("field");
125                }
126                $ABI_DUMP .= closeTag("members");
127            }
128            if(my @Positions = keys(%{$TInfo{"Param"}}))
129            {
130                $ABI_DUMP .= openTag("parameters");
131                foreach my $Pos (sort { $a<=>$b } @Positions)
132                {
133                    $ABI_DUMP .= openTag("param");
134                    if(my $PTid = $TInfo{"Param"}{$Pos}{"type"}) {
135                        $ABI_DUMP .= addTag("type", $PTid);
136                    }
137                    $ABI_DUMP .= addTag("pos", $Pos);
138                    $ABI_DUMP .= closeTag("param");
139                }
140                $ABI_DUMP .= closeTag("parameters");
141            }
142            if(my @Positions = keys(%{$TInfo{"TParam"}}))
143            {
144                $ABI_DUMP .= openTag("template_parameters");
145                foreach my $Pos (sort { $a<=>$b } @Positions)
146                {
147                    $ABI_DUMP .= openTag("param");
148                    $ABI_DUMP .= addTag("name", $TInfo{"TParam"}{$Pos}{"name"});
149                    $ABI_DUMP .= addTag("pos", $Pos);
150                    $ABI_DUMP .= closeTag("param");
151                }
152                $ABI_DUMP .= closeTag("template_parameters");
153            }
154            if(my @Offsets = keys(%{$TInfo{"VTable"}}))
155            {
156                $ABI_DUMP .= openTag("vtable");
157                foreach my $Offset (sort { $a<=>$b } @Offsets)
158                {
159                    $ABI_DUMP .= openTag("entry");
160                    $ABI_DUMP .= addTag("offset", $Offset);
161                    $ABI_DUMP .= addTag("value", $TInfo{"VTable"}{$Offset});
162                    $ABI_DUMP .= closeTag("entry");
163                }
164                $ABI_DUMP .= closeTag("vtable");
165            }
166            if(my $BTid = $TInfo{"BaseType"}) {
167                $ABI_DUMP .= addTag("base_type", $BTid);
168            }
169            if(my @BaseIDs = keys(%{$TInfo{"Base"}}))
170            {
171                @BaseIDs = sort { $TInfo{"Base"}{$a}{"pos"}<=>$TInfo{"Base"}{$b}{"pos"} } @BaseIDs;
172                $ABI_DUMP .= openTag("base");
173                foreach my $BaseID (@BaseIDs)
174                {
175                    $ABI_DUMP .= openTag("class");
176                    $ABI_DUMP .= addTag("id", $BaseID);
177                    if(my $Access = $TInfo{"Base"}{$BaseID}{"access"}) {
178                        $ABI_DUMP .= addTag("access", $Access);
179                    }
180                    if(my $Virt = $TInfo{"Base"}{$BaseID}{"virtual"}) {
181                        $ABI_DUMP .= addTag("inherit", "virtual");
182                    }
183                    $ABI_DUMP .= addTag("pos", $TInfo{"Base"}{$BaseID}{"pos"});
184                    $ABI_DUMP .= closeTag("class");
185                }
186                $ABI_DUMP .= closeTag("base");
187            }
188            if($TInfo{"Copied"}) {
189                $ABI_DUMP .= addTag("note", "copied");
190            }
191            if($TInfo{"Spec"}) {
192                $ABI_DUMP .= addTag("note", "specialization");
193            }
194            if($TInfo{"Forward"}) {
195                $ABI_DUMP .= addTag("note", "forward");
196            }
197            $ABI_DUMP .= closeTag("data_type");
198        }
199        $ABI_DUMP .= closeTag("type_info");
200    }
201
202    if(my @Constants = keys(%{$ABI->{"Constants"}}))
203    {
204        $ABI_DUMP .= openTag("constants");
205        foreach my $Constant (@Constants)
206        {
207            my %CInfo = %{$ABI->{"Constants"}{$Constant}};
208            $ABI_DUMP .= openTag("constant");
209            $ABI_DUMP .= addTag("name", $Constant);
210            $ABI_DUMP .= addTag("value", $CInfo{"Value"});
211            $ABI_DUMP .= addTag("header", $CInfo{"Header"});
212            $ABI_DUMP .= closeTag("constant");
213        }
214        $ABI_DUMP .= closeTag("constants");
215    }
216
217    if(my @SymbolInfo = keys(%{$ABI->{"SymbolInfo"}}))
218    {
219        my %TR = (
220            "MnglName" => "mangled",
221            "ShortName" => "short"
222        );
223        $ABI_DUMP .= openTag("symbol_info");
224        foreach my $ID (sort {$a<=>$b} @SymbolInfo)
225        {
226            my %SInfo = %{$ABI->{"SymbolInfo"}{$ID}};
227            $ABI_DUMP .= openTag("symbol");
228            $ABI_DUMP .= addTag("id", $ID);
229            foreach my $Attr ("MnglName", "ShortName", "Class",
230            "Header", "Line", "Return", "NameSpace", "Value")
231            {
232                if(defined $SInfo{$Attr})
233                {
234                    my $Tag = $Attr;
235                    if($TR{$Attr}) {
236                        $Tag = $TR{$Attr};
237                    }
238                    $ABI_DUMP .= addTag(lc($Tag), $SInfo{$Attr});
239                }
240            }
241            if($SInfo{"Constructor"}) {
242                $ABI_DUMP .= addTag("kind", "constructor");
243            }
244            if($SInfo{"Destructor"}) {
245                $ABI_DUMP .= addTag("kind", "destructor");
246            }
247            if($SInfo{"Data"}) {
248                $ABI_DUMP .= addTag("kind", "data");
249            }
250            if($SInfo{"Virt"}) {
251                $ABI_DUMP .= addTag("spec", "virtual");
252            }
253            elsif($SInfo{"PureVirt"}) {
254                $ABI_DUMP .= addTag("spec", "pure virtual");
255            }
256            elsif($SInfo{"Static"}) {
257                $ABI_DUMP .= addTag("spec", "static");
258            }
259            if($SInfo{"InLine"}) {
260                $ABI_DUMP .= addTag("spec", "inline");
261            }
262            if($SInfo{"Const"}) {
263                $ABI_DUMP .= addTag("spec", "const");
264            }
265            if($SInfo{"Volatile"}) {
266                $ABI_DUMP .= addTag("spec", "volatile");
267            }
268            if($SInfo{"Private"}) {
269                $ABI_DUMP .= addTag("access", "private");
270            }
271            if($SInfo{"Protected"}) {
272                $ABI_DUMP .= addTag("access", "protected");
273            }
274            if($SInfo{"Artificial"}) {
275                $ABI_DUMP .= addTag("note", "artificial");
276            }
277            if(my $Lang = $SInfo{"Lang"}) {
278                $ABI_DUMP .= addTag("lang", $Lang);
279            }
280            if(my @Positions = keys(%{$SInfo{"Param"}}))
281            {
282                $ABI_DUMP .= openTag("parameters");
283                foreach my $Pos (sort { $a<=>$b } @Positions)
284                {
285                    $ABI_DUMP .= openTag("param");
286                    if(my $PName = $SInfo{"Param"}{$Pos}{"name"}) {
287                        $ABI_DUMP .= addTag("name", $PName);
288                    }
289                    if(my $PTid = $SInfo{"Param"}{$Pos}{"type"}) {
290                        $ABI_DUMP .= addTag("type", $PTid);
291                    }
292                    my $Default = $SInfo{"Param"}{$Pos}{"default"};
293                    if(defined $Default) {
294                        $ABI_DUMP .= addTag("default", $Default);
295                    }
296                    if(my $Align = $SInfo{"Param"}{$Pos}{"algn"}) {
297                        $ABI_DUMP .= addTag("algn", $Align);
298                    }
299                    if(defined $SInfo{"Param"}{$Pos}{"reg"}) {
300                        $ABI_DUMP .= addTag("call", "register");
301                    }
302                    $ABI_DUMP .= addTag("pos", $Pos);
303                    $ABI_DUMP .= closeTag("param");
304                }
305                $ABI_DUMP .= closeTag("parameters");
306            }
307            if(my @Positions = keys(%{$SInfo{"TParam"}}))
308            {
309                $ABI_DUMP .= openTag("template_parameters");
310                foreach my $Pos (sort { $a<=>$b } @Positions)
311                {
312                    $ABI_DUMP .= openTag("param");
313                    $ABI_DUMP .= addTag("name", $SInfo{"TParam"}{$Pos}{"name"});
314                    $ABI_DUMP .= closeTag("param");
315                }
316                $ABI_DUMP .= closeTag("template_parameters");
317            }
318            $ABI_DUMP .= closeTag("symbol");
319        }
320        $ABI_DUMP .= closeTag("symbol_info");
321    }
322
323    if(my @Libs = keys(%{$ABI->{"Symbols"}}))
324    {
325        $ABI_DUMP .= openTag("symbols");
326        foreach my $Lib (sort {lc($a) cmp lc($b)} @Libs)
327        {
328            $ABI_DUMP .= openTag("library", "name", $Lib);
329            foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"Symbols"}{$Lib}}))
330            {
331                if((my $Size = $ABI->{"Symbols"}{$Lib}{$Symbol})<0)
332                { # data
333                    $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
334                }
335                else
336                { # functions
337                    $ABI_DUMP .= addTag("symbol", $Symbol);
338                }
339            }
340            $ABI_DUMP .= closeTag("library");
341        }
342        $ABI_DUMP .= closeTag("symbols");
343    }
344
345    if(my @DepLibs = keys(%{$ABI->{"DepSymbols"}}))
346    {
347        $ABI_DUMP .= openTag("dep_symbols");
348        foreach my $Lib (sort {lc($a) cmp lc($b)} @DepLibs)
349        {
350            $ABI_DUMP .= openTag("library", "name", $Lib);
351            foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"DepSymbols"}{$Lib}}))
352            {
353                if((my $Size = $ABI->{"DepSymbols"}{$Lib}{$Symbol})<0)
354                { # data
355                    $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
356                }
357                else
358                { # functions
359                    $ABI_DUMP .= addTag("symbol", $Symbol);
360                }
361            }
362            $ABI_DUMP .= closeTag("library");
363        }
364        $ABI_DUMP .= closeTag("dep_symbols");
365    }
366
367    if(my @VSymbols = keys(%{$ABI->{"SymbolVersion"}}))
368    {
369        $ABI_DUMP .= openTag("symbol_version");
370        foreach my $Symbol (sort {lc($a) cmp lc($b)} @VSymbols)
371        {
372            $ABI_DUMP .= openTag("symbol");
373            $ABI_DUMP .= addTag("name", $Symbol);
374            $ABI_DUMP .= addTag("version", $ABI->{"SymbolVersion"}{$Symbol});
375            $ABI_DUMP .= closeTag("symbol");
376        }
377        $ABI_DUMP .= closeTag("symbol_version");
378    }
379
380    if(my @SkipTypes = keys(%{$ABI->{"SkipTypes"}}))
381    {
382        $ABI_DUMP .= openTag("skip_types");
383        foreach my $Name (sort {lc($a) cmp lc($b)} @SkipTypes) {
384            $ABI_DUMP .= addTag("name", $Name);
385        }
386        $ABI_DUMP .= closeTag("skip_types");
387    }
388
389    if(my @SkipSymbols = keys(%{$ABI->{"SkipSymbols"}}))
390    {
391        $ABI_DUMP .= openTag("skip_symbols");
392        foreach my $Name (sort {lc($a) cmp lc($b)} @SkipSymbols) {
393            $ABI_DUMP .= addTag("name", $Name);
394        }
395        $ABI_DUMP .= closeTag("skip_symbols");
396    }
397
398    if(my @SkipNameSpaces = keys(%{$ABI->{"SkipNameSpaces"}}))
399    {
400        $ABI_DUMP .= openTag("skip_namespaces");
401        foreach my $Name (sort {lc($a) cmp lc($b)} @SkipNameSpaces) {
402            $ABI_DUMP .= addTag("name", $Name);
403        }
404        $ABI_DUMP .= closeTag("skip_namespaces");
405    }
406
407    if(my @SkipHeaders = keys(%{$ABI->{"SkipHeaders"}}))
408    {
409        $ABI_DUMP .= openTag("skip_headers");
410        foreach my $Name (sort {lc($a) cmp lc($b)} @SkipHeaders) {
411            $ABI_DUMP .= addTag("name", $Name);
412        }
413        $ABI_DUMP .= closeTag("skip_headers");
414    }
415
416    if(my @TargetHeaders = keys(%{$ABI->{"TargetHeaders"}}))
417    {
418        $ABI_DUMP .= openTag("target_headers");
419        foreach my $Name (sort {lc($a) cmp lc($b)} @TargetHeaders) {
420            $ABI_DUMP .= addTag("name", $Name);
421        }
422        $ABI_DUMP .= closeTag("target_headers");
423    }
424
425    $ABI_DUMP .= "</ABI_dump>\n";
426
427    checkTags();
428
429    return $ABI_DUMP;
430}
431
432sub readXmlDump($)
433{
434    my $ABI_DUMP = readFile($_[0]);
435    my %ABI = {};
436
437    $ABI{"LibraryName"} = parseTag(\$ABI_DUMP, "library");
438    $ABI{"LibraryVersion"} = parseTag(\$ABI_DUMP, "library_version");
439    $ABI{"Language"} = parseTag(\$ABI_DUMP, "language");
440    $ABI{"GccVersion"} = parseTag(\$ABI_DUMP, "gcc");
441    $ABI{"Arch"} = parseTag(\$ABI_DUMP, "architecture");
442    $ABI{"Target"} = parseTag(\$ABI_DUMP, "target");
443    $ABI{"WordSize"} = parseTag(\$ABI_DUMP, "word_size");
444
445    my $Pos = 0;
446
447    if(my $Headers = parseTag(\$ABI_DUMP, "headers"))
448    {
449        while(my $Name = parseTag(\$Headers, "name")) {
450            $ABI{"Headers"}{$Name} = $Pos++;
451        }
452    }
453
454    if(my $NameSpaces = parseTag(\$ABI_DUMP, "namespaces"))
455    {
456        while(my $Name = parseTag(\$NameSpaces, "name")) {
457            $ABI{"NameSpaces"}{$Name} = 1;
458        }
459    }
460
461    if(my $TypeInfo = parseTag(\$ABI_DUMP, "type_info"))
462    {
463        while(my $DataType = parseTag(\$TypeInfo, "data_type"))
464        {
465            my %TInfo = ();
466            my $ID = parseTag(\$DataType, "id");
467
468            if(my $Members = parseTag(\$DataType, "members"))
469            {
470                $Pos = 0;
471                while(my $Field = parseTag(\$Members, "field"))
472                {
473                    my %MInfo = ();
474                    $MInfo{"name"} = parseTag(\$Field, "name");
475                    if(my $Tid = parseTag(\$Field, "type")) {
476                        $MInfo{"type"} = $Tid;
477                    }
478                    if(my $Access = parseTag(\$Field, "access")) {
479                        $MInfo{"access"} = $Access;
480                    }
481                    my $Val = parseTag(\$Field, "value");
482                    if(defined $Val) {
483                        $MInfo{"value"} = $Val;
484                    }
485                    if(my $Align = parseTag(\$Field, "algn")) {
486                        $MInfo{"algn"} = $Align;
487                    }
488                    if(my $Bitfield = parseTag(\$Field, "bitfield")) {
489                        $MInfo{"bitfield"} = $Bitfield;
490                    }
491                    if(my $Spec = parseTag(\$Field, "spec")) {
492                        $MInfo{$Spec} = 1;
493                    }
494                    $TInfo{"Memb"}{$Pos++} = \%MInfo;
495                }
496            }
497
498            if(my $Parameters = parseTag(\$DataType, "parameters"))
499            {
500                $Pos = 0;
501                while(my $Parameter = parseTag(\$Parameters, "param"))
502                {
503                    my %PInfo = ();
504                    if(my $Tid = parseTag(\$Parameter, "type")) {
505                        $PInfo{"type"} = $Tid;
506                    }
507                    $TInfo{"Param"}{$Pos++} = \%PInfo;
508                }
509            }
510            if(my $TParams = parseTag(\$DataType, "template_parameters"))
511            {
512                $Pos = 0;
513                while(my $TParam = parseTag(\$TParams, "param")) {
514                    $TInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
515                }
516            }
517            if(my $VTable = parseTag(\$DataType, "vtable"))
518            {
519                $Pos = 0;
520                while(my $Entry = parseTag(\$VTable, "entry")) {
521                    $TInfo{"VTable"}{parseTag(\$Entry, "offset")} = parseTag(\$Entry, "value");
522                }
523            }
524            if(my $BTid = parseTag(\$DataType, "base_type")) {
525                $TInfo{"BaseType"} = $BTid;
526            }
527            if(my $Base = parseTag(\$DataType, "base"))
528            {
529                $Pos = 0;
530                while(my $Class = parseTag(\$Base, "class"))
531                {
532                    my %CInfo = ();
533                    $CInfo{"pos"} = parseTag(\$Class, "pos");
534                    if(my $Access = parseTag(\$Class, "access")) {
535                        $CInfo{"access"} = $Access;
536                    }
537                    if(my $Inherit = parseTag(\$Class, "inherit"))
538                    {
539                        if($Inherit eq "virtual") {
540                            $CInfo{"virtual"} = 1;
541                        }
542                    }
543                    $TInfo{"Base"}{parseTag(\$Class, "id")} = \%CInfo;
544                }
545            }
546            while(my $Note = parseTag(\$DataType, "note"))
547            {
548                if($Note eq "copied") {
549                    $TInfo{"Copied"} = 1;
550                }
551                elsif($Note eq "specialization") {
552                    $TInfo{"Spec"} = 1;
553                }
554                elsif($Note eq "forward") {
555                    $TInfo{"Forward"} = 1;
556                }
557            }
558            foreach my $Attr ("Name", "Type", "Size",
559            "Header", "Line", "NameSpace", "Class", "Return", "Algn")
560            {
561                my $Val = parseTag(\$DataType, lc($Attr));
562                if(defined $Val) {
563                    $TInfo{$Attr} = $Val;
564                }
565            }
566            if(my $Access = parseTag(\$DataType, "access")) {
567                $TInfo{ucfirst($Access)} = 1;
568            }
569            $ABI{"TypeInfo"}{$ID} = \%TInfo;
570        }
571    }
572
573    if(my $Constants = parseTag(\$ABI_DUMP, "constants"))
574    {
575        while(my $Constant = parseTag(\$Constants, "constant"))
576        {
577            if(my $Name = parseTag(\$Constant, "name"))
578            {
579                my %CInfo = ();
580                $CInfo{"Value"} = parseTag(\$Constant, "value");
581                $CInfo{"Header"} = parseTag(\$Constant, "header");
582                $ABI{"Constants"}{$Name} = \%CInfo;
583            }
584        }
585    }
586
587    if(my $SymbolInfo = parseTag(\$ABI_DUMP, "symbol_info"))
588    {
589        my %TR = (
590            "MnglName"=>"mangled",
591            "ShortName"=>"short"
592        );
593        while(my $Symbol = parseTag(\$SymbolInfo, "symbol"))
594        {
595            my %SInfo = ();
596            my $ID = parseTag(\$Symbol, "id");
597
598            if(my $Parameters = parseTag(\$Symbol, "parameters"))
599            {
600                $Pos = 0;
601                while(my $Parameter = parseTag(\$Parameters, "param"))
602                {
603                    my %PInfo = ();
604                    if(my $PName = parseTag(\$Parameter, "name")) {
605                        $PInfo{"name"} = $PName;
606                    }
607                    if(my $PTid = parseTag(\$Parameter, "type")) {
608                        $PInfo{"type"} = $PTid;
609                    }
610                    my $Default = parseTag(\$Parameter, "default", "spaces");
611                    if(defined $Default) {
612                        $PInfo{"default"} = $Default;
613                    }
614                    if(my $Align = parseTag(\$Parameter, "algn")) {
615                        $PInfo{"algn"} = $Align;
616                    }
617                    if(my $Call = parseTag(\$Parameter, "call"))
618                    {
619                        if($Call eq "register") {
620                            $PInfo{"reg"} = 1;
621                        }
622                    }
623                    $SInfo{"Param"}{$Pos++} = \%PInfo;
624                }
625            }
626            if(my $TParams = parseTag(\$Symbol, "template_parameters"))
627            {
628                $Pos = 0;
629                while(my $TParam = parseTag(\$TParams, "param")) {
630                    $SInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
631                }
632            }
633
634            foreach my $Attr ("MnglName", "ShortName", "Class",
635            "Header", "Line", "Return", "NameSpace", "Value")
636            {
637                my $Tag = lc($Attr);
638                if($TR{$Attr}) {
639                    $Tag = $TR{$Attr};
640                }
641                my $Val = parseTag(\$Symbol, $Tag);
642                if(defined $Val) {
643                    $SInfo{$Attr} = $Val;
644                }
645            }
646            if(my $Kind = parseTag(\$Symbol, "kind")) {
647                $SInfo{ucfirst($Kind)} = 1;
648            }
649            while(my $Spec = parseTag(\$Symbol, "spec"))
650            {
651                if($Spec eq "virtual") {
652                    $SInfo{"Virt"} = 1;
653                }
654                elsif($Spec eq "pure virtual") {
655                    $SInfo{"PureVirt"} = 1;
656                }
657                elsif($Spec eq "inline") {
658                    $SInfo{"InLine"} = 1;
659                }
660                else
661                { # const, volatile, static
662                    $SInfo{ucfirst($Spec)} = 1;
663                }
664            }
665            if(my $Access = parseTag(\$Symbol, "access")) {
666                $SInfo{ucfirst($Access)} = 1;
667            }
668            if(my $Note = parseTag(\$Symbol, "note")) {
669                $SInfo{ucfirst($Note)} = 1;
670            }
671            if(my $Lang = parseTag(\$Symbol, "lang")) {
672                $SInfo{"Lang"} = $Lang;
673            }
674            $ABI{"SymbolInfo"}{$ID} = \%SInfo;
675        }
676    }
677
678    if(my $Symbols = parseTag(\$ABI_DUMP, "symbols"))
679    {
680        my %LInfo = ();
681        while(my $LibSymbols = parseTag_E(\$Symbols, "library", \%LInfo))
682        {
683            my %SInfo = ();
684            while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
685            {
686                if(my $Size = $SInfo{"size"}) {
687                    $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
688                }
689                else {
690                    $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = 1;
691                }
692                %SInfo = ();
693            }
694            %LInfo = ();
695        }
696    }
697
698    if(my $DepSymbols = parseTag(\$ABI_DUMP, "dep_symbols"))
699    {
700        my %LInfo = ();
701        while(my $LibSymbols = parseTag_E(\$DepSymbols, "library", \%LInfo))
702        {
703            my %SInfo = ();
704            while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
705            {
706                if(my $Size = $SInfo{"size"}) {
707                    $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
708                }
709                else {
710                    $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = 1;
711                }
712                %SInfo = ();
713            }
714            %LInfo = ();
715        }
716    }
717
718    $ABI{"SymbolVersion"} = {};
719
720    if(my $SymbolVersion = parseTag(\$ABI_DUMP, "symbol_version"))
721    {
722        while(my $Symbol = parseTag(\$SymbolVersion, "symbol")) {
723            $ABI{"SymbolVersion"}{parseTag(\$Symbol, "name")} = parseTag(\$Symbol, "version");
724        }
725    }
726
727    $ABI{"SkipTypes"} = {};
728
729    if(my $SkipTypes = parseTag(\$ABI_DUMP, "skip_types"))
730    {
731        while(my $Name = parseTag(\$SkipTypes, "name")) {
732            $ABI{"SkipTypes"}{$Name} = 1;
733        }
734    }
735
736    $ABI{"SkipSymbols"} = {};
737
738    if(my $SkipSymbols = parseTag(\$ABI_DUMP, "skip_symbols"))
739    {
740        while(my $Name = parseTag(\$SkipSymbols, "name")) {
741            $ABI{"SkipSymbols"}{$Name} = 1;
742        }
743    }
744
745    $ABI{"SkipNameSpaces"} = {};
746
747    if(my $SkipNameSpaces = parseTag(\$ABI_DUMP, "skip_namespaces"))
748    {
749        while(my $Name = parseTag(\$SkipNameSpaces, "name")) {
750            $ABI{"SkipNameSpaces"}{$Name} = 1;
751        }
752    }
753
754    $ABI{"SkipHeaders"} = {};
755
756    if(my $SkipHeaders = parseTag(\$ABI_DUMP, "skip_headers"))
757    {
758        while(my $Name = parseTag(\$SkipHeaders, "name")) {
759            $ABI{"SkipHeaders"}{$Name} = 1;
760        }
761    }
762
763    if(my $TargetHeaders = parseTag(\$ABI_DUMP, "target_headers"))
764    {
765        while(my $Name = parseTag(\$TargetHeaders, "name")) {
766            $ABI{"TargetHeaders"}{$Name} = 1;
767        }
768    }
769
770    if(my $Mode = parseTag(\$ABI_DUMP, "mode")) {
771        $ABI{"Mode"} = $Mode;
772    }
773    if(my $Kind = parseTag(\$ABI_DUMP, "kind"))
774    {
775        if($Kind eq "BinOnly") {
776            $ABI{"BinOnly"} = 1;
777        }
778        elsif($Kind eq "SrcBin") {
779            $ABI{"SrcBin"} = 1;
780        }
781    }
782
783    my %RInfo = ();
784    parseTag_E(\$ABI_DUMP, "ABI_dump", \%RInfo);
785
786    $ABI{"ABI_DUMP_VERSION"} = $RInfo{"version"};
787    $ABI{"XML_ABI_DUMP_VERSION"} = $RInfo{"xml_format"};
788    $ABI{"ABI_COMPLIANCE_CHECKER_VERSION"} = $RInfo{"acc"};
789
790    return \%ABI;
791}
792
793sub parseTag_E($$$)
794{
795    my ($CodeRef, $Tag, $Info) = @_;
796    if(not $Tag or not $CodeRef
797    or not $Info) {
798        return undef;
799    }
800    if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
801    {
802        my ($Ext, $Content) = ($2, $3);
803        $Content=~s/\A\s+//g;
804        $Content=~s/\s+\Z//g;
805        if($Ext)
806        {
807            while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
808            {
809                my ($K, $V) = ($1, $2);
810                $Info->{$K} = xmlSpecChars_R($V);
811            }
812        }
813        if(substr($Content, 0, 1) ne "<") {
814            $Content = xmlSpecChars_R($Content);
815        }
816        return $Content;
817    }
818    return undef;
819}
820
821sub addTag(@)
822{
823    my $Tag = shift(@_);
824    my $Val = shift(@_);
825    my @Ext = @_;
826    my $Content = openTag($Tag, @Ext);
827    chomp($Content);
828    $Content .= xmlSpecChars($Val);
829    $Content .= "</$Tag>\n";
830    $TAG_ID-=1;
831
832    return $Content;
833}
834
835sub openTag(@)
836{
837    my $Tag = shift(@_);
838    my @Ext = @_;
839    my $Content = "";
840    foreach (1 .. $TAG_ID) {
841        $Content .= $INDENT;
842    }
843    $TAG_ID+=1;
844    if(@Ext)
845    {
846        $Content .= "<".$Tag;
847        my $P = 0;
848        while($P<=$#Ext-1)
849        {
850            $Content .= " ".$Ext[$P];
851            $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
852            $P+=2;
853        }
854        $Content .= ">\n";
855    }
856    else {
857        $Content .= "<".$Tag.">\n";
858    }
859    return $Content;
860}
861
862sub closeTag($)
863{
864    my $Tag = $_[0];
865    my $Content = "";
866    $TAG_ID-=1;
867    foreach (1 .. $TAG_ID) {
868        $Content .= $INDENT;
869    }
870    $Content .= "</".$Tag.">\n";
871    return $Content;
872}
873
874sub checkTags()
875{
876    if($TAG_ID!=0) {
877        printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
878    }
879}
880
881return 1;