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