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