~ubuntu-branches/debian/sid/abi-compliance-checker/sid

« back to all changes in this revision

Viewing changes to abi-compliance-checker.pl

  • Committer: Package Import Robot
  • Author(s): Mathieu Malaterre
  • Date: 2013-06-11 10:48:45 UTC
  • mfrom: (1.1.7)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: package-import@ubuntu.com-20130611104845-z4316jm22tc4yl6e
Tags: upstream-1.99.1
ImportĀ upstreamĀ versionĀ 1.99.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/perl
2
2
###########################################################################
3
 
# ABI Compliance Checker (ACC) 1.97.7
 
3
# ABI Compliance Checker (ACC) 1.99.1
4
4
# A tool for checking backward compatibility of a C/C++ library API
5
5
#
6
6
# Copyright (C) 2009-2010 The Linux Foundation
7
7
# Copyright (C) 2009-2011 Institute for System Programming, RAS
8
8
# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9
 
# Copyright (C) 2011-2012 ROSA Laboratory
 
9
# Copyright (C) 2011-2013 ROSA Laboratory
10
10
#
11
11
# Written by Andrey Ponomarenko
12
12
#
20
20
#    - G++ (3.0-4.7, recommended 4.5 or newer)
21
21
#    - GNU Binutils (readelf, c++filt, objdump)
22
22
#    - Perl 5 (5.8 or newer)
 
23
#    - Ctags (5.8 or newer)
23
24
#
24
25
#  Mac OS X
25
 
#    - Xcode (gcc, otool, c++filt)
 
26
#    - Xcode (g++, c++filt, otool, nm)
 
27
#    - Ctags (5.8 or newer)
26
28
#
27
29
#  MS Windows
28
30
#    - MinGW (3.0-4.7, recommended 4.5 or newer)
30
32
#    - Active Perl 5 (5.8 or newer)
31
33
#    - Sigcheck v1.71 or newer
32
34
#    - Info-ZIP 3.0 (zip, unzip)
33
 
#    - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
 
35
#    - Ctags (5.8 or newer)
 
36
#    - Add tool locations to the PATH environment variable
34
37
#    - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
35
38
#
 
39
# COMPATIBILITY
 
40
# =============
 
41
#  ABI Dumper >= 0.97
 
42
#
 
43
#
36
44
# This program is free software: you can redistribute it and/or modify
37
45
# it under the terms of the GNU General Public License or the GNU Lesser
38
46
# General Public License as published by the Free Software Foundation.
51
59
use File::Path qw(mkpath rmtree);
52
60
use File::Temp qw(tempdir);
53
61
use File::Copy qw(copy move);
54
 
use Cwd qw(abs_path cwd);
 
62
use Cwd qw(abs_path cwd realpath);
55
63
use Data::Dumper;
56
64
use Config;
57
65
 
58
 
my $TOOL_VERSION = "1.97.7";
59
 
my $ABI_DUMP_VERSION = "2.16";
 
66
my $TOOL_VERSION = "1.99.1";
 
67
my $ABI_DUMP_VERSION = "3.1";
60
68
my $OLDEST_SUPPORTED_VERSION = "1.18";
61
 
my $XML_REPORT_VERSION = "1.0";
 
69
my $XML_REPORT_VERSION = "1.1";
 
70
my $XML_ABI_DUMP_VERSION = "1.2";
62
71
my $OSgroup = get_OSgroup();
63
72
my $ORIG_DIR = cwd();
64
73
my $TMP_DIR = tempdir(CLEANUP=>1);
75
84
$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
76
85
$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
77
86
%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
78
 
%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
 
87
%TargetVersion, $InfoMsg, $UseOldDumps, $CrossGcc, %OutputLogPath,
79
88
$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
80
89
$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
81
90
$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
82
 
$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
 
91
$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
83
92
$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
84
 
$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump);
 
93
$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
 
94
$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath);
85
95
 
86
96
my $CmdName = get_filename($0);
87
97
my %OS_LibExt = (
88
98
    "dynamic" => {
89
 
        "default"=>"so",
 
99
        "linux"=>"so",
90
100
        "macos"=>"dylib",
91
101
        "windows"=>"dll",
92
 
        "symbian"=>"dso"
 
102
        "symbian"=>"dso",
 
103
        "default"=>"so"
93
104
    },
94
105
    "static" => {
95
 
        "default"=>"a",
 
106
        "linux"=>"a",
96
107
        "windows"=>"lib",
97
 
        "symbian"=>"lib"
 
108
        "symbian"=>"lib",
 
109
        "default"=>"a"
98
110
    }
99
111
);
100
112
 
162
174
 
163
175
More info: $CmdName --help\n";
164
176
 
165
 
if($#ARGV==-1) {
 
177
if($#ARGV==-1)
 
178
{
166
179
    printMsg("INFO", $ShortUsage);
167
180
    exit(0);
168
181
}
169
182
 
170
183
foreach (2 .. $#ARGV)
171
184
{ # correct comma separated options
172
 
    if($ARGV[$_-1] eq ",") {
 
185
    if($ARGV[$_-1] eq ",")
 
186
    {
173
187
        $ARGV[$_-2].=",".$ARGV[$_];
174
188
        splice(@ARGV, $_-1, 2);
175
189
    }
176
 
    elsif($ARGV[$_-1]=~/,\Z/) {
 
190
    elsif($ARGV[$_-1]=~/,\Z/)
 
191
    {
177
192
        $ARGV[$_-1].=$ARGV[$_];
178
193
        splice(@ARGV, $_, 1);
179
194
    }
180
195
    elsif($ARGV[$_]=~/\A,/
181
 
    and $ARGV[$_] ne ",") {
 
196
    and $ARGV[$_] ne ",")
 
197
    {
182
198
        $ARGV[$_-1].=$ARGV[$_];
183
199
        splice(@ARGV, $_, 1);
184
200
    }
205
221
  "v2|version2=s" => \$TargetVersion{2},
206
222
  "s|strict!" => \$StrictCompat,
207
223
  "symbols-list=s" => \$SymbolsListPath,
 
224
  "skip-symbols=s" => \$SkipSymbolsListPath,
 
225
  "headers-list=s" => \$TargetHeadersPath,
208
226
  "skip-headers=s" => \$SkipHeadersPath,
 
227
  "header=s" => \$TargetHeader,
209
228
  "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
210
229
  "objects-only!" => \$CheckObjectsOnly_Opt,
211
230
  "check-impl|check-implementation!" => \$CheckImpl,
216
235
  "sysinfo=s" => \$TargetSysInfo,
217
236
  "cmp-systems!" => \$CmpSystems,
218
237
  "libs-list=s" => \$TargetLibsPath,
219
 
  "headers-list=s" => \$TargetHeadersPath,
220
 
  "header=s" => \$TargetHeader,
221
238
  "ext|extended!" => \$ExtendedCheck,
222
239
  "q|quiet!" => \$Quiet,
223
240
  "stdout!" => \$StdOut,
224
241
  "report-format=s" => \$ReportFormat,
 
242
  "dump-format=s" => \$DumpFormat,
225
243
  "xml!" => \$UseXML,
226
244
  "lang=s" => \$UserLang,
227
245
  "binary|bin|abi!" => \$BinaryOnly,
230
248
  "test!" => \$TestTool,
231
249
  "test-dump!" => \$TestDump,
232
250
  "debug!" => \$Debug,
233
 
  "cpp-compatible!" => \$Cpp2003,
 
251
  "cpp-compatible!" => \$CppCompat,
234
252
  "p|params=s" => \$ParamNamesPath,
235
253
  "relpath1|relpath=s" => \$RelativeDirectory{1},
236
254
  "relpath2=s" => \$RelativeDirectory{2},
247
265
  "l-full|lib-full=s" => \$TargetLibraryFName,
248
266
  "component=s" => \$TargetComponent_Opt,
249
267
  "b|browse=s" => \$Browse,
250
 
  "open!" => \$OpenReport
 
268
  "open!" => \$OpenReport,
 
269
  "extra-info=s" => \$ExtraInfo,
 
270
  "extra-dump!" => \$ExtraDump,
 
271
  "force!" => \$Force,
 
272
  "tolerance=s" => \$Tolerance,
 
273
  "tolerant!" => \$Tolerant
251
274
) or ERR_MESSAGE();
252
275
 
253
276
sub ERR_MESSAGE()
333
356
      Print the tool version ($TOOL_VERSION) and don't do anything else.
334
357
 
335
358
GENERAL OPTIONS:
336
 
  -l|-lib|-library <name>
 
359
  -l|-lib|-library NAME
337
360
      Library name (without version).
338
 
      It affects only on the path and the title of the report.
339
361
 
340
 
  -d1|-old|-o <path>
 
362
  -d1|-old|-o PATH
341
363
      Descriptor of 1st (old) library version.
342
364
      It may be one of the following:
343
365
      
369
391
         6. Comma separated list of headers and/or libraries
370
392
 
371
393
      If you are using an 2-6 descriptor types then you should
372
 
      specify version numbers with -v1 <num> and -v2 <num> options too.
 
394
      specify version numbers with -v1 and -v2 options too.
373
395
 
374
396
      For more information, please see:
375
397
        http://ispras.linuxbase.org/index.php/Library_Descriptor
376
398
 
377
 
  -d2|-new|-n <path>
 
399
  -d2|-new|-n PATH
378
400
      Descriptor of 2nd (new) library version.
379
401
 
380
 
  -dump|-dump-abi <descriptor path(s)>
381
 
      Dump library ABI to gzipped TXT format file. You can transfer it
382
 
      anywhere and pass instead of the descriptor. Also it can be used
383
 
      for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
 
402
  -dump|-dump-abi PATH
 
403
      Create library ABI dump for the input XML descriptor. You can
 
404
      transfer it anywhere and pass instead of the descriptor. Also
 
405
      it can be used for debugging the tool.
 
406
      
 
407
      Supported ABI dump versions: 2.0<=V<=$ABI_DUMP_VERSION
384
408
 
385
409
  -old-dumps
386
 
      Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
 
410
      Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0).\n";
387
411
 
388
412
sub HELP_MESSAGE() {
389
413
    printMsg("INFO", $HelpMessage."
398
422
  -d|-descriptor-template
399
423
      Create XML-descriptor template ./VERSION.xml
400
424
 
401
 
  -app|-application <path>
 
425
  -app|-application PATH
402
426
      This option allows to specify the application that should be checked
403
427
      for portability to the new library version.
404
428
 
406
430
      Check static libraries instead of the shared ones. The <libs> section
407
431
      of the XML-descriptor should point to static libraries location.
408
432
 
409
 
  -cross-gcc|-gcc-path <path>
 
433
  -cross-gcc|-gcc-path PATH
410
434
      Path to the cross GCC compiler to use instead of the usual (host) GCC.
411
435
 
412
 
  -cross-prefix|-gcc-prefix <prefix>
 
436
  -cross-prefix|-gcc-prefix PREFIX
413
437
      GCC toolchain prefix.
414
438
 
415
 
  -sysroot <dirpath>
 
439
  -sysroot DIR
416
440
      Specify the alternative root directory. The tool will search for include
417
 
      paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
 
441
      paths in the DIR/usr/include and DIR/usr/lib directories.
418
442
 
419
 
  -v1|-version1 <num>
 
443
  -v1|-version1 NUM
420
444
      Specify 1st library version outside the descriptor. This option is needed
421
445
      if you have prefered an alternative descriptor type (see -d1 option).
422
446
 
425
449
              VERSION
426
450
          </version>
427
451
 
428
 
  -v2|-version2 <num>
 
452
  -v2|-version2 NUM
429
453
      Specify 2nd library version outside the descriptor.
430
454
 
431
455
  -s|-strict
462
486
  -show-retval
463
487
      Show the symbol's return type in the report.
464
488
 
465
 
  -symbols-list <path>
 
489
  -symbols-list PATH
466
490
      This option allows to specify a file with a list of symbols (mangled
467
491
      names in C++) that should be checked, other symbols will not be checked.
 
492
      
 
493
  -skip-symbols PATH
 
494
      The list of symbols that should NOT be checked.
468
495
 
469
 
  -skip-headers <path>
 
496
  -headers-list PATH
 
497
      The file with a list of headers, that should be checked/dumped.
 
498
      
 
499
  -skip-headers PATH
470
500
      The file with the list of header files, that should not be checked.
 
501
      
 
502
  -header NAME
 
503
      Check/Dump ABI of this header only.
471
504
 
472
505
  -use-dumps
473
506
      Make dumps for two versions of a library and compare dumps. This should
474
507
      increase the performance of the tool and decrease the system memory usage.
475
508
 
476
509
  -nostdinc
477
 
      Do not search the GCC standard system directories for header files.
 
510
      Do not search in GCC standard system directories for header files.
478
511
 
479
 
  -dump-system <name> -sysroot <dirpath>
480
 
      Find all the shared libraries and header files in <dirpath> directory,
 
512
  -dump-system NAME -sysroot DIR
 
513
      Find all the shared libraries and header files in DIR directory,
481
514
      create XML descriptors and make ABI dumps for each library. The result
482
515
      set of ABI dumps can be compared (--cmp-systems) with the other one
483
516
      created for other version of operating system in order to check them for
484
517
      compatibility. Do not forget to specify -cross-gcc option if your target
485
518
      system requires some specific version of GCC compiler (different from
486
519
      the host GCC). The system ABI dump will be generated to:
487
 
          sys_dumps/<name>/<arch>
 
520
          sys_dumps/NAME/ARCH
488
521
          
489
 
  -dump-system <descriptor.xml>
 
522
  -dump-system DESCRIPTOR.xml
490
523
      The same as the previous option but takes an XML descriptor of the target
491
524
      system as input, where you should describe it:
492
525
          
536
569
              /* Additional GCC options, one per line */
537
570
          </gcc_options>
538
571
 
539
 
  -sysinfo <dir>
 
572
  -sysinfo DIR
540
573
      This option may be used with -dump-system to dump ABI of operating
541
574
      systems and configure the dumping process.
542
575
      Default:
543
576
          modules/Targets/{unix, symbian, windows}
544
577
 
545
 
  -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
 
578
  -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
546
579
      Compare two system ABI dumps. Create compatibility reports for each
547
580
      library and the common HTML report including the summary of test
548
581
      results for all checked libraries. Report will be generated to:
549
 
          sys_compat_reports/<name1>_to_<name2>/<arch>
 
582
          sys_compat_reports/NAME1_to_NAME2/ARCH
550
583
 
551
 
  -libs-list <path>
 
584
  -libs-list PATH
552
585
      The file with a list of libraries, that should be dumped by
553
586
      the -dump-system option or should be checked by the -cmp-systems option.
554
587
 
555
 
  -header <name>
556
 
      Check/Dump ABI of this header only.
557
 
 
558
 
  -headers-list <path>
559
 
      The file with a list of headers, that should be checked/dumped.
560
 
 
561
588
  -ext|-extended
562
589
      If your library A is supposed to be used by other library B and you
563
590
      want to control the ABI of B, then you should enable this option. The
577
604
      Print analysis results (compatibility reports and ABI dumps) to stdout
578
605
      instead of creating a file. This would allow piping data to other programs.
579
606
 
580
 
  -report-format <fmt>
 
607
  -report-format FMT
581
608
      Change format of compatibility report.
582
609
      Formats:
583
610
        htm - HTML format (default)
584
611
        xml - XML format
585
612
 
 
613
  -dump-format FMT
 
614
      Change format of ABI dump.
 
615
      Formats:
 
616
        perl - Data::Dumper format (default)
 
617
        xml - XML format
 
618
 
586
619
  -xml
587
 
      Alias for: --report-format=xml
 
620
      Alias for: --report-format=xml or --dump-format=xml
588
621
 
589
 
  -lang <lang>
 
622
  -lang LANG
590
623
      Set library language (C or C++). You can use this option if the tool
591
624
      cannot auto-detect a language. This option may be useful for checking
592
625
      C-library headers (--lang=C) in --headers-only or --extended modes.
594
627
  -binary|-bin|-abi
595
628
      Show \"Binary\" compatibility problems only.
596
629
      Generate report to:
597
 
        compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
 
630
        compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
598
631
      
599
632
  -source|-src|-api
600
633
      Show \"Source\" compatibility problems only.
601
634
      Generate report to:
602
 
        compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
 
635
        compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
603
636
 
604
637
OTHER OPTIONS:
605
638
  -test
613
646
  -debug
614
647
      Debugging mode. Print debug info on the screen. Save intermediate
615
648
      analysis stages in the debug directory:
616
 
          debug/<library>/<version>/
 
649
          debug/LIB_NAME/VERSION/
617
650
 
618
651
      Also consider using --dump option for debugging the tool.
619
652
 
620
653
  -cpp-compatible
621
 
      If your header file is written in C language and can be compiled by
622
 
      the C++ compiler (i.e. doesn't contain C++-keywords and other bad
623
 
      things), then you can tell ACC about this and speedup the analysis.
 
654
      If your header files are written in C language and can be compiled
 
655
      by the G++ compiler (i.e. don't use C++ keywords), then you can tell
 
656
      the tool about this and speedup the analysis.
624
657
 
625
 
  -p|-params <path>
 
658
  -p|-params PATH
626
659
      Path to file with the function parameter names. It can be used
627
660
      for improving report view if the library header files have no
628
661
      parameter names. File format:
631
664
            func2;param1;param2;param3 ...
632
665
             ...
633
666
 
634
 
  -relpath <path>
635
 
      Replace {RELPATH} macros to <path> in the XML-descriptor used
 
667
  -relpath PATH
 
668
      Replace {RELPATH} macros to PATH in the XML-descriptor used
636
669
      for dumping the library ABI (see -dump option).
637
670
  
638
 
  -relpath1 <path>
639
 
      Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
640
 
 
641
 
  -relpath2 <path>
642
 
      Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
643
 
 
644
 
  -dump-path <path>
645
 
      Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
 
671
  -relpath1 PATH
 
672
      Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
 
673
 
 
674
  -relpath2 PATH
 
675
      Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
 
676
 
 
677
  -dump-path PATH
 
678
      Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
646
679
      Default: 
647
 
          abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
 
680
          abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
648
681
 
649
682
  -sort
650
683
      Enable sorting of data in ABI dumps.
651
684
 
652
 
  -report-path <path>
 
685
  -report-path PATH
653
686
      Path to compatibility report.
654
687
      Default: 
655
 
          compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
 
688
          compat_reports/LIB_NAME/V1_to_V2/compat_report.html
656
689
 
657
 
  -bin-report-path <path>
 
690
  -bin-report-path PATH
658
691
      Path to \"Binary\" compatibility report.
659
692
      Default: 
660
 
          compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
 
693
          compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
661
694
 
662
 
  -src-report-path <path>
 
695
  -src-report-path PATH
663
696
      Path to \"Source\" compatibility report.
664
697
      Default: 
665
 
          compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
 
698
          compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
666
699
 
667
 
  -log-path <path>
 
700
  -log-path PATH
668
701
      Log path for all messages.
669
702
      Default:
670
 
          logs/<library>/<version>/log.txt
 
703
          logs/LIB_NAME/VERSION/log.txt
671
704
 
672
 
  -log1-path <path>
 
705
  -log1-path PATH
673
706
      Log path for 1st version of a library.
674
707
      Default:
675
 
          logs/<library name>/<v1>/log.txt
 
708
          logs/LIB_NAME/V1/log.txt
676
709
 
677
 
  -log2-path <path>
 
710
  -log2-path PATH
678
711
      Log path for 2nd version of a library.
679
712
      Default:
680
 
          logs/<library name>/<v2>/log.txt
 
713
          logs/LIB_NAME/V2/log.txt
681
714
 
682
 
  -logging-mode <mode>
 
715
  -logging-mode MODE
683
716
      Change logging mode.
684
717
      Modes:
685
718
        w - overwrite old logs (default)
695
728
          abi_affected.txt
696
729
          src_affected.txt
697
730
 
698
 
  -component <name>
 
731
  -component NAME
699
732
      The component name in the title and summary of the HTML report.
700
733
      Default:
701
734
          library
702
735
      
703
 
  -l-full|-lib-full <name>
704
 
      Change library name in the report title to <name>. By default
 
736
  -l-full|-lib-full NAME
 
737
      Change library name in the report title to NAME. By default
705
738
      will be displayed a name specified by -l option.
706
739
 
707
 
  -b|-browse <program>
 
740
  -b|-browse PROGRAM
708
741
      Open report(s) in the browser (firefox, opera, etc.).
709
742
 
710
743
  -open
711
744
      Open report(s) in the default browser.
 
745
      
 
746
  -extra-info DIR
 
747
      Dump extra info to DIR.
 
748
      
 
749
  -extra-dump
 
750
      Create extended ABI dump containing all symbols
 
751
      from the translation unit.
 
752
      
 
753
  -force
 
754
      Try to use this option if the tool doesn't work.
 
755
      
 
756
  -tolerance LEVEL
 
757
      Apply a set of heuristics to successfully compile input
 
758
      header files. You can enable several tolerance levels by
 
759
      joining them into one string (e.g. 13, 124, etc.).
 
760
      Levels:
 
761
          1 - skip non-Linux headers (e.g. win32_*.h, etc.)
 
762
          2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.)
 
763
          3 - skip headers that iclude non-Linux headers
 
764
          4 - skip headers included by others
 
765
          
 
766
  -tolerant
 
767
      Enable highest tolerance level [1234].
712
768
 
713
769
REPORT:
714
770
    Compatibility report will be generated to:
715
 
        compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
 
771
        compat_reports/LIB_NAME/V1_to_V2/compat_report.html
716
772
 
717
773
    Log will be generated to:
718
 
        logs/<library name>/<v1>/log.txt
719
 
        logs/<library name>/<v2>/log.txt
 
774
        logs/LIB_NAME/V1/log.txt
 
775
        logs/LIB_NAME/V2/log.txt
720
776
 
721
777
EXIT CODES:
722
778
    0 - Compatible. The tool has run without any errors.
775
831
 
776
832
<include_preamble>
777
833
    /* The list of header files that will be
778
 
       included before other headers, one per line.
779
 
       Examples:
780
 
           1) tree.h for libxml2
781
 
           2) ft2build.h for freetype2 */
 
834
       included before other headers, one per line  */
782
835
</include_preamble>
783
836
 
784
837
<defines>
788
841
          #define C D */
789
842
</defines>
790
843
 
 
844
<add_namespaces>
 
845
    /* The list of namespaces that should be added to the alanysis
 
846
       if the tool cannot find them automatically, one per line */
 
847
</add_namespaces>
 
848
 
791
849
<skip_types>
792
850
    /* The list of data types, that
793
851
       should not be checked, one per line */
931
989
  "union_type" => "Union",
932
990
  "var_decl" => "Other",
933
991
  "void_type" => "Intrinsic",
934
 
  # "nop_expr" => "Other",
935
 
  # "addr_expr" => "Other",
 
992
  "nop_expr" => "Other", #
 
993
  "addr_expr" => "Other", #
936
994
  "offset_type" => "Other" );
937
995
 
938
996
my %CppKeywords_C = map {$_=>1} (
997
1055
 
998
1056
my %CppKeywords_A = map {$_=>1} (
999
1057
    "this",
1000
 
    "throw"
 
1058
    "throw",
 
1059
    "template"
1001
1060
);
1002
1061
 
1003
1062
foreach (keys(%CppKeywords_C),
1045
1104
    "3std14basic_iostreamIcE"=>"Sd"
1046
1105
);
1047
1106
 
 
1107
my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
 
1108
 
1048
1109
my %ConstantSuffix = (
1049
1110
    "unsigned int"=>"u",
1050
1111
    "long"=>"l",
1171
1232
    "stdio.h",
1172
1233
    "stdlib.h",
1173
1234
    "string.h",
 
1235
    "strings.h",
1174
1236
    "tar.h",
1175
1237
    "termios.h",
1176
1238
    "time.h",
1192
1254
    "sys",
1193
1255
    "linux" );
1194
1256
 
 
1257
my %WinHeaders = map {$_=>1} (
 
1258
    "dos.h",
 
1259
    "process.h",
 
1260
    "winsock.h",
 
1261
    "config-win.h",
 
1262
    "mem.h",
 
1263
    "windows.h",
 
1264
    "winsock2.h",
 
1265
    "crtdbg.h",
 
1266
    "ws2tcpip.h"
 
1267
);
 
1268
 
 
1269
my %ObsoleteHeaders = map {$_=>1} (
 
1270
    "iostream.h",
 
1271
    "fstream.h"
 
1272
);
 
1273
 
 
1274
my %AlienHeaders = map {$_=>1} (
 
1275
 # Solaris
 
1276
    "thread.h",
 
1277
    "sys/atomic.h",
 
1278
 # HPUX
 
1279
    "sys/stream.h",
 
1280
 # Symbian
 
1281
    "AknDoc.h",
 
1282
 # Atari ST
 
1283
    "ext.h",
 
1284
    "tos.h",
 
1285
 # MS-DOS
 
1286
    "alloc.h",
 
1287
 # Sparc
 
1288
    "sys/atomic.h"
 
1289
);
 
1290
 
 
1291
my %ConfHeaders = map {$_=>1} (
 
1292
    "atomic",
 
1293
    "conf.h",
 
1294
    "config.h",
 
1295
    "configure.h",
 
1296
    "build.h",
 
1297
    "setup.h"
 
1298
);
 
1299
 
1195
1300
my %LocalIncludes = map {$_=>1} (
1196
1301
    "/usr/local/include",
1197
1302
    "/usr/local" );
1199
1304
my %OS_AddPath=(
1200
1305
# These paths are needed if the tool cannot detect them automatically
1201
1306
    "macos"=>{
1202
 
        "include"=>{
1203
 
            "/Library"=>1,
1204
 
            "/Developer/usr/include"=>1
1205
 
        },
1206
 
        "lib"=>{
1207
 
            "/Library"=>1,
1208
 
            "/Developer/usr/lib"=>1
1209
 
        },
1210
 
        "bin"=>{
1211
 
            "/Developer/usr/bin"=>1
1212
 
        }
 
1307
        "include"=>[
 
1308
            "/Library",
 
1309
            "/Developer/usr/include"
 
1310
        ],
 
1311
        "lib"=>[
 
1312
            "/Library",
 
1313
            "/Developer/usr/lib"
 
1314
        ],
 
1315
        "bin"=>[
 
1316
            "/Developer/usr/bin"
 
1317
        ]
1213
1318
    },
1214
1319
    "beos"=>{
1215
1320
    # Haiku has GCC 2.95.3 by default
1216
1321
    # try to find GCC>=3.0 in /boot/develop/abi
1217
 
        "include"=>{
1218
 
            "/boot/common"=>1,
1219
 
            "/boot/develop"=>1},
1220
 
        "lib"=>{
1221
 
            "/boot/common/lib"=>1,
1222
 
            "/boot/system/lib"=>1,
1223
 
            "/boot/apps"=>1},
1224
 
        "bin"=>{
1225
 
            "/boot/common/bin"=>1,
1226
 
            "/boot/system/bin"=>1,
1227
 
            "/boot/develop/abi"=>1
 
1322
        "include"=>[
 
1323
            "/boot/common",
 
1324
            "/boot/develop"
 
1325
        ],
 
1326
        "lib"=>[
 
1327
            "/boot/common/lib",
 
1328
            "/boot/system/lib",
 
1329
            "/boot/apps"
 
1330
        ],
 
1331
        "bin"=>[
 
1332
            "/boot/common/bin",
 
1333
            "/boot/system/bin",
 
1334
            "/boot/develop/abi"
 
1335
        ]
1228
1336
    }
1229
 
}
1230
1337
);
1231
1338
 
1232
1339
my %Slash_Type=(
1242
1349
  2 => "C" );
1243
1350
 
1244
1351
my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
 
1352
my $MAX_CPPFILT_FILE_SIZE = 50000;
 
1353
my $CPPFILT_SUPPORT_FILE;
 
1354
 
1245
1355
my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1246
1356
 
1247
1357
my $STDCXX_TESTING = 0;
1248
1358
my $GLIBC_TESTING = 0;
 
1359
my $CPP_HEADERS = 0;
1249
1360
 
1250
1361
my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1251
1362
my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
 
1363
 
1252
1364
my $TargetComponent;
1253
1365
 
 
1366
my $CheckUndefined = 0;
 
1367
 
1254
1368
# Set Target Component Name
1255
1369
if($TargetComponent_Opt) {
1256
1370
    $TargetComponent = lc($TargetComponent_Opt);
1279
1393
# Constants (#defines)
1280
1394
my %Constants;
1281
1395
my %SkipConstants;
 
1396
my %EnumConstants;
 
1397
 
 
1398
# Extra Info
 
1399
my %SymbolHeader;
 
1400
my %KnownLibs;
1282
1401
 
1283
1402
# Types
1284
1403
my %TypeInfo;
1304
1423
my %ClassNames;
1305
1424
my %Class_SubClasses;
1306
1425
my %OverriddenMethods;
 
1426
my %TypedefToAnon;
1307
1427
my $MAX_ID = 0;
1308
1428
 
1309
1429
# Typedefs
1314
1434
my %MissedTypedef;
1315
1435
my %MissedBase;
1316
1436
my %MissedBase_R;
 
1437
my %TypeTypedef;
1317
1438
 
1318
1439
# Symbols
1319
1440
my %SymbolInfo;
1326
1447
my %SkipNameSpaces = (
1327
1448
  "1"=>{},
1328
1449
  "2"=>{} );
 
1450
my %AddNameSpaces = (
 
1451
  "1"=>{},
 
1452
  "2"=>{} );
1329
1453
my %SymbolsList;
 
1454
my %SkipSymbolsList;
1330
1455
my %SymbolsList_App;
1331
1456
my %CheckedSymbols;
1332
1457
my %Symbol_Library = (
1342
1467
  "1"=>{},
1343
1468
  "2"=>{} );
1344
1469
my %MangledNames;
 
1470
my %Func_ShortName;
1345
1471
my %AddIntParams;
1346
1472
my %Interface_Impl;
1347
1473
my %GlobalDataObject;
 
1474
my %WeakSymbols;
 
1475
my %Library_Needed= (
 
1476
  "1"=>{},
 
1477
  "2"=>{} );
 
1478
 
 
1479
# Extra Info
 
1480
my %UndefinedSymbols;
 
1481
my %PreprocessedHeaders;
1348
1482
 
1349
1483
# Headers
1350
 
my %Include_Preamble;
 
1484
my %Include_Preamble = (
 
1485
    "1"=>[],
 
1486
    "2"=>[] );
1351
1487
my %Registered_Headers;
 
1488
my %Registered_Sources;
1352
1489
my %HeaderName_Paths;
1353
1490
my %Header_Dependency;
1354
1491
my %Include_Neighbors;
1355
 
my %Include_Paths;
 
1492
my %Include_Paths = (
 
1493
    "1"=>[],
 
1494
    "2"=>[] );
1356
1495
my %INC_PATH_AUTODETECT = (
1357
1496
  "1"=>1,
1358
1497
  "2"=>1 );
1359
 
my %Add_Include_Paths;
 
1498
my %Add_Include_Paths = (
 
1499
    "1"=>[],
 
1500
    "2"=>[] );
1360
1501
my %Skip_Include_Paths;
1361
1502
my %RegisteredDirs;
1362
1503
my %Header_ErrorRedirect;
1363
1504
my %Header_Includes;
 
1505
my %Header_Includes_R;
1364
1506
my %Header_ShouldNotBeUsed;
1365
1507
my %RecursiveIncludes;
1366
1508
my %Header_Include_Prefix;
1371
1513
my %SkipLibs;
1372
1514
my %Include_Order;
1373
1515
my %TUnit_NameSpaces;
 
1516
my %TUnit_Classes;
 
1517
my %TUnit_Funcs;
 
1518
my %TUnit_Vars;
1374
1519
 
1375
 
my %C99Mode = (
 
1520
my %CppMode = (
1376
1521
  "1"=>0,
1377
1522
  "2"=>0 );
1378
1523
my %AutoPreambleMode = (
1381
1526
my %MinGWMode = (
1382
1527
  "1"=>0,
1383
1528
  "2"=>0 );
 
1529
my %Cpp0xMode = (
 
1530
  "1"=>0,
 
1531
  "2"=>0 );
1384
1532
 
1385
1533
# Shared Objects
1386
 
my %DyLib_DefaultPath;
1387
 
my %InputObject_Paths;
1388
 
my %RegisteredObjDirs;
 
1534
my %RegisteredObjects;
 
1535
my %RegisteredObjects_Short;
 
1536
my %RegisteredSONAMEs;
 
1537
my %RegisteredObject_Dirs;
1389
1538
 
1390
1539
# System Objects
1391
1540
my %SystemObjects;
1392
 
my %DefaultLibPaths;
 
1541
my @DefaultLibPaths;
 
1542
my %DyLib_DefaultPath;
1393
1543
 
1394
1544
# System Headers
1395
1545
my %SystemHeaders;
1396
 
my %DefaultCppPaths;
1397
 
my %DefaultGccPaths;
1398
 
my %DefaultIncPaths;
 
1546
my @DefaultCppPaths;
 
1547
my @DefaultGccPaths;
 
1548
my @DefaultIncPaths;
1399
1549
my %DefaultCppHeader;
1400
1550
my %DefaultGccHeader;
1401
 
my %UserIncPath;
 
1551
my @UsersIncPath;
1402
1552
 
1403
1553
# Merging
1404
1554
my %CompleteSignature;
1420
1570
my %SourceAlternative_B;
1421
1571
my %SourceReplacement;
1422
1572
 
 
1573
# Calling Conventions
 
1574
my %UseConv_Real = (
 
1575
  1=>{ "R"=>0, "P"=>0 },
 
1576
  2=>{ "R"=>0, "P"=>0 }
 
1577
);
 
1578
 
 
1579
# ABI Dump
 
1580
my %UsedDump;
 
1581
 
1423
1582
# OS Compliance
1424
1583
my %TargetLibs;
1425
1584
my %TargetHeaders;
1433
1592
 
1434
1593
# Recursion locks
1435
1594
my @RecurLib;
1436
 
my @RecurSymlink;
1437
1595
my @RecurTypes;
 
1596
my @RecurTypes_Diff;
1438
1597
my @RecurInclude;
1439
1598
my @RecurConstant;
1440
1599
 
1441
1600
# System
1442
 
my %SystemPaths;
1443
 
my %DefaultBinPaths;
 
1601
my %SystemPaths = (
 
1602
    "include"=>[],
 
1603
    "lib"=>[],
 
1604
    "bin"=>[]
 
1605
);
 
1606
my @DefaultBinPaths;
1444
1607
my $GCC_PATH;
1445
1608
 
1446
1609
# Symbols versioning
1450
1613
 
1451
1614
# Problem descriptions
1452
1615
my %CompatProblems;
1453
 
my %ProblemsWithConstants;
1454
 
my %ImplProblems;
 
1616
my %CompatProblems_Constants;
 
1617
my %CompatProblems_Impl;
1455
1618
my %TotalAffected;
1456
1619
 
1457
1620
# Reports
1480
1643
        abs_path($TOOL_DIR),
1481
1644
        # relative path to modules
1482
1645
        abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1483
 
        # system directory
1484
 
        "ACC_MODULES_INSTALL_PATH"
 
1646
        # install path
 
1647
        'MODULES_INSTALL_PATH'
1485
1648
    );
1486
1649
    foreach my $DIR (@SEARCH_DIRS)
1487
1650
    {
1496
1659
    exitStatus("Module_Error", "can't find modules");
1497
1660
}
1498
1661
 
 
1662
my %LoadedModules = ();
 
1663
 
1499
1664
sub loadModule($)
1500
1665
{
1501
1666
    my $Name = $_[0];
 
1667
    if(defined $LoadedModules{$Name}) {
 
1668
        return;
 
1669
    }
1502
1670
    my $Path = $MODULES_DIR."/Internals/$Name.pm";
1503
1671
    if(not -f $Path) {
1504
1672
        exitStatus("Module_Error", "can't access \'$Path\'");
1505
1673
    }
1506
1674
    require $Path;
 
1675
    $LoadedModules{$Name} = 1;
 
1676
}
 
1677
 
 
1678
sub readModule($$)
 
1679
{
 
1680
    my ($Module, $Name) = @_;
 
1681
    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
 
1682
    if(not -f $Path) {
 
1683
        exitStatus("Module_Error", "can't access \'$Path\'");
 
1684
    }
 
1685
    return readFile($Path);
1507
1686
}
1508
1687
 
1509
1688
sub showPos($)
1540
1719
    {
1541
1720
        foreach my $Path (@Paths)
1542
1721
        {
1543
 
            if(-f joinPath($Path, $Name)) {
1544
 
                return joinPath($Path, $Name);
 
1722
            if(-f join_P($Path, $Name)) {
 
1723
                return join_P($Path, $Name);
1545
1724
            }
1546
1725
            if($CrossPrefix)
1547
1726
            { # user-defined prefix (arm-none-symbianelf, ...)
1548
 
                my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
 
1727
                my $Candidate = join_P($Path, $CrossPrefix."-".$Name);
1549
1728
                if(-f $Candidate) {
1550
1729
                    return $Candidate;
1551
1730
                }
1639
1818
    if(my $DefaultPath = get_CmdPath_Default($Name)) {
1640
1819
        return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1641
1820
    }
1642
 
    foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
 
1821
    foreach my $Path (@{$SystemPaths{"bin"}})
1643
1822
    {
1644
 
        my $CmdPath = joinPath($Path,$Name);
 
1823
        my $CmdPath = join_P($Path,$Name);
1645
1824
        if(-f $CmdPath)
1646
1825
        {
1647
1826
            if($Name=~/gcc/) {
1667
1846
    my $Name = $_[0];
1668
1847
    if($Name=~/find/)
1669
1848
    { # special case: search for "find" utility
1670
 
        if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
 
1849
        if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
1671
1850
            return "find";
1672
1851
        }
1673
1852
    }
1674
1853
    elsif($Name=~/gcc/) {
1675
1854
        return check_gcc($Name, "3");
1676
1855
    }
1677
 
    if(check_command($Name)) {
 
1856
    if(checkCmd($Name)) {
1678
1857
        return $Name;
1679
1858
    }
1680
1859
    if($OSgroup eq "windows")
1681
1860
    {
1682
 
        if(`$Name /? 2>$TMP_DIR/null`) {
 
1861
        if(`$Name /? 2>\"$TMP_DIR/null\"`) {
1683
1862
            return $Name;
1684
1863
        }
1685
1864
    }
1686
 
    if($Name!~/which/)
1687
 
    {
1688
 
        if(my $WhichCmd = get_CmdPath("which"))
1689
 
        {
1690
 
            if(`$WhichCmd $Name 2>$TMP_DIR/null`) {
1691
 
                return $Name;
1692
 
            }
1693
 
        }
1694
 
    }
1695
 
    foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
 
1865
    foreach my $Path (@DefaultBinPaths)
1696
1866
    {
1697
1867
        if(-f $Path."/".$Name) {
1698
 
            return joinPath($Path,$Name);
 
1868
            return join_P($Path, $Name);
1699
1869
        }
1700
1870
    }
1701
1871
    return "";
1702
1872
}
1703
1873
 
1704
 
sub clean_path($)
1705
 
{
1706
 
    my $Path = $_[0];
1707
 
    $Path=~s/[\/\\]+\Z//g;
1708
 
    return $Path;
1709
 
}
1710
 
 
1711
1874
sub classifyPath($)
1712
1875
{
1713
1876
    my $Path = $_[0];
1719
1882
    }
1720
1883
    elsif($Path=~/[\/\\]/)
1721
1884
    { # directory or relative path
1722
 
        $Path=~s/[\/\\]+\Z//g;
1723
1885
        return (path_format($Path, $OSgroup), "Path");
1724
1886
    }
1725
1887
    else {
1736
1898
        exitStatus("Error", "$DName is empty");
1737
1899
    }
1738
1900
    if($Content!~/\</) {
1739
 
        exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
 
1901
        exitStatus("Error", "incorrect descriptor (see -d1 option)");
1740
1902
    }
1741
1903
    $Content=~s/\/\*(.|\n)+?\*\///g;
1742
1904
    $Content=~s/<\!--(.|\n)+?-->//g;
 
1905
    
1743
1906
    $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1744
1907
    if($TargetVersion{$LibVersion}) {
1745
1908
        $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1807
1970
    }
1808
1971
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1809
1972
    {
1810
 
        $Path = clean_path($Path);
1811
1973
        if(not -d $Path) {
1812
1974
            exitStatus("Access_Error", "can't access directory \'$Path\'");
1813
1975
        }
 
1976
        $Path = get_abs_path($Path);
1814
1977
        $Path = path_format($Path, $OSgroup);
1815
 
        $SystemPaths{"include"}{$Path}=1;
 
1978
        push_U($SystemPaths{"include"}, $Path);
1816
1979
    }
1817
1980
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1818
1981
    {
1819
 
        $Path = clean_path($Path);
1820
1982
        if(not -d $Path) {
1821
1983
            exitStatus("Access_Error", "can't access directory \'$Path\'");
1822
1984
        }
 
1985
        $Path = get_abs_path($Path);
1823
1986
        $Path = path_format($Path, $OSgroup);
1824
 
        $SystemPaths{"lib"}{$Path}=1;
 
1987
        push_U($SystemPaths{"lib"}, $Path);
1825
1988
    }
1826
1989
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1827
1990
    {
1828
 
        $Path=clean_path($Path);
1829
1991
        if(not -d $Path) {
1830
1992
            exitStatus("Access_Error", "can't access directory \'$Path\'");
1831
1993
        }
 
1994
        $Path = get_abs_path($Path);
1832
1995
        $Path = path_format($Path, $OSgroup);
1833
 
        $SystemPaths{"bin"}{$Path}=1;
 
1996
        push_U($SystemPaths{"bin"}, $Path);
1834
1997
        $TargetTools{$Path}=1;
1835
1998
    }
1836
1999
    if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1837
2000
        $CrossPrefix = $Prefix;
1838
2001
    }
 
2002
    $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //=
1839
2003
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1840
2004
    {
1841
 
        $Path=clean_path($Path);
1842
2005
        if(not -d $Path) {
1843
2006
            exitStatus("Access_Error", "can't access directory \'$Path\'");
1844
2007
        }
 
2008
        $Path = get_abs_path($Path);
1845
2009
        $Path = path_format($Path, $OSgroup);
1846
 
        $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
 
2010
        push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
1847
2011
    }
 
2012
    $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"});
1848
2013
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1849
2014
    {
1850
 
        $Path=clean_path($Path);
1851
2015
        if(not -d $Path) {
1852
2016
            exitStatus("Access_Error", "can't access directory \'$Path\'");
1853
2017
        }
 
2018
        $Path = get_abs_path($Path);
1854
2019
        $Path = path_format($Path, $OSgroup);
1855
 
        $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
 
2020
        push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
1856
2021
    }
1857
2022
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1858
 
    {
1859
 
        # skip some auto-generated include paths
1860
 
        $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
 
2023
    { # skip some auto-generated include paths
 
2024
        if(not is_abs($Path))
 
2025
        {
 
2026
            if(my $P = abs_path($Path)) {
 
2027
                $Path = $P;
 
2028
            }
 
2029
        }
 
2030
        $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
1861
2031
    }
1862
2032
    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1863
 
    {
1864
 
        # skip direct including of some headers
1865
 
        $SkipHeadersList{$LibVersion}{$Path} = 2;
 
2033
    { # skip direct including of some headers
1866
2034
        my ($CPath, $Type) = classifyPath($Path);
1867
2035
        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
1868
2036
    }
1869
2037
    $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1870
 
    foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1871
 
        $CompilerOptions{$LibVersion} .= " ".$Option;
 
2038
    foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"}))
 
2039
    {
 
2040
        if($Option!~/\A\-(Wl|l|L)/)
 
2041
        { # skip linker options
 
2042
            $CompilerOptions{$LibVersion} .= " ".$Option;
 
2043
        }
1872
2044
    }
1873
2045
    $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1874
2046
    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1912
2084
    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1913
2085
        $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1914
2086
    }
 
2087
    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
 
2088
        $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
 
2089
    }
1915
2090
    foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1916
2091
        $SkipConstants{$LibVersion}{$Constant} = 1;
1917
2092
    }
1927
2102
    }
1928
2103
}
1929
2104
 
1930
 
sub parseTag($$)
 
2105
sub parseTag(@)
1931
2106
{
1932
 
    my ($CodeRef, $Tag) = @_;
1933
 
    return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1934
 
    if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
 
2107
    my $CodeRef = shift(@_);
 
2108
    my $Tag = shift(@_);
 
2109
    if(not $Tag or not $CodeRef) {
 
2110
        return undef;
 
2111
    }
 
2112
    my $Sp = 0;
 
2113
    if(@_) {
 
2114
        $Sp = shift(@_);
 
2115
    }
 
2116
    my $Start = index(${$CodeRef}, "<$Tag>");
 
2117
    if($Start!=-1)
1935
2118
    {
1936
 
        my $Content = $1;
1937
 
        $Content=~s/(\A\s+|\s+\Z)//g;
1938
 
        return $Content;
1939
 
    }
1940
 
    else {
1941
 
        return "";
1942
 
    }
 
2119
        my $End = index(${$CodeRef}, "</$Tag>");
 
2120
        if($End!=-1)
 
2121
        {
 
2122
            my $TS = length($Tag)+3;
 
2123
            my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
 
2124
            substr($Content, 0, $TS-1, ""); # cut start tag
 
2125
            substr($Content, -$TS, $TS, ""); # cut end tag
 
2126
            if(not $Sp)
 
2127
            {
 
2128
                $Content=~s/\A\s+//g;
 
2129
                $Content=~s/\s+\Z//g;
 
2130
            }
 
2131
            if(substr($Content, 0, 1) ne "<") {
 
2132
                $Content = xmlSpecChars_R($Content);
 
2133
            }
 
2134
            return $Content;
 
2135
        }
 
2136
    }
 
2137
    return undef;
1943
2138
}
1944
2139
 
1945
2140
sub getInfo($)
1951
2146
    
1952
2147
    # processing info
1953
2148
    setTemplateParams_All();
 
2149
    
 
2150
    if($ExtraDump) {
 
2151
        setAnonTypedef_All();
 
2152
    }
 
2153
    
1954
2154
    getTypeInfo_All();
1955
2155
    simplifyNames();
 
2156
    simplifyConstants();
 
2157
    getVarInfo_All();
1956
2158
    getSymbolInfo_All();
1957
 
    getVarInfo_All();
 
2159
    
1958
2160
    
1959
2161
    # clean memory
1960
2162
    %LibInfo = ();
1965
2167
    %MissedTypedef = ();
1966
2168
    %Typedef_Tr = ();
1967
2169
    %Typedef_Eq = ();
 
2170
    %TypedefToAnon = ();
1968
2171
    
1969
2172
    # clean cache
1970
2173
    delete($Cache{"getTypeAttr"});
1971
2174
    delete($Cache{"getTypeDeclId"});
1972
2175
    
1973
 
    # remove unused types
1974
 
    if($BinaryOnly and not $ExtendedCheck)
1975
 
    { # --binary
1976
 
        removeUnused($Version, "All");
 
2176
    if($ExtraDump)
 
2177
    {
 
2178
        foreach (keys(%{$TypeInfo{$Version}}))
 
2179
        {
 
2180
            if($TypeInfo{$Version}{$_}{"Artificial"}) {
 
2181
                delete($TypeInfo{$Version}{$_});
 
2182
            }
 
2183
        }
1977
2184
    }
1978
 
    else {
1979
 
        removeUnused($Version, "Derived");
 
2185
    else
 
2186
    { # remove unused types
 
2187
        if($BinaryOnly and not $ExtendedCheck)
 
2188
        { # --binary
 
2189
            removeUnused($Version, "All");
 
2190
        }
 
2191
        else {
 
2192
            removeUnused($Version, "Extended");
 
2193
        }
1980
2194
    }
1981
2195
    
1982
2196
    if($Debug) {
2020
2234
    undef @Lines;
2021
2235
}
2022
2236
 
 
2237
sub simplifyConstants()
 
2238
{
 
2239
    foreach my $Constant (keys(%{$Constants{$Version}}))
 
2240
    {
 
2241
        if(defined $Constants{$Version}{$Constant}{"Header"})
 
2242
        {
 
2243
            my $Value = $Constants{$Version}{$Constant}{"Value"};
 
2244
            if(defined $EnumConstants{$Version}{$Value}) {
 
2245
                $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"};
 
2246
            }
 
2247
        }
 
2248
    }
 
2249
}
 
2250
 
2023
2251
sub simplifyNames()
2024
2252
{
2025
2253
    foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2026
2254
    {
2027
 
        my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2028
 
        if($#Translations==0 and length($Translations[0])<=length($Base)) {
2029
 
            $Typedef_Eq{$Version}{$Base} = $Translations[0];
 
2255
        if($Typedef_Eq{$Version}{$Base}) {
 
2256
            next;
 
2257
        }
 
2258
        my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
 
2259
        if($#Translations==0)
 
2260
        {
 
2261
            if(length($Translations[0])<=length($Base)) {
 
2262
                $Typedef_Eq{$Version}{$Base} = $Translations[0];
 
2263
            }
 
2264
        }
 
2265
        else
 
2266
        { # select most appropriate
 
2267
            foreach my $Tr (@Translations)
 
2268
            {
 
2269
                if($Base=~/\A\Q$Tr\E/)
 
2270
                {
 
2271
                    $Typedef_Eq{$Version}{$Base} = $Tr;
 
2272
                    last;
 
2273
                }
 
2274
            }
2030
2275
        }
2031
2276
    }
2032
2277
    foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
2039
2284
        if($TypeName=~/>(::\w+)+\Z/)
2040
2285
        { # skip unused types
2041
2286
            next;
2042
 
        };
 
2287
        }
2043
2288
        foreach my $Base (sort {length($b)<=>length($a)}
2044
2289
        sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
2045
2290
        {
2046
2291
            next if(not $Base);
2047
2292
            next if(index($TypeName,$Base)==-1);
2048
2293
            next if(length($TypeName) - length($Base) <= 3);
2049
 
            my $Typedef = $Typedef_Eq{$Version}{$Base};
2050
 
            $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2051
 
            $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2052
 
            if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
 
2294
            if(my $Typedef = $Typedef_Eq{$Version}{$Base})
2053
2295
            {
2054
 
                foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
 
2296
                $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
 
2297
                $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
 
2298
                if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
2055
2299
                {
2056
 
                    my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"};
2057
 
                    $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2058
 
                    $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
 
2300
                    foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
 
2301
                    {
 
2302
                        if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
 
2303
                        {
 
2304
                            $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
 
2305
                            $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
 
2306
                            $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
 
2307
                        }
 
2308
                    }
2059
2309
                }
2060
2310
            }
2061
2311
        }
2062
 
        $TypeName = formatName($TypeName);
 
2312
        $TypeName = formatName($TypeName, "T");
2063
2313
        $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2064
2314
        $TName_Tid{$Version}{$TypeName} = $TypeId;
2065
2315
    }
2066
2316
}
2067
2317
 
 
2318
sub setAnonTypedef_All()
 
2319
{
 
2320
    foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}}))
 
2321
    {
 
2322
        if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl")
 
2323
        {
 
2324
            if(isAnon(getNameByInfo($InfoId))) {
 
2325
                $TypedefToAnon{getTypeId($InfoId)} = 1;
 
2326
            }
 
2327
        }
 
2328
    }
 
2329
}
 
2330
 
2068
2331
sub setTemplateParams_All()
2069
2332
{
2070
2333
    foreach (keys(%{$LibInfo{$Version}{"info"}}))
2174
2437
    }
2175
2438
    
2176
2439
    # add "..." type
2177
 
    $TypeInfo{$Version}{-1} = {
 
2440
    $TypeInfo{$Version}{"-1"} = {
2178
2441
        "Name" => "...",
2179
2442
        "Type" => "Intrinsic",
2180
 
        "Tid" => -1
 
2443
        "Tid" => "-1"
2181
2444
    };
2182
 
    $TName_Tid{$Version}{"..."} = -1;
 
2445
    $TName_Tid{$Version}{"..."} = "-1";
2183
2446
    
2184
2447
    if(not check_gcc($GCC_PATH, "4.5"))
2185
2448
    { # support for GCC < 4.5
2229
2492
        my %MissedInfo = ( # typedef info
2230
2493
            "Name" => $TypedefName,
2231
2494
            "NameSpace" => $TypedefNS,
2232
 
            "BaseType" => {
2233
 
                            "Tid" => $Tid
2234
 
                          },
 
2495
            "BaseType" => $Tid,
2235
2496
            "Type" => "Typedef",
2236
2497
            "Tid" => "$MAX_ID" );
2237
2498
        my ($H, $L) = getLocation($MissedTDid);
2418
2679
        if(not $BTid) {
2419
2680
            return ();
2420
2681
        }
2421
 
        $TypeAttr{"BaseType"}{"Tid"} = $BTid;
 
2682
        if(my $Algn = getAlgn($TypeId)) {
 
2683
            $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
 
2684
        }
 
2685
        $TypeAttr{"BaseType"} = $BTid;
2422
2686
        if(my %BTAttr = getTypeAttr($BTid))
2423
2687
        {
2424
2688
            if(not $BTAttr{"Name"}) {
2446
2710
                    $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
2447
2711
                }
2448
2712
            }
2449
 
            $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
 
2713
            $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
2450
2714
            if($BTAttr{"Header"})  {
2451
2715
                $TypeAttr{"Header"} = $BTAttr{"Header"};
2452
2716
            }
2480
2744
        if(not $BTid) {
2481
2745
            return ();
2482
2746
        }
2483
 
        $TypeAttr{"BaseType"}{"Tid"} = $BTid;
 
2747
        $TypeAttr{"BaseType"} = $BTid;
2484
2748
        if(defined $MissedTypedef{$Version}{$BTid})
2485
2749
        {
2486
2750
            if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
2487
2751
            {
2488
2752
                if($MissedTDid ne $TypeDeclId) {
2489
 
                    $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
 
2753
                    $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2490
2754
                }
2491
2755
            }
2492
2756
        }
2493
 
        my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
 
2757
        my %BTAttr = getTypeAttr($TypeAttr{"BaseType"});
2494
2758
        if(not $BTAttr{"Name"})
2495
2759
        { # templates
2496
2760
            return ();
2497
2761
        }
2498
2762
        if($BTAttr{"Type"} eq "Typedef")
2499
2763
        { # relinking typedefs
2500
 
            my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
 
2764
            my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version);
2501
2765
            if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
2502
 
                $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
 
2766
                $TypeAttr{"BaseType"} = $BaseBase{"Tid"};
2503
2767
            }
2504
2768
        }
2505
2769
        if($BTSpec)
2520
2784
        if($TypeAttr{"Type"} eq "Typedef")
2521
2785
        {
2522
2786
            $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
 
2787
            
 
2788
            if(index($TypeAttr{"Name"}, "tmp_add_type")==0) {
 
2789
                return ();
 
2790
            }
 
2791
            
2523
2792
            if(isAnon($TypeAttr{"Name"}))
2524
2793
            { # anon typedef to anon type: ._N
2525
2794
                return ();
2526
2795
            }
 
2796
            
 
2797
            if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i)
 
2798
            { # artificial typedef of "struct X" to "X"
 
2799
                $TypeAttr{"Artificial"} = 1;
 
2800
            }
 
2801
            
2527
2802
            if(my $NS = getNameSpace($TypeDeclId))
2528
2803
            {
2529
2804
                my $TypeName = $TypeAttr{"Name"};
2558
2833
                    }
2559
2834
                }
2560
2835
            }
2561
 
            if($TypeAttr{"Name"} ne $BTAttr{"Name"}
 
2836
            if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"}
2562
2837
            and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
2563
2838
            {
2564
2839
                if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2584
2859
                $TypeAttr{"Size"} = $BTAttr{"Size"};
2585
2860
            }
2586
2861
        }
2587
 
        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
 
2862
        if(my $Algn = getAlgn($TypeId)) {
 
2863
            $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
 
2864
        }
 
2865
        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
2588
2866
        if(not $TypeAttr{"Header"} and $BTAttr{"Header"})  {
2589
2867
            $TypeAttr{"Header"} = $BTAttr{"Header"};
2590
2868
        }
2660
2938
            }
2661
2939
        }
2662
2940
        if($Pos>=1 and
2663
 
        $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
 
2941
        $PName=~/\A$DEFAULT_STD_PARMS\</)
2664
2942
        { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2665
2943
          # template<typename _Key, typename _Compare = std::less<_Key>
2666
2944
          # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2683
2961
      # one typedefs to the same type
2684
2962
        return $Covers[0];
2685
2963
    }
2686
 
    my $TypeName_Covered = $TypeName;
 
2964
    my $Covered = $TypeName;
2687
2965
    while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2688
2966
    if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2689
2967
    {
2690
 
        my $Cover = $Covers[0];
2691
 
        $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2692
 
        $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
 
2968
        if(my $Cover = $Covers[0])
 
2969
        {
 
2970
            $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
 
2971
            $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
 
2972
        }
2693
2973
    }
2694
 
    return formatName($TypeName_Covered);
 
2974
    return formatName($Covered, "T");
2695
2975
}
2696
2976
 
2697
2977
sub getNodeIntCst($)
2733
3013
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2734
3014
    {
2735
3015
        if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2736
 
        { # string length is N-1 because of the null terminator
2737
 
            return substr($1, 0, $2-1);
 
3016
        { 
 
3017
            if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
 
3018
            { # string length is N-1 because of the null terminator
 
3019
                return substr($1, 0, $2-1);
 
3020
            }
 
3021
            else
 
3022
            { # identifier_node
 
3023
                return substr($1, 0, $2);
 
3024
            }
2738
3025
        }
2739
3026
    }
2740
3027
    return "";
2752
3039
    my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
2753
3040
    if($Type eq "MethodPtr")
2754
3041
    { # size of "method pointer" may be greater than WORD size
2755
 
        if(my $Size = getSize($TypeId)) {
2756
 
            $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
 
3042
        if(my $Size = getSize($TypeId))
 
3043
        {
 
3044
            $Size/=$BYTE_SIZE;
 
3045
            $TypeAttr{"Size"} = "$Size";
2757
3046
        }
2758
3047
    }
 
3048
    if(my $Algn = getAlgn($TypeId)) {
 
3049
        $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
 
3050
    }
2759
3051
    # Return
2760
3052
    if($Type eq "FieldPtr")
2761
3053
    {
2802
3094
        if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2803
3095
        {
2804
3096
            my $PTypeInfoId = $1;
2805
 
            my $Pos = 0;
 
3097
            my ($Pos, $PPos) = (0, 0);
2806
3098
            while($PTypeInfoId)
2807
3099
            {
2808
3100
                my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2819
3111
                    }
2820
3112
                    if($Pos!=0 or $Type ne "MethodPtr")
2821
3113
                    {
2822
 
                        $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
 
3114
                        $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
2823
3115
                        push(@ParamTypeName, $ParamAttr{"Name"});
2824
3116
                    }
2825
3117
                    if($PTypeInfoId = getNextElem($PTypeInfoId)) {
2836
3128
        }
2837
3129
        $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2838
3130
    }
2839
 
    $TypeAttr{"Name"} = formatName($MemPtrName);
 
3131
    $TypeAttr{"Name"} = formatName($MemPtrName, "T");
2840
3132
    return %TypeAttr;
2841
3133
}
2842
3134
 
2858
3150
                return "int";
2859
3151
            }
2860
3152
        }
2861
 
        elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2862
 
        {
 
3153
        elsif($Info=~/name[ ]*:[ ]*@(\d+) /) {
2863
3154
            return getNameByInfo($1);
2864
3155
        }
2865
3156
    }
2950
3241
    return "Unknown";
2951
3242
}
2952
3243
 
 
3244
my %UnQual = (
 
3245
    "r"=>"restrict",
 
3246
    "v"=>"volatile",
 
3247
    "c"=>"const",
 
3248
    "cv"=>"const volatile"
 
3249
);
 
3250
 
2953
3251
sub getQual($)
2954
3252
{
2955
3253
    my $TypeId = $_[0];
2956
 
    my %UnQual = (
2957
 
        "r"=>"restrict",
2958
 
        "v"=>"volatile",
2959
 
        "c"=>"const",
2960
 
        "cv"=>"const volatile"
2961
 
    );
2962
3254
    if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2963
3255
    {
2964
3256
        my ($Qual, $To) = ();
2995
3287
    }
2996
3288
    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
2997
3289
    my ($Qual, $To) = getQual($TypeId);
2998
 
    if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
2999
 
    and (getTypeId($1) ne $TypeId))
 
3290
    if(($Qual or $To) and $TypeDeclId
 
3291
    and (getTypeId($TypeDeclId) ne $TypeId))
3000
3292
    { # qualified types (special)
3001
3293
        return getQualType($Qual);
3002
3294
    }
3008
3300
    { # qualified types
3009
3301
        return getQualType($Qual);
3010
3302
    }
 
3303
    
 
3304
    if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
 
3305
    { # typedef struct { ... } name
 
3306
        $TypeTypedef{$Version}{$TypeId} = $1;
 
3307
    }
 
3308
    
3011
3309
    my $TypeType = getTypeTypeByTypeId($TypeId);
3012
3310
    if($TypeType eq "Struct")
3013
3311
    {
3126
3424
sub getVarInfo($)
3127
3425
{
3128
3426
    my $InfoId = $_[0];
3129
 
    if(my $NSid = getNameSpaceId($InfoId))
 
3427
    if(my $NSid = getTreeAttr_Scpe($InfoId))
3130
3428
    {
3131
3429
        my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3132
3430
        if($NSInfoType and $NSInfoType eq "function_decl") {
3149
3447
        return;
3150
3448
    }
3151
3449
    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
3152
 
    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
 
3450
    if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
 
3451
    {
 
3452
        if($OSgroup eq "windows")
 
3453
        { # cut the offset
 
3454
            $MnglName=~s/\@\d+\Z//g;
 
3455
        }
 
3456
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
 
3457
    }
3153
3458
    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3154
 
    and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
 
3459
    and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
3155
3460
    { # validate mangled name
3156
3461
        delete($SymbolInfo{$Version}{$InfoId});
3157
3462
        return;
3158
3463
    }
3159
3464
    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3160
 
    and $ShortName=~/\A_Z/)
 
3465
    and index($ShortName, "_Z")==0)
3161
3466
    { # _ZTS, etc.
3162
3467
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3163
3468
    }
3189
3494
            return;
3190
3495
        }
3191
3496
    }
3192
 
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
 
3497
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
 
3498
    { # extern "C"
3193
3499
        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
 
3500
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3194
3501
    }
3195
3502
    if($UserLang and $UserLang eq "C")
3196
3503
    { # --lang=C option
3197
3504
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3198
3505
    }
 
3506
    if(not $CheckHeadersOnly)
 
3507
    {
 
3508
        if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
 
3509
        {
 
3510
            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
 
3511
            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
 
3512
            {
 
3513
                if(link_symbol($ShortName, $Version, "-Deps"))
 
3514
                { # "const" global data is mangled as _ZL... in the TU dump
 
3515
                  # but not mangled when compiling a C shared library
 
3516
                    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
 
3517
                }
 
3518
            }
 
3519
        }
 
3520
    }
3199
3521
    if($COMMON_LANGUAGE{$Version} eq "C++")
3200
3522
    {
3201
3523
        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3202
3524
        { # for some symbols (_ZTI) the short name is the mangled name
3203
 
            if($ShortName=~/\A_Z/) {
 
3525
            if(index($ShortName, "_Z")==0) {
3204
3526
                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3205
3527
            }
3206
3528
        }
3219
3541
    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3220
3542
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3221
3543
    }
3222
 
    if(not $CheckHeadersOnly
3223
 
    and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3224
 
    {
3225
 
        if(link_symbol($ShortName, $Version, "-Deps"))
3226
 
        {
3227
 
            if(not $SymbolInfo{$Version}{$InfoId}{"Class"}
3228
 
            and isConstType($SymbolInfo{$Version}{$InfoId}{"Return"}, $Version)
3229
 
            and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/L\d+$ShortName/)
3230
 
            { # "const" global data is mangled as _ZL... in the TU dump
3231
 
              # but not mangled when compiling a C shared library
3232
 
                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3233
 
            }
3234
 
        }
3235
 
    }
3236
3544
    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3237
3545
    {
3238
3546
        if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3251
3559
        }
3252
3560
    }
3253
3561
    setFuncAccess($InfoId);
3254
 
    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
 
3562
    if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
3255
3563
        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3256
3564
    }
3257
3565
    if($ShortName=~/\A(_Z|\?)/) {
3258
3566
        delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3259
3567
    }
 
3568
    
 
3569
    if($ExtraDump) {
 
3570
        $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId);
 
3571
    }
3260
3572
}
3261
3573
 
3262
3574
sub isConstType($$)
3264
3576
    my ($TypeId, $LibVersion) = @_;
3265
3577
    my %Base = get_Type($TypeId, $LibVersion);
3266
3578
    while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
3267
 
        %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
 
3579
        %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
3268
3580
    }
3269
3581
    return ($Base{"Type"} eq "Const");
3270
3582
}
3283
3595
    if(isAnon($TypeAttr{"Name"}))
3284
3596
    {
3285
3597
        my $NameSpaceId = $TypeId;
3286
 
        while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
 
3598
        while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
3287
3599
        { # searching for a first not anon scope
3288
3600
            if($NSId eq $NameSpaceId) {
3289
3601
                last;
3292
3604
            {
3293
3605
                $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3294
3606
                if(not $TypeAttr{"NameSpace"}
3295
 
                or isNotAnon($TypeAttr{"NameSpace"})) {
 
3607
                or not isAnon($TypeAttr{"NameSpace"})) {
3296
3608
                    last;
3297
3609
                }
3298
3610
            }
3301
3613
    }
3302
3614
    else
3303
3615
    {
3304
 
        if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
 
3616
        if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
3305
3617
        {
3306
3618
            if($NameSpaceId ne $TypeId) {
3307
3619
                $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3308
3620
            }
3309
3621
        }
3310
3622
    }
3311
 
    if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
 
3623
    if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) {
3312
3624
        $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3313
3625
    }
3314
 
    $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
 
3626
    $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
3315
3627
    if(isAnon($TypeAttr{"Name"}))
3316
3628
    { # anon-struct-header.h-line
3317
3629
        $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
3328
3640
        { # template declarations with abstract params
3329
3641
            return ("", "");
3330
3642
        }
3331
 
        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
 
3643
        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
3332
3644
    }
3333
3645
    return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3334
3646
}
3378
3690
            }
3379
3691
        }
3380
3692
    }
3381
 
    if(my $Size = getSize($TypeId)) {
3382
 
        $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3383
 
    }
 
3693
    if(my $Size = getSize($TypeId))
 
3694
    {
 
3695
        $Size = $Size/$BYTE_SIZE;
 
3696
        $TypeAttr{"Size"} = "$Size";
 
3697
    }
 
3698
    else
 
3699
    { # declaration only
 
3700
        $TypeAttr{"Forward"} = 1;
 
3701
    }
 
3702
    
 
3703
    my $StaticFields = setTypeMemb($TypeId, \%TypeAttr);
 
3704
    
3384
3705
    if($TypeAttr{"Type"} eq "Struct"
3385
 
    and detect_lang($TypeId))
 
3706
    and ($StaticFields or detect_lang($TypeId)))
3386
3707
    {
3387
3708
        $TypeAttr{"Type"} = "Class";
3388
3709
        $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
3395
3716
            return ();
3396
3717
        }
3397
3718
    }
 
3719
    if(my $Algn = getAlgn($TypeId)) {
 
3720
        $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
 
3721
    }
3398
3722
    setSpec($TypeId, \%TypeAttr);
3399
 
    setTypeMemb($TypeId, \%TypeAttr);
 
3723
    
 
3724
    if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/)
 
3725
    {
 
3726
        if(not $TypedefToAnon{$TypeId}
 
3727
        and not keys(%{$TemplateInstance{$Version}{"Type"}{$TypeId}}))
 
3728
        {
 
3729
            if(not isAnon($TypeAttr{"Name"})) {
 
3730
                $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"};
 
3731
            }
 
3732
        }
 
3733
    }
 
3734
    
3400
3735
    $TypeAttr{"Tid"} = $TypeId;
3401
3736
    if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3402
3737
    {
3409
3744
            }
3410
3745
        }
3411
3746
    }
 
3747
    
 
3748
    if($TypeAttr{"Type"} eq "Enum")
 
3749
    {
 
3750
        if(not $TypeAttr{"NameSpace"})
 
3751
        {
 
3752
            foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
 
3753
            {
 
3754
                my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
 
3755
                my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"};
 
3756
                $EnumConstants{$Version}{$MName} = {
 
3757
                    "Value"=>$MVal,
 
3758
                    "Header"=>$TypeAttr{"Header"}
 
3759
                };
 
3760
                if(isAnon($TypeAttr{"Name"}))
 
3761
                {
 
3762
                    %{$Constants{$Version}{$MName}} = (
 
3763
                        "Value" => $MVal,
 
3764
                        "Header" => $TypeAttr{"Header"}
 
3765
                    );
 
3766
                }
 
3767
            }
 
3768
        }
 
3769
    }
 
3770
    if($ExtraDump)
 
3771
    {
 
3772
        if(defined $TypedefToAnon{$TypeId}) {
 
3773
            $TypeAttr{"AnonTypedef"} = 1;
 
3774
        }
 
3775
    }
 
3776
    
3412
3777
    return %TypeAttr;
3413
3778
}
3414
3779
 
3462
3827
                return 1;
3463
3828
            }
3464
3829
            my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3465
 
            if($Access=~/prot/)
3466
 
            {
 
3830
            if($Access=~/prot/) {
3467
3831
                $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3468
3832
            }
3469
 
            elsif($Access=~/priv/)
3470
 
            {
 
3833
            elsif($Access=~/priv/) {
3471
3834
                $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3472
3835
            }
3473
 
            $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
 
3836
            $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
3474
3837
            if($BaseInfo=~/virt/)
3475
3838
            { # virtual base
3476
3839
                $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3477
3840
            }
3478
3841
            $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
 
3842
            $Pos += 1;
3479
3843
        }
3480
3844
    }
3481
3845
    return 0;
3517
3881
        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3518
3882
        { # checking parameters
3519
3883
            my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
3520
 
            my %PType = get_PureType($PId, $Version);
 
3884
            my %PType = get_PureType($PId, $TypeInfo{$Version});
3521
3885
            my $PTName = unmangledFormat($PType{"Name"}, $Version);
3522
3886
            $PTName=~s/\b(restrict|register)\b//g;
3523
3887
            if($Compiler eq "MSVC") {
3570
3934
    { # mangled names for template function specializations include return value
3571
3935
        if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3572
3936
        {
3573
 
            my %RType = get_PureType($ReturnId, $Version);
 
3937
            my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
3574
3938
            my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3575
3939
            $PureSignature = $ReturnName." ".$PureSignature;
3576
3940
        }
3577
3941
    }
3578
 
    return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
 
3942
    return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
3579
3943
}
3580
3944
 
3581
3945
sub mangle_symbol($$$)
3635
3999
        }
3636
4000
        $Mangled .= $MangledNS;
3637
4001
    }
3638
 
    my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
 
4002
    my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
3639
4003
    my @TParams = ();
3640
 
    if($Version)
 
4004
    if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
3641
4005
    { # parsing mode
3642
 
        @TParams = getTParams($InfoId, "Func");
 
4006
        foreach (@TPos) {
 
4007
            push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
 
4008
        }
3643
4009
    }
3644
4010
    elsif($TmplParams)
3645
4011
    { # remangling mode
3646
4012
      # support for old ABI dumps
3647
 
        @TParams = separate_params($TmplParams, 0);
 
4013
        @TParams = separate_Params($TmplParams, 0, 0);
3648
4014
    }
3649
4015
    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3650
4016
        $Mangled .= "C1";
3742
4108
    return $Mangled;
3743
4109
}
3744
4110
 
3745
 
sub template_base($)
 
4111
sub template_Base($)
3746
4112
{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
3747
4113
  # NOTE: operators: >>, <<
3748
4114
    my $Name = $_[0];
3807
4173
    my %ReplCopy = %{$Repl};
3808
4174
    my %BaseType = get_BaseType($PTid, $LibVersion);
3809
4175
    my $BaseType_Name = $BaseType{"Name"};
 
4176
    $BaseType_Name=~s/\A(struct|union|enum) //g;
3810
4177
    if(not $BaseType_Name) {
3811
4178
        return "";
3812
4179
    }
3813
 
    my ($ShortName, $TmplParams) = template_base($BaseType_Name);
 
4180
    my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
3814
4181
    my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
3815
4182
    while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3816
4183
    while($Suffix=~/(&|\*|const)\Z/)
3841
4208
    elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3842
4209
    {
3843
4210
        my @TParams = ();
3844
 
        if($Version)
 
4211
        if(my @TPos = keys(%{$BaseType{"TParam"}}))
3845
4212
        { # parsing mode
3846
 
            @TParams = getTParams($BaseType{"Tid"}, "Type");
 
4213
            foreach (@TPos) {
 
4214
                push(@TParams, $BaseType{"TParam"}{$_}{"name"});
 
4215
            }
3847
4216
        }
3848
4217
        elsif($TmplParams)
3849
4218
        { # remangling mode
3850
4219
          # support for old ABI dumps
3851
 
            @TParams = separate_params($TmplParams, 0);
 
4220
            @TParams = separate_Params($TmplParams, 0, 0);
3852
4221
        }
3853
4222
        my $MangledNS = "";
3854
4223
        my ($SubNS, $SName) = get_sub_ns($ShortName);
4081
4450
    if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4082
4451
        return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4083
4452
    }
4084
 
    my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
 
4453
    my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
4085
4454
    while($TypeName_New ne $TypeName_Pre)
4086
4455
    {
4087
4456
        $TypeName_Pre = $TypeName_New;
4105
4474
                    my $Type_Suffix = $1;
4106
4475
                    $TypeName_New = $BaseType_Name;
4107
4476
                    if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4108
 
                        $TypeName_New = formatName($TypeName_New);
 
4477
                        $TypeName_New = formatName($TypeName_New, "T");
4109
4478
                    }
4110
4479
                }
4111
4480
            }
4112
4481
            else
4113
4482
            {
4114
4483
                if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
4115
 
                    $TypeName_New = formatName($TypeName_New);
 
4484
                    $TypeName_New = formatName($TypeName_New, "T");
4116
4485
                }
4117
4486
            }
4118
4487
        }
4144
4513
        {
4145
4514
            if(defined $LibInfo{$Version}{"info_type"}{$1}
4146
4515
            and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4147
 
            { # char const* data = "str"
4148
 
              # NOTE: disabled
4149
 
                if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
 
4516
            {
 
4517
                if(my $Nop = getTreeAttr_Op($1))
4150
4518
                {
4151
 
                    if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
 
4519
                    if(defined $LibInfo{$Version}{"info_type"}{$Nop}
 
4520
                    and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr")
4152
4521
                    {
4153
 
                        if(defined $LibInfo{$Version}{"info_type"}{$1}
4154
 
                        and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4155
 
                        {
4156
 
                            if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4157
 
                            {
4158
 
                                if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4159
 
                                {
4160
 
                                    return getInitVal($1, $TypeId);
4161
 
                                }
4162
 
                            }
 
4522
                        if(my $Addr = getTreeAttr_Op($1)) {
 
4523
                            return getInitVal($Addr, $TypeId);
4163
4524
                        }
4164
4525
                    }
4165
4526
                }
4191
4552
            elsif($InfoType eq "string_cst") {
4192
4553
                return getNodeStrCst($InfoId);
4193
4554
            }
 
4555
            elsif($InfoType eq "var_decl")
 
4556
            {
 
4557
                if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
 
4558
                    return $Name;
 
4559
                }
 
4560
            }
4194
4561
        }
4195
4562
    }
4196
4563
    return undef;
4217
4584
    }
4218
4585
    if($SymbolInfo{$Version}{$InfoId}{"Class"}
4219
4586
    or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4220
 
    { # identify language
4221
 
        setLanguage($Version, "C++");
 
4587
    {
 
4588
        if($COMMON_LANGUAGE{$Version} ne "C++")
 
4589
        { # skip
 
4590
            return 1;
 
4591
        }
4222
4592
    }
4223
 
}
4224
 
 
4225
 
sub debugType($$)
4226
 
{
4227
 
    my ($Tid, $LibVersion) = @_;
4228
 
    my %Type = get_Type($Tid, $LibVersion);
4229
 
    printMsg("INFO", Dumper(\%Type));
 
4593
    
 
4594
    return 0;
4230
4595
}
4231
4596
 
4232
4597
sub debugMangling($)
4257
4622
{ # link symbols from shared libraries
4258
4623
  # with the symbols from header files
4259
4624
    my $InfoId = $_[0];
4260
 
    if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
4261
 
    {
4262
 
        if($Lang eq "C")
4263
 
        { # extern "C"
4264
 
            return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4265
 
        }
4266
 
    }
4267
4625
    # try to mangle symbol
4268
4626
    if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4269
4627
    or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
4303
4661
    }
4304
4662
    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4305
4663
    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
4306
 
    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
 
4664
    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
 
4665
    {
4307
4666
        delete($SymbolInfo{$Version}{$InfoId});
4308
4667
        return;
4309
4668
    }
4310
4669
    setFuncAccess($InfoId);
4311
4670
    setFuncKind($InfoId);
4312
 
    if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) {
 
4671
    if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
 
4672
    {
4313
4673
        delete($SymbolInfo{$Version}{$InfoId});
4314
4674
        return;
4315
4675
    }
 
4676
    
4316
4677
    $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
4317
4678
    if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4318
4679
    {
4334
4695
    if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4335
4696
        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
4336
4697
    }
4337
 
    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName(getFuncOrig($InfoId));
4338
 
    if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/) {
4339
 
        delete($SymbolInfo{$Version}{$InfoId});
4340
 
        return;
4341
 
    }
4342
 
    if(defined $TemplateInstance{$Version}{"Func"}{$InfoId})
4343
 
    {
4344
 
        my @TParams = getTParams($InfoId, "Func");
4345
 
        if(not @TParams) {
 
4698
    my $Orig = getFuncOrig($InfoId);
 
4699
    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
 
4700
    if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1)
 
4701
    {
 
4702
        delete($SymbolInfo{$Version}{$InfoId});
 
4703
        return;
 
4704
    }
 
4705
    
 
4706
    if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0)
 
4707
    {
 
4708
        delete($SymbolInfo{$Version}{$InfoId});
 
4709
        return;
 
4710
    }
 
4711
    
 
4712
    if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
 
4713
    {
 
4714
        my @TParams = getTParams($Orig, "Func");
 
4715
        if(not @TParams)
 
4716
        {
4346
4717
            delete($SymbolInfo{$Version}{$InfoId});
4347
4718
            return;
4348
4719
        }
4355
4726
            $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4356
4727
        }
4357
4728
        $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4358
 
        $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
 
4729
        $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
4359
4730
    }
4360
4731
    else
4361
4732
    { # support for GCC 3.4
4362
4733
        $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
4363
4734
    }
4364
 
    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
4365
 
    # NOTE: mangling of some symbols may change depending on GCC version
4366
 
    # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4367
 
    # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
 
4735
    if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
 
4736
    {
 
4737
        if($OSgroup eq "windows")
 
4738
        { # cut the offset
 
4739
            $MnglName=~s/\@\d+\Z//g;
 
4740
        }
 
4741
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
 
4742
        
 
4743
        # NOTE: mangling of some symbols may change depending on GCC version
 
4744
        # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
 
4745
        # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
 
4746
    }
4368
4747
    
4369
4748
    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4370
 
    and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
 
4749
    and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
4371
4750
    {
4372
4751
        delete($SymbolInfo{$Version}{$InfoId});
4373
4752
        return;
4375
4754
    if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
4376
4755
    { # destructors have an empty parameter list
4377
4756
        my $Skip = setFuncParams($InfoId);
4378
 
        if($Skip) {
 
4757
        if($Skip)
 
4758
        {
4379
4759
            delete($SymbolInfo{$Version}{$InfoId});
4380
4760
            return;
4381
4761
        }
4382
4762
    }
4383
 
    set_Class_And_Namespace($InfoId);
 
4763
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
 
4764
        $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
 
4765
    }
 
4766
    
 
4767
    if(set_Class_And_Namespace($InfoId))
 
4768
    {
 
4769
        delete($SymbolInfo{$Version}{$InfoId});
 
4770
        return;
 
4771
    }
 
4772
    
4384
4773
    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4385
4774
    {
4386
4775
        if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4389
4778
            return;
4390
4779
        }
4391
4780
    }
4392
 
    if(not $CheckHeadersOnly)
4393
 
    {
4394
 
        if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4395
 
        and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4396
 
        and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4397
 
        { # functions (C++): not mangled in library, but are mangled in TU dump
4398
 
            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4399
 
            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4400
 
                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4401
 
            }
4402
 
        }
4403
 
    }
4404
 
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
 
4781
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
 
4782
    { # extern "C"
4405
4783
        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
 
4784
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4406
4785
    }
4407
4786
    if($UserLang and $UserLang eq "C")
4408
4787
    { # --lang=C option
4434
4813
            }
4435
4814
        }
4436
4815
    }
 
4816
    else
 
4817
    { # not mangled in C
 
4818
        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
 
4819
    }
 
4820
    if(not $CheckHeadersOnly
 
4821
    and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
 
4822
    and not $SymbolInfo{$Version}{$InfoId}{"Class"})
 
4823
    {
 
4824
        my $Incorrect = 0;
 
4825
        
 
4826
        if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
 
4827
        {
 
4828
            if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0
 
4829
            and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
 
4830
            { # mangled in the TU dump, but not mangled in the library
 
4831
                $Incorrect = 1;
 
4832
            }
 
4833
        }
 
4834
        else
 
4835
        {
 
4836
            if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C")
 
4837
            { # all C++ functions are not mangled in the TU dump
 
4838
                $Incorrect = 1;
 
4839
            }
 
4840
        }
 
4841
        if($Incorrect)
 
4842
        {
 
4843
            if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) {
 
4844
                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
 
4845
            }
 
4846
        }
 
4847
    }
4437
4848
    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4438
4849
    { # can't detect symbol name
4439
4850
        delete($SymbolInfo{$Version}{$InfoId});
4440
4851
        return;
4441
4852
    }
4442
4853
    if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4443
 
    and my $Spec = getVirtSpec(getFuncOrig($InfoId)))
 
4854
    and my $Spec = getVirtSpec($Orig))
4444
4855
    { # identify virtual and pure virtual functions
4445
4856
      # NOTE: constructors cannot be virtual
4446
4857
      # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4454
4865
    if(isInline($InfoId)) {
4455
4866
        $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
4456
4867
    }
4457
 
    if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4458
 
        $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
 
4868
    if(hasThrow($InfoId)) {
 
4869
        $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4459
4870
    }
4460
4871
    if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4461
4872
    and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4468
4879
    }
4469
4880
    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4470
4881
    {
4471
 
        if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4472
 
        and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
 
4882
        if(not $ExtraDump)
4473
4883
        {
4474
4884
            if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4475
4885
            { # non-target symbols
4483
4893
    or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4484
4894
    or $SymbolInfo{$Version}{$InfoId}{"Class"})
4485
4895
    {
4486
 
        if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
 
4896
        if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
 
4897
        {
4487
4898
            delete($SymbolInfo{$Version}{$InfoId});
4488
4899
            return;
4489
4900
        }
4518
4929
    {
4519
4930
        if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4520
4931
        {
4521
 
            if($Unmangled=~/\.\_\d/) {
 
4932
            if($Unmangled=~/\.\_\d/)
 
4933
            {
4522
4934
                delete($SymbolInfo{$Version}{$InfoId});
4523
4935
                return;
4524
4936
            }
4531
4943
    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4532
4944
        $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4533
4945
    }
 
4946
    
 
4947
    if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
 
4948
        $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
 
4949
    }
 
4950
    
 
4951
    if($ExtraDump) {
 
4952
        $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId);
 
4953
    }
 
4954
}
 
4955
 
 
4956
sub guessHeader($)
 
4957
{
 
4958
    my $InfoId = $_[0];
 
4959
    my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
 
4960
    my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"};
 
4961
    my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):"";
 
4962
    my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"};
 
4963
    if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName})
 
4964
    {
 
4965
        if(get_filename($HPath) eq $Header)
 
4966
        {
 
4967
            my $HDir = get_filename(get_dirname($HPath));
 
4968
            if($HDir ne "include"
 
4969
            and $HDir=~/\A[a-z]+\Z/i) {
 
4970
                return join_P($HDir, $Header);
 
4971
            }
 
4972
        }
 
4973
    }
 
4974
    return $Header;
4534
4975
}
4535
4976
 
4536
4977
sub isInline($)
4545
4986
    return 1;
4546
4987
}
4547
4988
 
 
4989
sub hasThrow($)
 
4990
{
 
4991
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
 
4992
    {
 
4993
        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
 
4994
            return getTreeAttr_Unql($1, "unql");
 
4995
        }
 
4996
    }
 
4997
    return 1;
 
4998
}
 
4999
 
4548
5000
sub getTypeId($)
4549
5001
{
4550
5002
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4561
5013
    my ($TypeId, $TypeAttr) = @_;
4562
5014
    my $TypeType = $TypeAttr->{"Type"};
4563
5015
    my ($Pos, $UnnamedPos) = (0, 0);
 
5016
    my $StaticFields = 0;
4564
5017
    if($TypeType eq "Enum")
4565
5018
    {
4566
 
        my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
4567
 
        while($TypeMembInfoId)
 
5019
        my $MInfoId = getTreeAttr_Csts($TypeId);
 
5020
        while($MInfoId)
4568
5021
        {
4569
 
            $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
4570
 
            my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
 
5022
            $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId);
 
5023
            my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId));
4571
5024
            $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4572
 
            $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4573
 
            $TypeMembInfoId = getNextElem($TypeMembInfoId);
 
5025
            $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
 
5026
            $MInfoId = getNextElem($MInfoId);
4574
5027
            $Pos += 1;
4575
5028
        }
4576
5029
    }
4577
5030
    elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4578
5031
    {
4579
 
        my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
4580
 
        while($TypeMembInfoId)
 
5032
        my $MInfoId = getTreeAttr_Flds($TypeId);
 
5033
        while($MInfoId)
4581
5034
        {
4582
 
            my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
4583
 
            my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
 
5035
            my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId};
 
5036
            my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId};
4584
5037
            if(not $IType or $IType ne "field_decl")
4585
5038
            { # search for fields, skip other stuff in the declaration
4586
 
                $TypeMembInfoId = getNextElem($TypeMembInfoId);
 
5039
            
 
5040
                if($IType eq "var_decl")
 
5041
                { # static field
 
5042
                    $StaticFields = 1;
 
5043
                }
 
5044
                
 
5045
                $MInfoId = getNextElem($MInfoId);
4587
5046
                next;
4588
5047
            }
4589
 
            my $StructMembName = getStructMembName($TypeMembInfoId);
4590
 
            if($StructMembName=~/_vptr\./)
 
5048
            my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId));
 
5049
            if(index($StructMembName, "_vptr.")==0)
4591
5050
            { # virtual tables
4592
 
                $TypeMembInfoId = getNextElem($TypeMembInfoId);
4593
 
                next;
 
5051
                $StructMembName = "_vptr";
4594
5052
            }
4595
5053
            if(not $StructMembName)
4596
5054
            { # unnamed fields
4597
 
                if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
 
5055
                if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
4598
5056
                {
4599
 
                    my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
 
5057
                    my $UnnamedTid = getTreeAttr_Type($MInfoId);
4600
5058
                    my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4601
5059
                    if(isAnon($UnnamedTName))
4602
5060
                    { # rename unnamed fields to unnamed0, unnamed1, ...
4606
5064
            }
4607
5065
            if(not $StructMembName)
4608
5066
            { # unnamed fields and base classes
4609
 
                $TypeMembInfoId = getNextElem($TypeMembInfoId);
 
5067
                $MInfoId = getNextElem($MInfoId);
4610
5068
                next;
4611
5069
            }
4612
 
            my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
 
5070
            my $MembTypeId = getTreeAttr_Type($MInfoId);
4613
5071
            if(defined $MissedTypedef{$Version}{$MembTypeId})
4614
5072
            {
4615
5073
                if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4618
5076
            }
4619
5077
            $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4620
5078
            $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
4621
 
            if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
 
5079
            if((my $Access = getTreeAccess($MInfoId)) ne "public")
4622
5080
            { # marked only protected and private, public by default
4623
5081
                $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4624
5082
            }
4626
5084
            { # mutable fields
4627
5085
                $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
4628
5086
            }
4629
 
            if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
 
5087
            if(my $Algn = getAlgn($MInfoId)) {
 
5088
                $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
 
5089
            }
 
5090
            if(my $BFSize = getBitField($MInfoId))
 
5091
            { # in bits
4630
5092
                $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
4631
5093
            }
4632
5094
            else
4633
 
            { # set alignment for non-bit fields
4634
 
              # alignment for bitfields is always equal to 1 bit
4635
 
                if(my $Algn = getAlgn($TypeMembInfoId)) {
4636
 
                    $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4637
 
                }
 
5095
            { # in bytes
 
5096
                $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
4638
5097
            }
4639
 
            $TypeMembInfoId = getNextElem($TypeMembInfoId);
 
5098
            
 
5099
            $MInfoId = getNextElem($MInfoId);
4640
5100
            $Pos += 1;
4641
5101
        }
4642
5102
    }
 
5103
    
 
5104
    return $StaticFields;
4643
5105
}
4644
5106
 
4645
5107
sub setFuncParams($)
4662
5124
        { # skip
4663
5125
            return 1;
4664
5126
        }
4665
 
        $ParamInfoId = getNextElem($ParamInfoId);
 
5127
        # skip "this"-parameter
 
5128
        # $ParamInfoId = getNextElem($ParamInfoId);
4666
5129
    }
4667
5130
    my ($Pos, $Vtt_Pos) = (0, -1);
4668
5131
    while($ParamInfoId)
4713
5176
        $Pos += 1;
4714
5177
    }
4715
5178
    if(setFuncArgs($InfoId, $Vtt_Pos)) {
4716
 
        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
 
5179
        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
4717
5180
    }
4718
5181
    return 0;
4719
5182
}
4758
5221
        }
4759
5222
        if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
4760
5223
        { # default arguments
4761
 
            if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4762
 
                $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
 
5224
            if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
 
5225
            {
 
5226
                if($PurpType eq "nop_expr")
 
5227
                { # func ( const char* arg = (const char*)(void*)0 )
 
5228
                    $PurpId = getTreeAttr_Op($PurpId);
 
5229
                }
 
5230
                my $Val = getInitVal($PurpId, $ParamTypeId);
 
5231
                if(defined $Val) {
 
5232
                    $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
 
5233
                }
4763
5234
            }
4764
5235
        }
4765
5236
        $ParamListElemId = getNextElem($ParamListElemId);
4790
5261
    return "";
4791
5262
}
4792
5263
 
 
5264
sub getTreeAttr_Unql($)
 
5265
{
 
5266
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
 
5267
    {
 
5268
        if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
 
5269
            return $1;
 
5270
        }
 
5271
    }
 
5272
    return "";
 
5273
}
 
5274
 
4793
5275
sub getTreeAttr_Scpe($)
4794
5276
{
4795
5277
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4878
5360
    return "";
4879
5361
}
4880
5362
 
 
5363
sub getTreeAttr_Op($)
 
5364
{
 
5365
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
 
5366
    {
 
5367
        if($Info=~/op 0[ ]*:[ ]*@(\d+) /) {
 
5368
            return $1;
 
5369
        }
 
5370
    }
 
5371
    return "";
 
5372
}
 
5373
 
4881
5374
sub getTreeAttr_Valu($)
4882
5375
{
4883
5376
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5023
5516
    return "";
5024
5517
}
5025
5518
 
5026
 
sub get_IntNameSpace($$)
 
5519
sub select_Symbol_NS($$)
5027
5520
{
5028
 
    my ($Interface, $LibVersion) = @_;
5029
 
    return "" if(not $Interface or not $LibVersion);
5030
 
    if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5031
 
        return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
 
5521
    my ($Symbol, $LibVersion) = @_;
 
5522
    return "" if(not $Symbol or not $LibVersion);
 
5523
    my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
 
5524
    if(not $NS)
 
5525
    {
 
5526
        if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
 
5527
            $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"};
 
5528
        }
5032
5529
    }
5033
 
    my $Signature = get_Signature($Interface, $LibVersion);
5034
 
    if($Signature=~/\:\:/)
 
5530
    if($NS)
5035
5531
    {
5036
 
        my $FounNameSpace = 0;
5037
 
        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
 
5532
        if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
 
5533
            return $NS;
 
5534
        }
 
5535
        else
5038
5536
        {
5039
 
            if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5040
 
                return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
 
5537
            while($NS=~s/::[^:]+\Z//)
 
5538
            {
 
5539
                if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
 
5540
                    return $NS;
 
5541
                }
5041
5542
            }
5042
5543
        }
5043
5544
    }
5044
 
    else {
5045
 
        return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5046
 
    }
 
5545
    
 
5546
    return "";
5047
5547
}
5048
5548
 
5049
 
sub parse_TypeNameSpace($$)
 
5549
sub select_Type_NS($$)
5050
5550
{
5051
5551
    my ($TypeName, $LibVersion) = @_;
5052
5552
    return "" if(not $TypeName or not $LibVersion);
5053
 
    if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5054
 
        return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5055
 
    }
5056
 
    if($TypeName=~/\:\:/)
 
5553
    if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"})
5057
5554
    {
5058
 
        my $FounNameSpace = 0;
5059
 
        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
 
5555
        if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
 
5556
            return $NS;
 
5557
        }
 
5558
        else
5060
5559
        {
5061
 
            if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5062
 
                return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
 
5560
            while($NS=~s/::[^:]+\Z//)
 
5561
            {
 
5562
                if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
 
5563
                    return $NS;
 
5564
                }
5063
5565
            }
5064
5566
        }
5065
5567
    }
5066
 
    else {
5067
 
        return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5068
 
    }
 
5568
    return "";
5069
5569
}
5070
5570
 
5071
5571
sub getNameSpace($)
5072
5572
{
5073
 
    my $TypeInfoId = $_[0];
5074
 
    if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
 
5573
    my $InfoId = $_[0];
 
5574
    if(my $NSInfoId = getTreeAttr_Scpe($InfoId))
5075
5575
    {
5076
5576
        if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
5077
5577
        {
5104
5604
    return "";
5105
5605
}
5106
5606
 
5107
 
sub getNameSpaceId($)
5108
 
{
5109
 
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5110
 
    {
5111
 
        if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5112
 
            return $1;
5113
 
        }
5114
 
    }
5115
 
    return "";
5116
 
}
5117
 
 
5118
 
sub getStructMembName($)
5119
 
{
5120
 
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5121
 
    {
5122
 
        if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5123
 
            return getTreeStr($1);
5124
 
        }
5125
 
    }
5126
 
    return "";
5127
 
}
5128
 
 
5129
5607
sub getEnumMembVal($)
5130
5608
{
5131
5609
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5170
5648
    return "";
5171
5649
}
5172
5650
 
5173
 
sub getStructMembBitFieldSize($)
 
5651
sub getBitField($)
5174
5652
{
5175
5653
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5176
5654
    {
5210
5688
    {
5211
5689
        detect_header_includes($Header_Path, $LibVersion);
5212
5690
        
 
5691
        if(defined $Tolerance and $Tolerance=~/3/)
 
5692
        { # 3 - skip headers that include non-Linux headers
 
5693
            if($OSgroup ne "windows")
 
5694
            {
 
5695
                foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}}))
 
5696
                {
 
5697
                    if(specificHeader($Inc, "windows")) {
 
5698
                        return "";
 
5699
                    }
 
5700
                }
 
5701
            }
 
5702
        }
 
5703
        
5213
5704
        if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5214
5705
        { # redirect
5215
5706
            if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5232
5723
        
5233
5724
        if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5234
5725
        or $Header!~/\.(\w+)\Z/)
5235
 
        { # hpp, hh
 
5726
        { # hpp, hh, etc.
5236
5727
            setLanguage($LibVersion, "C++");
 
5728
            $CPP_HEADERS = 1;
5237
5729
        }
5238
5730
        
5239
5731
        if($CheckHeadersOnly
5247
5739
    return "";
5248
5740
}
5249
5741
 
5250
 
sub register_directory($$$)
 
5742
sub registerDir($$$)
5251
5743
{
5252
5744
    my ($Dir, $WithDeps, $LibVersion) = @_;
5253
5745
    $Dir=~s/[\/\\]+\Z//g;
5254
5746
    return if(not $LibVersion or not $Dir or not -d $Dir);
5255
 
    return if(skipHeader($Dir, $LibVersion));
5256
5747
    $Dir = get_abs_path($Dir);
5257
5748
    my $Mode = "All";
5258
5749
    if($WithDeps)
5275
5766
    $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5276
5767
    if($Mode eq "DepsOnly")
5277
5768
    {
5278
 
        foreach my $Path (cmd_find($Dir,"d","","")) {
 
5769
        foreach my $Path (cmd_find($Dir,"d")) {
5279
5770
            $Header_Dependency{$LibVersion}{$Path} = 1;
5280
5771
        }
5281
5772
        return;
5282
5773
    }
5283
 
    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
 
5774
    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f"))
5284
5775
    {
5285
5776
        if($WithDeps)
5286
5777
        { 
5292
5783
        }
5293
5784
        next if(is_not_header($Path));
5294
5785
        next if(ignore_path($Path));
5295
 
        next if(skipHeader($Path, $LibVersion));
5296
5786
        # Neighbors
5297
 
        foreach my $Part (get_path_prefixes($Path)) {
 
5787
        foreach my $Part (get_prefixes($Path)) {
5298
5788
            $Include_Neighbors{$LibVersion}{$Part} = $Path;
5299
5789
        }
5300
5790
    }
5302
5792
    { # search for "lib/include/" directory
5303
5793
        my $LibDir = $Dir;
5304
5794
        if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5305
 
            register_directory($LibDir, $WithDeps, $LibVersion);
 
5795
            registerDir($LibDir, $WithDeps, $LibVersion);
5306
5796
        }
5307
5797
    }
5308
5798
}
5322
5812
        |update\ to\ include
5323
5813
        |replaced\ with
5324
5814
        |replaced\ by|renamed\ to
5325
 
        |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
 
5815
        |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5326
5816
        {
5327
5817
            $Redirect = $2;
5328
5818
            last;
5337
5827
         |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5338
5828
         |is\ not\ supported\ API\ for\ general\ use
5339
5829
         |do\ not\ use
5340
 
         |should\ not\ be\ used
 
5830
         |should\ not\ be\ (used|using)
5341
5831
         |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5342
5832
            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5343
5833
        }
5354
5844
{
5355
5845
    my ($Content, $Path) = @_;
5356
5846
    my %Includes = ();
5357
 
    while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
 
5847
    while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m)
5358
5848
    { # C/C++: include, Objective C/C++: import directive
5359
 
        my ($Header, $Method) = ($5, $4);
 
5849
        my $Header = $2;
 
5850
        my $Method = substr($Header, 0, 1, "");
 
5851
        substr($Header, length($Header)-1, 1, "");
5360
5852
        $Header = path_format($Header, $OSgroup);
5361
5853
        if($Method eq "\"" or is_abs($Header))
5362
5854
        {
5363
 
            if(-e joinPath(get_dirname($Path), $Header))
 
5855
            if(-e join_P(get_dirname($Path), $Header))
5364
5856
            { # relative path exists
5365
5857
                $Includes{$Header} = -1;
5366
5858
            }
5373
5865
            $Includes{$Header} = 1;
5374
5866
        }
5375
5867
    }
 
5868
    if($ExtraInfo)
 
5869
    {
 
5870
        while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m)
 
5871
        { # FT_FREETYPE_H
 
5872
            $Includes{$2} = 0;
 
5873
        }
 
5874
    }
5376
5875
    return \%Includes;
5377
5876
}
5378
5877
 
5390
5889
    return 0;
5391
5890
}
5392
5891
 
5393
 
sub sort_by_word($$)
 
5892
sub sortByWord($$)
5394
5893
{
5395
5894
    my ($ArrRef, $W) = @_;
5396
5895
    return if(length($W)<2);
5397
5896
    @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5398
5897
}
5399
5898
 
5400
 
sub natural_sorting($$)
 
5899
sub sortHeaders($$)
5401
5900
{
5402
5901
    my ($H1, $H2) = @_;
 
5902
    
5403
5903
    $H1=~s/\.[a-z]+\Z//ig;
5404
5904
    $H2=~s/\.[a-z]+\Z//ig;
5405
 
    my ($HDir1, $Hname1) = separate_path($H1);
5406
 
    my ($HDir2, $Hname2) = separate_path($H2);
 
5905
    
 
5906
    my $Hname1 = get_filename($H1);
 
5907
    my $Hname2 = get_filename($H2);
 
5908
    my $HDir1 = get_dirname($H1);
 
5909
    my $HDir2 = get_dirname($H2);
5407
5910
    my $Dirname1 = get_filename($HDir1);
5408
5911
    my $Dirname2 = get_filename($HDir2);
5409
 
    if($H1 eq $H2) {
 
5912
    
 
5913
    $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
 
5914
    $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
 
5915
    
 
5916
    if($_[0] eq $_[1]
 
5917
    or $H1 eq $H2) {
5410
5918
        return 0;
5411
5919
    }
5412
5920
    elsif($H1=~/\A\Q$H2\E/) {
5417
5925
    }
5418
5926
    elsif($HDir1=~/\Q$Hname1\E/i
5419
5927
    and $HDir2!~/\Q$Hname2\E/i)
5420
 
    {# include/glib-2.0/glib.h
 
5928
    { # include/glib-2.0/glib.h
5421
5929
        return -1;
5422
5930
    }
5423
5931
    elsif($HDir2=~/\Q$Hname2\E/i
5424
5932
    and $HDir1!~/\Q$Hname1\E/i)
5425
 
    {# include/glib-2.0/glib.h
 
5933
    { # include/glib-2.0/glib.h
5426
5934
        return 1;
5427
5935
    }
5428
5936
    elsif($Hname1=~/\Q$Dirname1\E/i
5429
5937
    and $Hname2!~/\Q$Dirname2\E/i)
5430
 
    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
 
5938
    { # include/hildon-thumbnail/hildon-thumbnail-factory.h
5431
5939
        return -1;
5432
5940
    }
5433
5941
    elsif($Hname2=~/\Q$Dirname2\E/i
5434
5942
    and $Hname1!~/\Q$Dirname1\E/i)
5435
 
    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5436
 
        return 1;
5437
 
    }
5438
 
    elsif($Hname1=~/(config|lib)/i
5439
 
    and $Hname2!~/(config|lib)/i)
5440
 
    {# include/alsa/asoundlib.h
5441
 
        return -1;
5442
 
    }
5443
 
    elsif($Hname2=~/(config|lib)/i
5444
 
    and $Hname1!~/(config|lib)/i)
5445
 
    {# include/alsa/asoundlib.h
5446
 
        return 1;
5447
 
    }
5448
 
    elsif(checkRelevance($H1)
5449
 
    and not checkRelevance($H2))
5450
 
    {# libebook/e-book.h
5451
 
        return -1;
5452
 
    }
5453
 
    elsif(checkRelevance($H2)
5454
 
    and not checkRelevance($H1))
5455
 
    {# libebook/e-book.h
5456
 
        return 1;
5457
 
    }
5458
 
    else {
5459
 
        return (lc($H1) cmp lc($H2));
 
5943
    { # include/hildon-thumbnail/hildon-thumbnail-factory.h
 
5944
        return 1;
 
5945
    }
 
5946
    elsif($Hname1=~/(config|lib|util)/i
 
5947
    and $Hname2!~/(config|lib|util)/i)
 
5948
    { # include/alsa/asoundlib.h
 
5949
        return -1;
 
5950
    }
 
5951
    elsif($Hname2=~/(config|lib|util)/i
 
5952
    and $Hname1!~/(config|lib|util)/i)
 
5953
    { # include/alsa/asoundlib.h
 
5954
        return 1;
 
5955
    }
 
5956
    else
 
5957
    {
 
5958
        my $R1 = checkRelevance($H1);
 
5959
        my $R2 = checkRelevance($H2);
 
5960
        if($R1 and not $R2)
 
5961
        { # libebook/e-book.h
 
5962
            return -1;
 
5963
        }
 
5964
        elsif($R2 and not $R1)
 
5965
        { # libebook/e-book.h
 
5966
            return 1;
 
5967
        }
 
5968
        else
 
5969
        {
 
5970
            return (lc($H1) cmp lc($H2));
 
5971
        }
5460
5972
    }
5461
5973
}
5462
5974
 
5463
5975
sub searchForHeaders($)
5464
5976
{
5465
5977
    my $LibVersion = $_[0];
 
5978
    
5466
5979
    # gcc standard include paths
5467
 
    find_gcc_cxx_headers($LibVersion);
 
5980
    registerGccHeaders();
 
5981
    
 
5982
    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
 
5983
    { # c++ standard include paths
 
5984
        registerCppHeaders();
 
5985
    }
 
5986
    
5468
5987
    # processing header paths
5469
 
    foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5470
 
    keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
 
5988
    foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}},
 
5989
    @{$Descriptor{$LibVersion}{"AddIncludePaths"}})
5471
5990
    {
5472
5991
        my $IPath = $Path;
 
5992
        if($SystemRoot)
 
5993
        {
 
5994
            if(is_abs($Path)) {
 
5995
                $Path = $SystemRoot.$Path;
 
5996
            }
 
5997
        }
5473
5998
        if(not -e $Path) {
5474
5999
            exitStatus("Access_Error", "can't access \'$Path\'");
5475
6000
        }
5479
6004
        elsif(-d $Path)
5480
6005
        {
5481
6006
            $Path = get_abs_path($Path);
5482
 
            register_directory($Path, 0, $LibVersion);
5483
 
            if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5484
 
                $Add_Include_Paths{$LibVersion}{$Path} = 1;
 
6007
            registerDir($Path, 0, $LibVersion);
 
6008
            if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
 
6009
                push(@{$Add_Include_Paths{$LibVersion}}, $Path);
5485
6010
            }
5486
6011
            else {
5487
 
                $Include_Paths{$LibVersion}{$Path} = 1;
 
6012
                push(@{$Include_Paths{$LibVersion}}, $Path);
5488
6013
            }
5489
6014
        }
5490
6015
    }
5491
 
    if(keys(%{$Include_Paths{$LibVersion}})) {
 
6016
    if(@{$Include_Paths{$LibVersion}}) {
5492
6017
        $INC_PATH_AUTODETECT{$LibVersion} = 0;
5493
6018
    }
 
6019
    
5494
6020
    # registering directories
5495
6021
    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5496
6022
    {
5498
6024
        $Path = get_abs_path($Path);
5499
6025
        $Path = path_format($Path, $OSgroup);
5500
6026
        if(-d $Path) {
5501
 
            register_directory($Path, 1, $LibVersion);
 
6027
            registerDir($Path, 1, $LibVersion);
5502
6028
        }
5503
6029
        elsif(-f $Path)
5504
6030
        {
5505
6031
            my $Dir = get_dirname($Path);
5506
 
            if(not $SystemPaths{"include"}{$Dir}
 
6032
            if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
5507
6033
            and not $LocalIncludes{$Dir})
5508
6034
            {
5509
 
                register_directory($Dir, 1, $LibVersion);
5510
 
                if(my $OutDir = get_dirname($Dir))
5511
 
                { # registering the outer directory
5512
 
                    if(not $SystemPaths{"include"}{$OutDir}
5513
 
                    and not $LocalIncludes{$OutDir}) {
5514
 
                        register_directory($OutDir, 0, $LibVersion);
5515
 
                    }
5516
 
                }
 
6035
                registerDir($Dir, 1, $LibVersion);
 
6036
                # if(my $OutDir = get_dirname($Dir))
 
6037
                # { # registering the outer directory
 
6038
                #     if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
 
6039
                #     and not $LocalIncludes{$OutDir}) {
 
6040
                #         registerDir($OutDir, 0, $LibVersion);
 
6041
                #     }
 
6042
                # }
5517
6043
            }
5518
6044
        }
5519
6045
    }
5538
6064
        elsif(-d $Dest)
5539
6065
        {
5540
6066
            my @Registered = ();
5541
 
            foreach my $Path (cmd_find($Dest,"f","",""))
 
6067
            foreach my $Path (cmd_find($Dest,"f"))
5542
6068
            {
5543
6069
                next if(ignore_path($Path));
5544
6070
                next if(not is_header($Path, 0, $LibVersion));
5546
6072
                    push(@Registered, $HPath);
5547
6073
                }
5548
6074
            }
5549
 
            @Registered = sort {natural_sorting($a, $b)} @Registered;
5550
 
            sort_by_word(\@Registered, $TargetLibraryShortName);
 
6075
            @Registered = sort {sortHeaders($a, $b)} @Registered;
 
6076
            sortByWord(\@Registered, $TargetLibraryShortName);
5551
6077
            foreach my $Path (@Registered) {
5552
6078
                $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5553
6079
            }
5556
6082
            exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5557
6083
        }
5558
6084
    }
 
6085
    
 
6086
    if(defined $Tolerance and $Tolerance=~/4/)
 
6087
    { # 4 - skip headers included by others
 
6088
        foreach my $Path (keys(%{$Registered_Headers{$LibVersion}}))
 
6089
        {
 
6090
            if(defined $Header_Includes_R{$LibVersion}{$Path}) {
 
6091
                delete($Registered_Headers{$LibVersion}{$Path});
 
6092
            }
 
6093
        }
 
6094
    }
 
6095
    
5559
6096
    if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5560
6097
    { # preparing preamble headers
5561
 
        my $PPos=0;
5562
6098
        foreach my $Header (split(/\s*\n\s*/, $HList))
5563
6099
        {
5564
6100
            if(is_abs($Header) and not -f $Header) {
5568
6104
            if(my $Header_Path = is_header($Header, 1, $LibVersion))
5569
6105
            {
5570
6106
                next if(skipHeader($Header_Path, $LibVersion));
5571
 
                $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
 
6107
                push_U($Include_Preamble{$LibVersion}, $Header_Path);
5572
6108
            }
5573
6109
            else {
5574
6110
                exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5608
6144
    
5609
6145
    foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5610
6146
    { # ordering headers according to descriptor
5611
 
        my $PairName=$Include_Order{$LibVersion}{$HeaderName};
 
6147
        my $PairName = $Include_Order{$LibVersion}{$HeaderName};
5612
6148
        my ($Pos, $PairPos) = (-1, -1);
5613
6149
        my ($Path, $PairPath) = ();
5614
6150
        my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5695
6231
                $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5696
6232
            }
5697
6233
        }
 
6234
        else
 
6235
        { # can't find
 
6236
            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
 
6237
        }
5698
6238
    }
5699
6239
    if(my $Inc = parse_includes($Content, $Path))
5700
6240
    {
5701
6241
        foreach my $Include (keys(%{$Inc}))
5702
6242
        { # detect includes
5703
6243
            $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
 
6244
            
 
6245
            if(defined $Tolerance and $Tolerance=~/4/)
 
6246
            {
 
6247
                if(my $HPath = identifyHeader($Include, $LibVersion))
 
6248
                {
 
6249
                    $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1;
 
6250
                }
 
6251
            }
5704
6252
        }
5705
6253
    }
5706
6254
}
5707
6255
 
5708
 
sub simplify_path($)
5709
 
{
5710
 
    my $Path = $_[0];
5711
 
    while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5712
 
    return $Path;
5713
 
}
5714
 
 
5715
6256
sub fromLibc($)
5716
 
{ # GLIBC header
 
6257
{ # system GLIBC header
5717
6258
    my $Path = $_[0];
5718
6259
    my ($Dir, $Name) = separate_path($Path);
5719
 
    if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
5720
 
    { # /usr/include/{stdio, ...}.h
5721
 
      # epoc32/include/libc/{stdio, ...}.h
5722
 
        return 1;
 
6260
    if($OStarget eq "symbian")
 
6261
    {
 
6262
        if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name})
 
6263
        { # epoc32/include/libc/{stdio, ...}.h
 
6264
            return 1;
 
6265
        }
5723
6266
    }
5724
 
    if(isLibcDir($Dir)) {
5725
 
        return 1;
 
6267
    else
 
6268
    {
 
6269
        if($Dir eq "/usr/include" and $GlibcHeader{$Name})
 
6270
        { # /usr/include/{stdio, ...}.h
 
6271
            return 1;
 
6272
        }
5726
6273
    }
5727
6274
    return 0;
5728
6275
}
5729
6276
 
5730
6277
sub isLibcDir($)
5731
 
{ # GLIBC directory
 
6278
{ # system GLIBC directory
5732
6279
    my $Dir = $_[0];
5733
6280
    my ($OutDir, $Name) = separate_path($Dir);
5734
 
    if(get_filename($OutDir)=~/\A(include|libc)\Z/
5735
 
    and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5736
 
    { # /usr/include/{sys,bits,asm,asm-*}/*.h
5737
 
        return 1;
 
6281
    if($OStarget eq "symbian")
 
6282
    {
 
6283
        if(get_filename($OutDir) eq "libc"
 
6284
        and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
 
6285
        { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h
 
6286
            return 1;
 
6287
        }
 
6288
    }
 
6289
    else
 
6290
    { # linux
 
6291
        if($OutDir eq "/usr/include"
 
6292
        and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
 
6293
        { # /usr/include/{sys,bits,asm,asm-*}/*.h
 
6294
            return 1;
 
6295
        }
5738
6296
    }
5739
6297
    return 0;
5740
6298
}
5748
6306
    }
5749
6307
    my ($AbsDir, $Name) = separate_path($AbsPath);
5750
6308
    if(isLibcDir($AbsDir))
5751
 
    { # GLIBC internals
5752
 
        return ();
 
6309
    { # system GLIBC internals
 
6310
        return () if(not $ExtraInfo);
5753
6311
    }
5754
6312
    if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5755
6313
        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5756
6314
    }
5757
6315
    return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5758
 
    return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
 
6316
    
 
6317
    if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING)
 
6318
    { # skip /usr/include/c++/*/ headers
 
6319
        return () if(not $ExtraInfo);
 
6320
    }
 
6321
    
5759
6322
    push(@RecurInclude, $AbsPath);
5760
 
    if($DefaultGccPaths{$AbsDir}
5761
 
    or fromLibc($AbsPath))
 
6323
    if(grep { $AbsDir eq $_ } @DefaultGccPaths
 
6324
    or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath)))
5762
6325
    { # check "real" (non-"model") include paths
5763
6326
        my @Paths = detect_real_includes($AbsPath, $LibVersion);
5764
6327
        pop(@RecurInclude);
5773
6336
        my $HPath = "";
5774
6337
        if($IncType<0)
5775
6338
        { # for #include "..."
5776
 
            my $Candidate = joinPath($AbsDir, $Include);
 
6339
            my $Candidate = join_P($AbsDir, $Include);
5777
6340
            if(-f $Candidate) {
5778
 
                $HPath = simplify_path($Candidate);
 
6341
                $HPath = realpath($Candidate);
5779
6342
            }
5780
6343
        }
5781
6344
        elsif($IncType>0
5782
6345
        and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
5783
6346
        { # search for the nearest header
5784
6347
          # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5785
 
            my $Candidate = joinPath(get_dirname($AbsDir), $Include);
 
6348
            my $Candidate = join_P(get_dirname($AbsDir), $Include);
5786
6349
            if(-f $Candidate) {
5787
6350
                $HPath = $Candidate;
5788
6351
            }
5794
6357
        if($HPath eq $AbsPath) {
5795
6358
            next;
5796
6359
        }
 
6360
        
 
6361
        if($Debug)
 
6362
        { # boundary headers
 
6363
#             if($HPath=~/vtk/ and $AbsPath!~/vtk/)
 
6364
#             {
 
6365
#                 print STDERR "$AbsPath -> $HPath\n";
 
6366
#             }
 
6367
        }
 
6368
        
5797
6369
        $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5798
6370
        if($IncType>0)
5799
6371
        { # only include <...>, skip include "..." prefixes
5858
6430
    if(defined $Cache{"find_in_defaults"}{$Header}) {
5859
6431
        return $Cache{"find_in_defaults"}{$Header};
5860
6432
    }
5861
 
    foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5862
 
    (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
 
6433
    foreach my $Dir (@DefaultIncPaths,
 
6434
                     @DefaultGccPaths,
 
6435
                     @DefaultCppPaths,
 
6436
                     @UsersIncPath)
5863
6437
    {
5864
6438
        next if(not $Dir);
5865
6439
        if(-f $Dir."/".$Header) {
5903
6477
 
5904
6478
sub checkRelevance($)
5905
6479
{
5906
 
    my ($Path) = @_;
 
6480
    my $Path = $_[0];
5907
6481
    return 0 if(not $Path);
 
6482
    
5908
6483
    if($SystemRoot) {
5909
 
        $Path=~s/\A\Q$SystemRoot\E//g;
 
6484
        $Path = cut_path_prefix($Path, $SystemRoot);
5910
6485
    }
5911
 
    my ($Dir, $Name) = separate_path($Path);
5912
 
    $Name=~s/\.\w+\Z//g;# remove extension (.h)
5913
 
    my @Tokens = split(/[_\d\W]+/, $Name);
5914
 
    foreach (@Tokens)
 
6486
    
 
6487
    my $Name = lc(get_filename($Path));
 
6488
    my $Dir = lc(get_dirname($Path));
 
6489
    
 
6490
    $Name=~s/\.\w+\Z//g; # remove extension (.h)
 
6491
    
 
6492
    foreach my $Token (split(/[_\d\W]+/, $Name))
5915
6493
    {
5916
 
        next if(not $_);
5917
 
        if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5918
 
        or length($_)>=4 and $Dir=~/\Q$_\E/i)
 
6494
        my $Len = length($Token);
 
6495
        next if($Len<=1);
 
6496
        if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/)
 
6497
        { # include/evolution-data-server-1.4/libebook/e-book.h
 
6498
            return 1;
 
6499
        }
 
6500
        if($Len>=4 and index($Dir, $Token)!=-1)
5919
6501
        { # include/gupnp-1.0/libgupnp/gupnp-context.h
5920
 
          # include/evolution-data-server-1.4/libebook/e-book.h
5921
6502
            return 1;
5922
6503
        }
5923
6504
    }
5991
6572
            return 0;
5992
6573
        }
5993
6574
    }
5994
 
    if($OStarget ne "bsd") {
 
6575
    if($OStarget ne "bsd")
 
6576
    {
5995
6577
        if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
5996
6578
        { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
5997
6579
            return 0;
5998
6580
        }
5999
6581
    }
 
6582
    if($OStarget ne "windows")
 
6583
    {
 
6584
        if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
 
6585
        { # skip /usr/include/wine/msvcrt
 
6586
            return 0;
 
6587
        }
 
6588
    }
6000
6589
    if(not get_dirname($Header)
6001
6590
    and $Candidate=~/[\/\\]wx[\/\\]/)
6002
6591
    { # do NOT search in system /wx/ directory
6068
6657
    { # incorrect absolute path
6069
6658
        return "";
6070
6659
    }
6071
 
    if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
 
6660
    if(defined $ConfHeaders{lc($Header)})
6072
6661
    { # too abstract configuration headers
6073
6662
        return "";
6074
6663
    }
 
6664
    my $HName = get_filename($Header);
6075
6665
    if($OSgroup ne "windows")
6076
6666
    {
6077
 
        if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
 
6667
        if(defined $WinHeaders{lc($HName)}
 
6668
        or $HName=~/windows|win32|win64/i)
6078
6669
        { # windows headers
6079
6670
            return "";
6080
6671
        }
6081
 
        elsif($Header=~/\A(mem)\.h\Z/)
6082
 
        { # pngconf.h include mem.h for __MSDOS__
6083
 
            return "";
6084
 
        }
6085
 
    }
6086
 
    if($OSgroup ne "solaris")
6087
 
    {
6088
 
        if($Header=~/\A(thread)\.h\Z/)
6089
 
        { # thread.h in Solaris
6090
 
            return "";
6091
 
        }
6092
 
    }
6093
 
    
6094
 
    foreach my $Path (keys(%{$SystemPaths{"include"}}))
 
6672
    }
 
6673
    if($OSgroup ne "macos")
 
6674
    {
 
6675
        if($HName eq "fp.h")
 
6676
        { # pngconf.h includes fp.h in Mac OS
 
6677
            return "";
 
6678
        }
 
6679
    }
 
6680
    
 
6681
    if(defined $ObsoleteHeaders{$HName})
 
6682
    { # obsolete headers
 
6683
        return "";
 
6684
    }
 
6685
    if($OSgroup eq "linux" or $OSgroup eq "bsd")
 
6686
    {
 
6687
        if(defined $AlienHeaders{$HName}
 
6688
        or defined $AlienHeaders{$Header})
 
6689
        { # alien headers from other systems
 
6690
            return "";
 
6691
        }
 
6692
    }
 
6693
    
 
6694
    foreach my $Path (@{$SystemPaths{"include"}})
6095
6695
    { # search in default paths
6096
6696
        if(-f $Path."/".$Header) {
6097
 
            return joinPath($Path,$Header);
 
6697
            return join_P($Path,$Header);
6098
6698
        }
6099
6699
    }
6100
6700
    if(not keys(%SystemHeaders))
6139
6739
{
6140
6740
    my $Dir = $_[0];
6141
6741
    $Dir=~s/[\/\\]+\Z//;
6142
 
    return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
 
6742
    return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths);
6143
6743
}
6144
6744
 
6145
6745
sub identifyHeader($$)
6167
6767
    { # search for libc headers in the /usr/include
6168
6768
      # for non-libc target library before searching
6169
6769
      # in the library paths
6170
 
        return joinPath($HeaderDir,$Header);
 
6770
        return join_P($HeaderDir,$Header);
6171
6771
    }
6172
6772
    elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6173
6773
    { # search in the target library paths
6174
6774
        return $Path;
6175
6775
    }
6176
 
    elsif($DefaultGccHeader{$Header})
 
6776
    elsif(defined $DefaultGccHeader{$Header})
6177
6777
    { # search in the internal GCC include paths
6178
6778
        return $DefaultGccHeader{$Header};
6179
6779
    }
6180
6780
    elsif(my $DefaultDir = find_in_defaults($Header))
6181
6781
    { # search in the default GCC include paths
6182
 
        return joinPath($DefaultDir,$Header);
 
6782
        return join_P($DefaultDir,$Header);
6183
6783
    }
6184
 
    elsif($DefaultCppHeader{$Header})
 
6784
    elsif(defined $DefaultCppHeader{$Header})
6185
6785
    { # search in the default G++ include paths
6186
6786
        return $DefaultCppHeader{$Header};
6187
6787
    }
6195
6795
        {
6196
6796
            my $RelPath = "Headers\/".get_filename($Header);
6197
6797
            if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6198
 
                return joinPath($HeaderDir, $RelPath);
 
6798
                return join_P($HeaderDir, $RelPath);
6199
6799
            }
6200
6800
        }
6201
6801
    }
6208
6808
    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6209
6809
    {
6210
6810
        if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6211
 
            return ($1, $2);
 
6811
            return (path_format($1, $OSgroup), $2);
6212
6812
        }
6213
6813
    }
6214
6814
    return ();
6224
6824
            {
6225
6825
                if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6226
6826
                { # short unsigned int (may include spaces)
6227
 
                    return $1;
 
6827
                    my $Str = $1;
 
6828
                    if($CppMode{$Version}
 
6829
                    and $Str=~/\Ac99_(.+)\Z/)
 
6830
                    {
 
6831
                        if($CppKeywords_A{$1}) {
 
6832
                            $Str=$1;
 
6833
                        }
 
6834
                    }
 
6835
                    return $Str;
6228
6836
                }
6229
6837
            }
6230
6838
        }
6239
6847
        if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6240
6848
        {
6241
6849
            my $Str = $1;
6242
 
            if($C99Mode{$Version}
6243
 
            and $Str=~/\Ac99_(.+)\Z/) {
 
6850
            if($CppMode{$Version}
 
6851
            and $Str=~/\Ac99_(.+)\Z/)
 
6852
            {
6244
6853
                if($CppKeywords_A{$1}) {
6245
6854
                    $Str=$1;
6246
6855
                }
6255
6864
{
6256
6865
    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6257
6866
    {
6258
 
        if($Info=~/ operator /)
 
6867
        if(index($Info, " operator ")!=-1)
6259
6868
        {
6260
 
            if($Info=~/ conversion /)
 
6869
            if(index($Info, " conversion ")!=-1)
6261
6870
            {
6262
6871
                if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6263
6872
                {
6316
6925
    return $_[0];
6317
6926
}
6318
6927
 
6319
 
sub unmangleSymbol($)
6320
 
{
6321
 
    my $Symbol = $_[0];
6322
 
    if(my @Unmngl = unmangleArray($Symbol)) {
6323
 
        return $Unmngl[0];
6324
 
    }
6325
 
    return "";
6326
 
}
6327
 
 
6328
6928
sub unmangleArray(@)
6329
6929
{
6330
6930
    if($_[0]=~/\A\?/)
6334
6934
            exitStatus("Not_Found", "can't find \"undname\"");
6335
6935
        }
6336
6936
        writeFile("$TMP_DIR/unmangle", join("\n", @_));
6337
 
        return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
 
6937
        return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
6338
6938
    }
6339
6939
    else
6340
6940
    { # GCC mangling
6342
6942
        if(not $CppFiltCmd) {
6343
6943
            exitStatus("Not_Found", "can't find c++filt in PATH");
6344
6944
        }
6345
 
        my $Info = `$CppFiltCmd -h 2>&1`;
6346
 
        if($Info=~/\@<file>/)
6347
 
        {# new version of c++filt can take a file
6348
 
            my $NoStrip = "";
6349
 
            if($OSgroup eq "macos"
6350
 
            or $OSgroup eq "windows") {
6351
 
                $NoStrip = "-n";
6352
 
            }
6353
 
            writeFile("$TMP_DIR/unmangle", join("\n", @_));
6354
 
            return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
 
6945
        if(not defined $CPPFILT_SUPPORT_FILE)
 
6946
        {
 
6947
            my $Info = `$CppFiltCmd -h 2>&1`;
 
6948
            $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
 
6949
        }
 
6950
        my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":"";
 
6951
        if($CPPFILT_SUPPORT_FILE)
 
6952
        { # new versions of c++filt can take a file
 
6953
            if($#_>$MAX_CPPFILT_FILE_SIZE)
 
6954
            { # c++filt <= 2.22 may crash on large files (larger than 8mb)
 
6955
              # this is fixed in the oncoming version of Binutils
 
6956
                my @Half = splice(@_, 0, ($#_+1)/2);
 
6957
                return (unmangleArray(@Half), unmangleArray(@_))
 
6958
            }
 
6959
            else
 
6960
            {
 
6961
                writeFile("$TMP_DIR/unmangle", join("\n", @_));
 
6962
                my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
 
6963
                if($?==139)
 
6964
                { # segmentation fault
 
6965
                    printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
 
6966
                }
 
6967
                return split(/\n/, $Res);
 
6968
            }
6355
6969
        }
6356
6970
        else
6357
6971
        { # old-style unmangling
6358
 
            if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
 
6972
            if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
 
6973
            {
6359
6974
                my @Half = splice(@_, 0, ($#_+1)/2);
6360
6975
                return (unmangleArray(@Half), unmangleArray(@_))
6361
6976
            }
6362
6977
            else
6363
6978
            {
6364
 
                my $NoStrip = "";
6365
 
                if($OSgroup eq "macos"
6366
 
                or $OSgroup eq "windows") {
6367
 
                    $NoStrip = "-n";
6368
 
                }
6369
6979
                my $Strings = join(" ", @_);
6370
 
                return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
 
6980
                my $Res = `$CppFiltCmd $NoStrip $Strings`;
 
6981
                if($?==139)
 
6982
                { # segmentation fault
 
6983
                    printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
 
6984
                }
 
6985
                return split(/\n/, $Res);
6371
6986
            }
6372
6987
        }
6373
6988
    }
6383
6998
    my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
6384
6999
    if($Symbol=~/\A(_Z|\?)/)
6385
7000
    { # C++
 
7001
        # some standard typedefs
6386
7002
        $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6387
7003
        $Signature=~s/\Qstd::map<std::string, std::string, std::less<std::string >, std::allocator<std::pair<std::string const, std::string > > >\E/std::map<std::string, std::string>/g;
6388
7004
    }
6389
 
    if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
 
7005
    if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
6390
7006
    { # ELF format marks data as OBJECT
6391
7007
        if($GlobalDataObject{$LibVersion}{$Symbol}) {
6392
7008
            $Signature .= " [data]";
6478
7094
    { # non-public global data
6479
7095
        return get_SignatureNoInfo($Symbol, $LibVersion);
6480
7096
    }
6481
 
    my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
 
7097
    my ($Signature, @Param_Types_FromUnmangledName) = ();
6482
7098
    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6483
7099
    if($Symbol=~/\A(_Z|\?)/)
6484
7100
    {
6485
 
        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6486
 
            $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
 
7101
        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
 
7102
        {
 
7103
            $Signature .= $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::";
 
7104
            if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) {
 
7105
                $Signature .= "~";
 
7106
            }
 
7107
            $Signature .= $ShortName;
6487
7108
        }
6488
7109
        elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
6489
 
            $Func_Signature = $NameSpace."::".$ShortName;
 
7110
            $Signature .= $NameSpace."::".$ShortName;
6490
7111
        }
6491
7112
        else {
6492
 
            $Func_Signature = $ShortName;
 
7113
            $Signature .= $ShortName;
6493
7114
        }
6494
 
        @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
 
7115
        my ($Short, $Params) = split_Signature($tr_name{$MnglName});
 
7116
        @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
6495
7117
    }
6496
 
    else {
6497
 
        $Func_Signature = $MnglName;
 
7118
    else
 
7119
    {
 
7120
        $Signature .= $MnglName;
6498
7121
    }
6499
7122
    my @ParamArray = ();
6500
7123
    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
6508
7131
        }
6509
7132
        foreach my $Typedef (keys(%ChangedTypedef))
6510
7133
        {
6511
 
            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
6512
 
            $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
 
7134
            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
 
7135
                $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
 
7136
            }
6513
7137
        }
6514
7138
        if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
6515
7139
            push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6520
7144
    }
6521
7145
    if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6522
7146
    or $GlobalDataObject{$LibVersion}{$Symbol}) {
6523
 
        $Func_Signature .= " [data]";
 
7147
        $Signature .= " [data]";
6524
7148
    }
6525
7149
    else
6526
7150
    {
6527
7151
        if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
6528
7152
        { # add [in-charge]
6529
 
            $Func_Signature .= " ".$ChargeLevel;
 
7153
            $Signature .= " ".$ChargeLevel;
6530
7154
        }
6531
 
        $Func_Signature .= " (".join(", ", @ParamArray).")";
 
7155
        $Signature .= " (".join(", ", @ParamArray).")";
6532
7156
        if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6533
7157
        or $Symbol=~/\A_ZN(V|)K/) {
6534
 
            $Func_Signature .= " const";
 
7158
            $Signature .= " const";
6535
7159
        }
6536
7160
        if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6537
7161
        or $Symbol=~/\A_ZN(K|)V/) {
6538
 
            $Func_Signature .= " volatile";
 
7162
            $Signature .= " volatile";
6539
7163
        }
6540
7164
        if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6541
7165
        and $Symbol=~/\A(_Z|\?)/)
6542
 
        {# for static methods
6543
 
            $Func_Signature .= " [static]";
 
7166
        { # for static methods
 
7167
            $Signature .= " [static]";
6544
7168
        }
6545
7169
    }
6546
7170
    if(defined $ShowRetVal
6547
7171
    and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6548
 
        $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
 
7172
        $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
6549
7173
    }
6550
7174
    if($SymbolVersion) {
6551
 
        $Func_Signature .= $VersionSpec.$SymbolVersion;
 
7175
        $Signature .= $VersionSpec.$SymbolVersion;
6552
7176
    }
6553
 
    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
 
7177
    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature);
6554
7178
}
6555
7179
 
6556
7180
sub create_member_decl($$)
6591
7215
            }
6592
7216
        }
6593
7217
    }
6594
 
    return ""
 
7218
    return "";
6595
7219
}
6596
7220
 
6597
7221
sub getFuncTypeId($)
6605
7229
    return 0;
6606
7230
}
6607
7231
 
6608
 
sub isNotAnon($) {
6609
 
    return (not isAnon($_[0]));
6610
 
}
6611
 
 
6612
7232
sub isAnon($)
6613
7233
{ # "._N" or "$_N" in older GCC versions
6614
7234
    return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
6615
7235
}
6616
7236
 
6617
 
sub formatName($)
 
7237
sub formatName($$)
6618
7238
{ # type name correction
6619
 
    if(defined $Cache{"formatName"}{$_[0]}) {
6620
 
        return $Cache{"formatName"}{$_[0]};
6621
 
    }
6622
 
    
6623
 
    $_ = $_[0];
6624
 
    
6625
 
    s/\A[ ]+|[ ]+\Z//g;
6626
 
    s/[ ]{2,}/ /g;
6627
 
    s/[ ]*(\W)[ ]*/$1/g;
6628
 
    
6629
 
    s/\bvolatile const\b/const volatile/g;
6630
 
    
6631
 
    s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6632
 
    s/\b(short|long) int\b/$1/g;
6633
 
    
6634
 
    s/([\)\]])(const|volatile)\b/$1 $2/g;
6635
 
    
6636
 
    while(s/>>/> >/g) {};
6637
 
    
6638
 
    s/\b(operator[ ]*)> >/$1>>/;
6639
 
    
6640
 
    return ($Cache{"formatName"}{$_[0]}=$_);
 
7239
    if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
 
7240
        return $Cache{"formatName"}{$_[1]}{$_[0]};
 
7241
    }
 
7242
    
 
7243
    my $N = $_[0];
 
7244
    
 
7245
    if($_[1] ne "S")
 
7246
    {
 
7247
        $N=~s/\A[ ]+//g;
 
7248
        $N=~s/[ ]+\Z//g;
 
7249
        $N=~s/[ ]{2,}/ /g;
 
7250
    }
 
7251
    
 
7252
    $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
 
7253
    
 
7254
    $N=~s/\bvolatile const\b/const volatile/g;
 
7255
    
 
7256
    $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
 
7257
    $N=~s/\b(short|long) int\b/$1/g;
 
7258
    
 
7259
    $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
 
7260
    
 
7261
    while($N=~s/>>/> >/g) {};
 
7262
    
 
7263
    if($_[1] eq "S")
 
7264
    {
 
7265
        if(index($N, "operator")!=-1) {
 
7266
            $N=~s/\b(operator[ ]*)> >/$1>>/;
 
7267
        }
 
7268
    }
 
7269
    
 
7270
    return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
6641
7271
}
6642
7272
 
6643
7273
sub get_HeaderDeps($$)
6701
7331
            { # do NOT include /usr/include/{sys,bits}
6702
7332
                next;
6703
7333
            }
6704
 
            $IncDir{$Dep}=1;
 
7334
            $IncDir{$Dep} = 1;
6705
7335
        }
6706
7336
    }
6707
7337
    $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6733
7363
    return 0;
6734
7364
}
6735
7365
 
6736
 
sub joinPath($$) {
6737
 
    return join($SLASH, @_);
 
7366
sub join_P($$)
 
7367
{
 
7368
    my $S = "/";
 
7369
    if($OSgroup eq "windows") {
 
7370
        $S = "\\";
 
7371
    }
 
7372
    return join($S, @_);
6738
7373
}
6739
7374
 
6740
7375
sub get_namespace_additions($)
6758
7393
            $TypeDecl_Prefix .= "namespace $NS_Part\{";
6759
7394
            $TypeDecl_Suffix .= "}";
6760
7395
        }
6761
 
        my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
 
7396
        my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix;
6762
7397
        my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6763
7398
        $Additions.="  $TypeDecl\n  $FuncDecl\n";
6764
7399
        $AddNameSpaceId+=1;
6767
7402
}
6768
7403
 
6769
7404
sub path_format($$)
6770
 
{ # forward slash to pass into MinGW GCC
 
7405
{
6771
7406
    my ($Path, $Fmt) = @_;
 
7407
    $Path=~s/[\/\\]+\.?\Z//g;
6772
7408
    if($Fmt eq "windows")
6773
7409
    {
6774
7410
        $Path=~s/\//\\/g;
6775
7411
        $Path=lc($Path);
6776
7412
    }
6777
 
    else {
 
7413
    else
 
7414
    { # forward slash to pass into MinGW GCC
6778
7415
        $Path=~s/\\/\//g;
6779
7416
    }
6780
7417
    return $Path;
6791
7428
        }
6792
7429
        elsif($OSgroup eq "macos"
6793
7430
        and $Path=~/\.framework\Z/)
6794
 
        {# to Apple's GCC
 
7431
        { # to Apple's GCC
6795
7432
            return "-F".esc(get_dirname($Path));
6796
7433
        }
6797
7434
        else {
6920
7557
    "timeLocale",
6921
7558
    "tcp_debug",
6922
7559
    "rpc_createerr",
6923
 
# Other C structures appearing in every dump
 
7560
 # Other
6924
7561
    "timespec",
6925
7562
    "random_data",
6926
7563
    "drand48_data",
6932
7569
    "itimerspec",
6933
7570
    "_pthread_cleanup_buffer",
6934
7571
    "fd_set",
6935
 
    "siginfo"
 
7572
    "siginfo",
 
7573
    "mallinfo",
 
7574
    "timex",
 
7575
    "sigcontext",
 
7576
    "ucontext",
 
7577
 # Mac
 
7578
    "_timex",
 
7579
    "_class_t",
 
7580
    "_category_t",
 
7581
    "_class_ro_t",
 
7582
    "_protocol_t",
 
7583
    "_message_ref_t",
 
7584
    "_super_message_ref_t",
 
7585
    "_ivar_t",
 
7586
    "_ivar_list_t"
6936
7587
);
6937
7588
 
6938
7589
sub getCompileCmd($$$)
6962
7613
    }
6963
7614
    # allow extra qualifications
6964
7615
    # and other nonconformant code
6965
 
    $GccCall .= " -fpermissive -w";
 
7616
    $GccCall .= " -fpermissive";
 
7617
    $GccCall .= " -w";
6966
7618
    if($NoStdInc)
6967
7619
    {
6968
7620
        $GccCall .= " -nostdinc";
6972
7624
    { # user-defined options
6973
7625
        $GccCall .= " ".$CompilerOptions{$Version};
6974
7626
    }
6975
 
    $GccCall .= " \"".$Path."\"";
 
7627
    $GccCall .= " \"$Path\"";
6976
7628
    if($Inc)
6977
7629
    { # include paths
6978
7630
        $GccCall .= " ".$Inc;
6980
7632
    return $GccCall;
6981
7633
}
6982
7634
 
6983
 
sub getDump()
 
7635
sub detectPreamble($$)
6984
7636
{
6985
 
    if(not $GCC_PATH) {
6986
 
        exitStatus("Error", "internal error - GCC path is not set");
6987
 
    }
 
7637
    my ($Content, $LibVersion) = @_;
6988
7638
    my %HeaderElems = (
6989
7639
        # Types
6990
7640
        "stdio.h" => ["FILE", "va_list"],
6991
7641
        "stddef.h" => ["NULL", "ptrdiff_t"],
6992
 
        "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
 
7642
        "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
 
7643
                       "int8_t", "int16_t", "int32_t", "int64_t"],
6993
7644
        "time.h" => ["time_t"],
6994
7645
        "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
6995
 
             "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
6996
 
        "unistd.h" => ["gid_t", "uid_t"],
 
7646
                          "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
 
7647
        "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
6997
7648
        "stdbool.h" => ["_Bool"],
6998
7649
        "rpc/xdr.h" => ["bool_t"],
6999
7650
        "in_systm.h" => ["n_long", "n_short"],
7000
7651
        # Fields
7001
7652
        "arpa/inet.h" => ["fw_src", "ip_src"],
7002
7653
        # Functions
7003
 
        "stdlib.h" => ["free", "malloc"],
 
7654
        "stdlib.h" => ["free", "malloc", "size_t"],
7004
7655
        "string.h" => ["memmove", "strcmp"]
7005
7656
    );
7006
7657
    my %AutoPreamble = ();
7007
7658
    foreach (keys(%HeaderElems))
7008
7659
    {
7009
7660
        foreach my $Elem (@{$HeaderElems{$_}}) {
7010
 
            $AutoPreamble{$Elem}=$_;
7011
 
        }
7012
 
    }
7013
 
    my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
7014
 
    my $MHeaderPath = $TmpHeaderPath;
7015
 
    open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
7016
 
    if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7017
 
    {
7018
 
        $AddDefines=~s/\n\s+/\n  /g;
7019
 
        print TMP_HEADER "\n  // add defines\n  ".$AddDefines."\n";
7020
 
    }
7021
 
    print TMP_HEADER "\n  // add includes\n";
7022
 
    my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7023
 
    @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7024
 
    foreach my $Header_Path (@PreambleHeaders) {
7025
 
        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
7026
 
    }
7027
 
    my @Headers = keys(%{$Registered_Headers{$Version}});
7028
 
    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7029
 
    foreach my $Header_Path (@Headers)
7030
 
    {
7031
 
        next if($Include_Preamble{$Version}{$Header_Path});
7032
 
        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
7033
 
    }
7034
 
    close(TMP_HEADER);
7035
 
    my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7036
 
    if($Debug)
7037
 
    { # debug mode
7038
 
        writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7039
 
        writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7040
 
        writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
7041
 
        writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
7042
 
    }
7043
 
    
7044
 
    # Target headers
7045
 
    addTargetHeaders($Version);
7046
 
    
7047
 
    # clean memory
7048
 
    %RecursiveIncludes = ();
7049
 
    %Header_Include_Prefix = ();
7050
 
    %Header_Includes = ();
7051
 
    
7052
 
    # clean cache
7053
 
    delete($Cache{"identifyHeader"});
7054
 
    delete($Cache{"detect_header_includes"});
7055
 
    delete($Cache{"selectSystemHeader"});
7056
 
    
7057
 
    # preprocessing stage
7058
 
    checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
7059
 
    
7060
 
    # clean memory
7061
 
    delete($Include_Neighbors{$Version});
7062
 
    
7063
 
    my $MContent = "";
7064
 
    my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
 
7661
            $AutoPreamble{$Elem} = $_;
 
7662
        }
 
7663
    }
 
7664
    my %Types = ();
 
7665
    while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
 
7666
    { # error: 'FILE' has not been declared
 
7667
        $Types{$2} = 1;
 
7668
    }
 
7669
    if(keys(%Types))
 
7670
    {
 
7671
        my %AddHeaders = ();
 
7672
        foreach my $Type (keys(%Types))
 
7673
        {
 
7674
            if(my $Header = $AutoPreamble{$Type})
 
7675
            {
 
7676
                if(my $Path = identifyHeader($Header, $LibVersion))
 
7677
                {
 
7678
                    if(skipHeader($Path, $LibVersion)) {
 
7679
                        next;
 
7680
                    }
 
7681
                    $Path = path_format($Path, $OSgroup);
 
7682
                    $AddHeaders{$Path}{"Type"} = $Type;
 
7683
                    $AddHeaders{$Path}{"Header"} = $Header;
 
7684
                }
 
7685
            }
 
7686
        }
 
7687
        if(keys(%AddHeaders)) {
 
7688
            return \%AddHeaders;
 
7689
        }
 
7690
    }
 
7691
    return undef;
 
7692
}
 
7693
 
 
7694
sub checkCTags($)
 
7695
{
 
7696
    my $Path = $_[0];
 
7697
    if(not $Path) {
 
7698
        return;
 
7699
    }
 
7700
    my $CTags = undef;
 
7701
    
 
7702
    if($OSgroup eq "bsd")
 
7703
    { # use ectags on BSD
 
7704
        $CTags = get_CmdPath("ectags");
 
7705
        if(not $CTags) {
 
7706
            printMsg("WARNING", "can't find \'ectags\' program");
 
7707
        }
 
7708
    }
 
7709
    if(not $CTags) {
 
7710
        $CTags = get_CmdPath("ctags");
 
7711
    }
 
7712
    if(not $CTags)
 
7713
    {
 
7714
        printMsg("WARNING", "can't find \'ctags\' program");
 
7715
        return;
 
7716
    }
 
7717
    
 
7718
    if($OSgroup ne "linux")
 
7719
    { # macos, freebsd, etc.
 
7720
        my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
 
7721
        if($Info!~/exuberant/i)
 
7722
        {
 
7723
            printMsg("WARNING", "incompatible version of \'ctags\' program");
 
7724
            return;
 
7725
        }
 
7726
    }
 
7727
    
 
7728
    my $Out = $TMP_DIR."/ctags.txt";
 
7729
    system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
 
7730
    if($Debug) {
 
7731
        copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
 
7732
    }
 
7733
    open(CTAGS, "<", $Out);
 
7734
    while(my $Line = <CTAGS>)
 
7735
    {
 
7736
        chomp($Line);
 
7737
        my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
 
7738
        if(defined $Intrinsic_Keywords{$Name})
 
7739
        { # noise
 
7740
            next;
 
7741
        }
 
7742
        if($Type eq "n")
 
7743
        {
 
7744
            if(index($Scpe, "class:")==0) {
 
7745
                next;
 
7746
            }
 
7747
            if(index($Scpe, "struct:")==0) {
 
7748
                next;
 
7749
            }
 
7750
            if(index($Scpe, "namespace:")==0)
 
7751
            {
 
7752
                if($Scpe=~s/\Anamespace://) {
 
7753
                    $Name = $Scpe."::".$Name;
 
7754
                }
 
7755
            }
 
7756
            $TUnit_NameSpaces{$Version}{$Name} = 1;
 
7757
        }
 
7758
        elsif($Type eq "p")
 
7759
        {
 
7760
            if(not $Scpe or index($Scpe, "namespace:")==0) {
 
7761
                $TUnit_Funcs{$Version}{$Name} = 1;
 
7762
            }
 
7763
        }
 
7764
        elsif($Type eq "x")
 
7765
        {
 
7766
            if(not $Scpe or index($Scpe, "namespace:")==0) {
 
7767
                $TUnit_Vars{$Version}{$Name} = 1;
 
7768
            }
 
7769
        }
 
7770
    }
 
7771
    close(CTAGS);
 
7772
}
 
7773
 
 
7774
sub preChange($$)
 
7775
{
 
7776
    my ($HeaderPath, $IncStr) = @_;
 
7777
    
 
7778
    my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr);
 
7779
    my $Content = undef;
 
7780
    
7065
7781
    if($OStarget eq "windows"
7066
7782
    and get_dumpmachine($GCC_PATH)=~/mingw/i
7067
7783
    and $MinGWMode{$Version}!=-1)
7068
7784
    { # modify headers to compile by MinGW
7069
 
        if(not $MContent)
 
7785
        if(not $Content)
7070
7786
        { # preprocessing
7071
 
            $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
 
7787
            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
7072
7788
        }
7073
 
        if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
 
7789
        if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7074
7790
        { # __asm { ... }
7075
7791
            $MinGWMode{$Version}=1;
7076
7792
        }
7077
 
        if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
 
7793
        if($Content=~s/\s+(\/ \/.*?)\n/\n/g)
7078
7794
        { # comments after preprocessing
7079
7795
            $MinGWMode{$Version}=1;
7080
7796
        }
7081
 
        if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
 
7797
        if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7082
7798
        { # 0xffui8
7083
7799
            $MinGWMode{$Version}=1;
7084
7800
        }
7085
 
        if($MinGWMode{$Version})
7086
 
        {
 
7801
        
 
7802
        if($MinGWMode{$Version}) {
7087
7803
            printMsg("INFO", "Using MinGW compatibility mode");
7088
 
            $MHeaderPath = $TMP_DIR."/dump$Version.i";
7089
7804
        }
7090
7805
    }
 
7806
    
7091
7807
    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7092
 
    and $C99Mode{$Version}!=-1 and not $Cpp2003)
 
7808
    and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS)
7093
7809
    { # rename C++ keywords in C code
7094
 
        if(not $MContent)
 
7810
      # disable this code by -cpp-compatible option
 
7811
        if(not $Content)
7095
7812
        { # preprocessing
7096
 
            $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
 
7813
            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
7097
7814
        }
7098
7815
        my $RegExp_C = join("|", keys(%CppKeywords_C));
7099
7816
        my $RegExp_F = join("|", keys(%CppKeywords_F));
7100
7817
        my $RegExp_O = join("|", keys(%CppKeywords_O));
7101
 
        while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
 
7818
        
 
7819
        my $Detected = undef;
 
7820
        
 
7821
        while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7102
7822
        { # MATCH:
7103
7823
          # int foo(int new, int class, int (*new)(int));
7104
7824
          # unsigned private: 8;
7105
7825
          # DO NOT MATCH:
7106
7826
          # #pragma GCC visibility push(default)
7107
 
            $C99Mode{$Version} = 1;
 
7827
            $CppMode{$Version} = 1;
 
7828
            $Detected = "$1$2$3$4" if(not defined $Detected);
7108
7829
        }
7109
 
        if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
 
7830
        if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
7110
7831
        { # MATCH:
7111
7832
          # int delete(...);
7112
7833
          # int explicit(...);
7113
7834
          # DO NOT MATCH:
7114
7835
          # void operator delete(...)
7115
 
            $C99Mode{$Version} = 1;
 
7836
            $CppMode{$Version} = 1;
 
7837
            $Detected = "$1$2$3" if(not defined $Detected);
7116
7838
        }
7117
 
        if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
 
7839
        if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7118
7840
        { # MATCH:
7119
7841
          # int bool;
7120
7842
          # DO NOT MATCH:
7121
7843
          # bool X;
7122
7844
          # return *this;
7123
7845
          # throw;
7124
 
            $C99Mode{$Version} = 1;
 
7846
            $CppMode{$Version} = 1;
 
7847
            $Detected = "$1$2$3" if(not defined $Detected);
7125
7848
        }
7126
 
        if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
 
7849
        if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7127
7850
        { # MATCH:
7128
7851
          # int operator(...);
7129
7852
          # DO NOT MATCH:
7130
7853
          # int operator()(...);
7131
 
            $C99Mode{$Version} = 1;
 
7854
            $CppMode{$Version} = 1;
 
7855
            $Detected = "$1$2$3" if(not defined $Detected);
7132
7856
        }
7133
 
        if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
 
7857
        if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7134
7858
        { # MATCH:
7135
7859
          # int foo(int operator);
7136
7860
          # int foo(int operator, int other);
7137
7861
          # DO NOT MATCH:
7138
7862
          # int operator,(...);
7139
 
            $C99Mode{$Version} = 1;
 
7863
            $CppMode{$Version} = 1;
 
7864
            $Detected = "$1$2$3" if(not defined $Detected);
7140
7865
        }
7141
 
        if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
 
7866
        if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7142
7867
        { # MATCH:
7143
7868
          # int foo(gboolean *bool);
7144
7869
          # DO NOT MATCH:
7145
7870
          # void setTabEnabled(int index, bool);
7146
 
            $C99Mode{$Version} = 1;
 
7871
            $CppMode{$Version} = 1;
 
7872
            $Detected = "$1$2$3" if(not defined $Detected);
7147
7873
        }
7148
 
        if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
 
7874
        if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
7149
7875
        { # MATCH:
7150
7876
          # int foo(int* this);
7151
7877
          # int bar(int this);
 
7878
          # int baz(int throw);
7152
7879
          # DO NOT MATCH:
7153
 
          # baz(X, this);
7154
 
            $C99Mode{$Version} = 1;
7155
 
        }
7156
 
        if($C99Mode{$Version}==1)
7157
 
        { # try to change C++ "keyword" to "c99_keyword"
7158
 
            printMsg("INFO", "Using C99 compatibility mode");
7159
 
            $MHeaderPath = $TMP_DIR."/dump$Version.i";
 
7880
          # foo(X, this);
 
7881
            $CppMode{$Version} = 1;
 
7882
            $Detected = "$1$2$3$4" if(not defined $Detected);
 
7883
        }
 
7884
        if($Content=~s/(struct |extern )(template) /$1c99_$2 /g)
 
7885
        { # MATCH:
 
7886
          # struct template {...};
 
7887
          # extern template foo(...);
 
7888
            $CppMode{$Version} = 1;
 
7889
            $Detected = "$1$2" if(not defined $Detected);
 
7890
        }
 
7891
        
 
7892
        if($CppMode{$Version} == 1)
 
7893
        {
 
7894
            if($Debug)
 
7895
            {
 
7896
                $Detected=~s/\A\s+//g;
 
7897
                printMsg("INFO", "Detected code: \"$Detected\"");
 
7898
            }
 
7899
        }
 
7900
        
 
7901
        # remove typedef enum NAME NAME;
 
7902
        my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
 
7903
        my $N = 0;
 
7904
        while($N<=$#FwdTypedefs-1)
 
7905
        {
 
7906
            my $S = $FwdTypedefs[$N];
 
7907
            if($S eq $FwdTypedefs[$N+1])
 
7908
            {
 
7909
                $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
 
7910
                $CppMode{$Version} = 1;
 
7911
                
 
7912
                if($Debug) {
 
7913
                    printMsg("INFO", "Detected code: \"typedef enum $S $S;\"");
 
7914
                }
 
7915
            }
 
7916
            $N+=2;
 
7917
        }
 
7918
        
 
7919
        if($CppMode{$Version}==1) {
 
7920
            printMsg("INFO", "Using C++ compatibility mode");
7160
7921
        }
7161
7922
    }
7162
 
    if($C99Mode{$Version}==1
 
7923
        
 
7924
    if($CppMode{$Version}==1
7163
7925
    or $MinGWMode{$Version}==1)
7164
 
    { # compile the corrected preprocessor output
7165
 
        writeFile($MHeaderPath, $MContent);
7166
 
    }
7167
 
    
7168
 
    # clean memory
7169
 
    undef $MContent;
 
7926
    {
 
7927
        my $IPath = $TMP_DIR."/dump$Version.i";
 
7928
        writeFile($IPath, $Content);
 
7929
        return $IPath;
 
7930
    }
 
7931
    
 
7932
    return undef;
 
7933
}
 
7934
 
 
7935
sub getDump()
 
7936
{
 
7937
    if(not $GCC_PATH) {
 
7938
        exitStatus("Error", "internal error - GCC path is not set");
 
7939
    }
 
7940
    
 
7941
    my @Headers = keys(%{$Registered_Headers{$Version}});
 
7942
    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
 
7943
    
 
7944
    my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
 
7945
    
 
7946
    my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
 
7947
    my $HeaderPath = $TmpHeaderPath;
 
7948
    
 
7949
    # write tmp-header
 
7950
    open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
 
7951
    if(my $AddDefines = $Descriptor{$Version}{"Defines"})
 
7952
    {
 
7953
        $AddDefines=~s/\n\s+/\n  /g;
 
7954
        print TMP_HEADER "\n  // add defines\n  ".$AddDefines."\n";
 
7955
    }
 
7956
    print TMP_HEADER "\n  // add includes\n";
 
7957
    foreach my $HPath (@{$Include_Preamble{$Version}}) {
 
7958
        print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
 
7959
    }
 
7960
    foreach my $HPath (@Headers)
 
7961
    {
 
7962
        if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
 
7963
            print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
 
7964
        }
 
7965
    }
 
7966
    close(TMP_HEADER);
 
7967
    
 
7968
    if($ExtraInfo)
 
7969
    { # extra information for other tools
 
7970
        if($IncludeString) {
 
7971
            writeFile($ExtraInfo."/include-string", $IncludeString);
 
7972
        }
 
7973
        writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version}));
 
7974
        writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version}));
 
7975
        
 
7976
        if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}}))
 
7977
        {
 
7978
            my $REDIR = "";
 
7979
            foreach my $P1 (sort @Redirects) {
 
7980
                $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n";
 
7981
            }
 
7982
            writeFile($ExtraInfo."/include-redirect", $REDIR);
 
7983
        }
 
7984
    }
 
7985
    
 
7986
    if(not keys(%{$TargetHeaders{$Version}}))
 
7987
    { # Target headers
 
7988
        addTargetHeaders($Version);
 
7989
    }
 
7990
    
 
7991
    # clean memory
 
7992
    %RecursiveIncludes = ();
 
7993
    %Header_Include_Prefix = ();
 
7994
    %Header_Includes = ();
 
7995
    
 
7996
    # clean cache
 
7997
    delete($Cache{"identifyHeader"});
 
7998
    delete($Cache{"detect_header_includes"});
 
7999
    delete($Cache{"selectSystemHeader"});
 
8000
    
 
8001
    # preprocessing stage
 
8002
    my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
 
8003
    checkPreprocessedUnit($Pre);
 
8004
    
 
8005
    if($ExtraInfo)
 
8006
    { # extra information for other tools
 
8007
        writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}})));
 
8008
    }
 
8009
    
 
8010
    # clean memory
 
8011
    delete($Include_Neighbors{$Version});
 
8012
    delete($PreprocessedHeaders{$Version});
 
8013
    
 
8014
    if($COMMON_LANGUAGE{$Version} eq "C++") {
 
8015
        checkCTags($Pre);
 
8016
    }
 
8017
    
 
8018
    if(my $PrePath = preChange($TmpHeaderPath, $IncludeString))
 
8019
    { # try to correct the preprocessor output
 
8020
        $HeaderPath = $PrePath;
 
8021
    }
7170
8022
    
7171
8023
    if($COMMON_LANGUAGE{$Version} eq "C++")
7172
8024
    { # add classes and namespaces to the dump
7173
8025
        my $CHdump = "-fdump-class-hierarchy -c";
7174
 
        if($C99Mode{$Version}==1
 
8026
        if($CppMode{$Version}==1
7175
8027
        or $MinGWMode{$Version}==1) {
7176
8028
            $CHdump .= " -fpreprocessed";
7177
8029
        }
7178
 
        my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
 
8030
        my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString);
7179
8031
        chdir($TMP_DIR);
7180
8032
        system($ClassHierarchyCmd." >null 2>&1");
7181
8033
        chdir($ORIG_DIR);
7182
8034
        if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7183
8035
        {
7184
 
            my %AddClasses = ();
7185
8036
            my $Content = readFile($ClassDump);
7186
8037
            foreach my $ClassInfo (split(/\n\n/, $Content))
7187
8038
            {
7192
8043
                    $TUnit_NameSpaces{$Version}{$CName} = -1;
7193
8044
                    if($CName=~/\A[\w:]+\Z/)
7194
8045
                    { # classes
7195
 
                        $AddClasses{$CName} = 1;
 
8046
                        $TUnit_Classes{$Version}{$CName} = 1;
7196
8047
                    }
7197
8048
                    if($CName=~/(\w[\w:]*)::/)
7198
8049
                    { # namespaces
7208
8059
                    $ClassVTable_Content{$Version}{$CName} = $VTable;
7209
8060
                }
7210
8061
            }
 
8062
            foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
 
8063
            { # add user-defined namespaces
 
8064
                $TUnit_NameSpaces{$Version}{$NS} = 1;
 
8065
            }
7211
8066
            if($Debug)
7212
8067
            { # debug mode
7213
8068
                mkpath($DEBUG_PATH{$Version});
7214
8069
                copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
7215
8070
            }
7216
8071
            unlink($ClassDump);
7217
 
            if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7218
 
            { # GCC on all supported platforms does not include namespaces to the dump by default
7219
 
                appendFile($MHeaderPath, "\n  // add namespaces\n".$NS_Add);
 
8072
        }
 
8073
        
 
8074
        # add namespaces and classes
 
8075
        if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
 
8076
        { # GCC on all supported platforms does not include namespaces to the dump by default
 
8077
            appendFile($HeaderPath, "\n  // add namespaces\n".$NS_Add);
 
8078
        }
 
8079
        # some GCC versions don't include class methods to the TU dump by default
 
8080
        my ($AddClass, $ClassNum) = ("", 0);
 
8081
        my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions
 
8082
        foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
 
8083
        {
 
8084
            next if($C_Structure{$CName});
 
8085
            next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
 
8086
            next if($SkipTypes{$Version}{$CName});
 
8087
            if(not $Force and $GCC_44
 
8088
            and $OSgroup eq "linux")
 
8089
            { # optimization for linux with GCC >= 4.4
 
8090
              # disable this code by -force option
 
8091
                if(index($CName, "::")!=-1)
 
8092
                { # should be added by name space
 
8093
                    next;
 
8094
                }
7220
8095
            }
7221
 
            # some GCC versions don't include class methods to the TU dump by default
7222
 
            my ($AddClass, $ClassNum) = ("", 0);
7223
 
            foreach my $CName (sort keys(%AddClasses))
 
8096
            else
7224
8097
            {
7225
 
                next if($C_Structure{$CName});
7226
 
                next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7227
 
                next if(($CName=~tr![:]!!)>2);
7228
 
                next if($SkipTypes{$Version}{$CName});
7229
8098
                if($CName=~/\A(.+)::[^:]+\Z/
7230
 
                and $AddClasses{$1}) {
 
8099
                and $TUnit_Classes{$Version}{$1})
 
8100
                { # classes inside other classes
7231
8101
                    next;
7232
8102
                }
7233
 
                $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
7234
 
            }
7235
 
            appendFile($MHeaderPath, "\n  // add classes\n".$AddClass);
 
8103
            }
 
8104
            if(defined $TUnit_Funcs{$Version}{$CName})
 
8105
            { # the same name for a function and type
 
8106
                next;
 
8107
            }
 
8108
            if(defined $TUnit_Vars{$Version}{$CName})
 
8109
            { # the same name for a variable and type
 
8110
                next;
 
8111
            }
 
8112
            $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
 
8113
        }
 
8114
        if($AddClass) {
 
8115
            appendFile($HeaderPath, "\n  // add classes\n".$AddClass);
7236
8116
        }
7237
8117
    }
7238
8118
    writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7239
8119
    # create TU dump
7240
8120
    my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7241
 
    if($C99Mode{$Version}==1
 
8121
    if($CppMode{$Version}==1
7242
8122
    or $MinGWMode{$Version}==1) {
7243
8123
        $TUdump .= " -fpreprocessed";
7244
8124
    }
7245
 
    my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
 
8125
    my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString);
7246
8126
    writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
7247
8127
    chdir($TMP_DIR);
7248
 
    system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
 
8128
    system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
 
8129
    my $Errors = "";
7249
8130
    if($?)
7250
8131
    { # failed to compile, but the TU dump still can be created
7251
 
        my $Errors = readFile($TMP_DIR."/tu_errors");
7252
 
        if($Errors=~/c99_/)
7253
 
        { # disable c99 mode
7254
 
            $C99Mode{$Version}=-1;
7255
 
            printMsg("INFO", "Disabling C99 compatibility mode");
7256
 
            resetLogging($Version);
7257
 
            $TMP_DIR = tempdir(CLEANUP=>1);
7258
 
            return getDump();
7259
 
        }
7260
 
        elsif($AutoPreambleMode{$Version}!=-1
7261
 
        and my $TErrors = $Errors)
7262
 
        {
7263
 
            my %Types = ();
7264
 
            while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7265
 
            { # error: 'FILE' has not been declared
7266
 
                $Types{$2}=1;
7267
 
            }
7268
 
            my %AddHeaders = ();
7269
 
            foreach my $Type (keys(%Types))
7270
 
            {
7271
 
                if(my $Header = $AutoPreamble{$Type}) {
7272
 
                    $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7273
 
                }
7274
 
            }
7275
 
            if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7276
 
            { # sys/types.h should be the first
 
8132
        if($Errors = readFile($TMP_DIR."/tu_errors"))
 
8133
        { # try to recompile
 
8134
          # FIXME: handle other errors and try to recompile
 
8135
            if($CppMode{$Version}==1
 
8136
            and index($Errors, "c99_")!=-1)
 
8137
            { # disable c99 mode and try again
 
8138
                $CppMode{$Version}=-1;
 
8139
                printMsg("INFO", "Disabling C++ compatibility mode");
 
8140
                resetLogging($Version);
 
8141
                $TMP_DIR = tempdir(CLEANUP=>1);
 
8142
                return getDump();
 
8143
            }
 
8144
            elsif($AutoPreambleMode{$Version}!=-1
 
8145
            and my $AddHeaders = detectPreamble($Errors, $Version))
 
8146
            { # add auto preamble headers and try again
 
8147
                $AutoPreambleMode{$Version}=-1;
 
8148
                my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
7277
8149
                foreach my $Num (0 .. $#Headers)
7278
8150
                {
7279
 
                    my $Name = $Headers[$Num];
7280
 
                    if(my $Path = identifyHeader($Name, $Version))
7281
 
                    { # add automatic preamble headers
7282
 
                        if(defined $Include_Preamble{$Version}{$Path})
7283
 
                        { # already added
7284
 
                            next;
7285
 
                        }
7286
 
                        $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7287
 
                        my $Type = $AddHeaders{$Name};
7288
 
                        printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
 
8151
                    my $Path = $Headers[$Num];
 
8152
                    if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}}))
 
8153
                    {
 
8154
                        push_U($Include_Preamble{$Version}, $Path);
 
8155
                        printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
7289
8156
                    }
7290
8157
                }
7291
 
                $AutoPreambleMode{$Version}=-1;
7292
 
                resetLogging($Version);
7293
 
                $TMP_DIR = tempdir(CLEANUP=>1);
7294
 
                return getDump();
7295
 
            }
7296
 
        }
7297
 
        elsif($MinGWMode{$Version}!=-1)
7298
 
        {
7299
 
            $MinGWMode{$Version}=-1;
7300
 
            resetLogging($Version);
7301
 
            $TMP_DIR = tempdir(CLEANUP=>1);
7302
 
            return getDump();
7303
 
        }
7304
 
        # FIXME: handle other errors and try to recompile
7305
 
        writeLog($Version, $Errors);
 
8158
                resetLogging($Version);
 
8159
                $TMP_DIR = tempdir(CLEANUP=>1);
 
8160
                return getDump();
 
8161
            }
 
8162
            elsif($Cpp0xMode{$Version}!=-1
 
8163
            and ($Errors=~/\Q-std=c++0x\E/
 
8164
            or $Errors=~/is not a class or namespace/))
 
8165
            { # c++0x: enum class
 
8166
                if(check_gcc($GCC_PATH, "4.6"))
 
8167
                {
 
8168
                    $Cpp0xMode{$Version}=-1;
 
8169
                    printMsg("INFO", "Enabling c++0x mode");
 
8170
                    resetLogging($Version);
 
8171
                    $TMP_DIR = tempdir(CLEANUP=>1);
 
8172
                    $CompilerOptions{$Version} .= " -std=c++0x";
 
8173
                    return getDump();
 
8174
                }
 
8175
                else {
 
8176
                    printMsg("WARNING", "Probably c++0x construction detected");
 
8177
                }
 
8178
                
 
8179
            }
 
8180
            elsif($MinGWMode{$Version}==1)
 
8181
            { # disable MinGW mode and try again
 
8182
                $MinGWMode{$Version}=-1;
 
8183
                resetLogging($Version);
 
8184
                $TMP_DIR = tempdir(CLEANUP=>1);
 
8185
                return getDump();
 
8186
            }
 
8187
            writeLog($Version, $Errors);
 
8188
        }
 
8189
        else {
 
8190
            writeLog($Version, "$!: $?\n");
 
8191
        }
7306
8192
        printMsg("ERROR", "some errors occurred when compiling headers");
7307
8193
        printErrorLog($Version);
7308
8194
        $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7309
 
        writeLog($Version, "\n");# new line
 
8195
        writeLog($Version, "\n"); # new line
7310
8196
    }
7311
8197
    chdir($ORIG_DIR);
7312
 
    unlink($TmpHeaderPath, $MHeaderPath);
7313
 
    return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
 
8198
    unlink($TmpHeaderPath);
 
8199
    unlink($HeaderPath);
 
8200
    
 
8201
    if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
 
8202
        return $TUs[0];
 
8203
    }
 
8204
    else
 
8205
    {
 
8206
        my $Msg = "can't compile header(s)";
 
8207
        if($Errors=~/error trying to exec \W+cc1plus\W+/) {
 
8208
            $Msg .= "\nDid you install G++?";
 
8209
        }
 
8210
        exitStatus("Cannot_Compile", $Msg);
 
8211
    }
7314
8212
}
7315
8213
 
7316
8214
sub cmd_file($)
7337
8235
sub getIncPaths(@)
7338
8236
{
7339
8237
    my @HeaderPaths = @_;
7340
 
    my @IncPaths = ();
 
8238
    my @IncPaths = @{$Add_Include_Paths{$Version}};
7341
8239
    if($INC_PATH_AUTODETECT{$Version})
7342
8240
    { # auto-detecting dependencies
7343
8241
        my %Includes = ();
7348
8246
                if($Skip_Include_Paths{$Version}{$Dir}) {
7349
8247
                    next;
7350
8248
                }
7351
 
                $Includes{$Dir}=1;
 
8249
                if($SystemRoot)
 
8250
                {
 
8251
                    if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
 
8252
                        next;
 
8253
                    }
 
8254
                }
 
8255
                $Includes{$Dir} = 1;
7352
8256
            }
7353
8257
        }
7354
 
        foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7355
 
        { # added by user
7356
 
            next if($Includes{$Dir});
7357
 
            push(@IncPaths, $Dir);
7358
 
        }
7359
8258
        foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7360
 
            push(@IncPaths, $Dir);
 
8259
            push_U(\@IncPaths, $Dir);
7361
8260
        }
7362
8261
    }
7363
8262
    else
7364
8263
    { # user-defined paths
7365
 
        foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7366
 
        sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7367
 
            push(@IncPaths, $Dir);
7368
 
        }
 
8264
        @IncPaths = @{$Include_Paths{$Version}};
7369
8265
    }
7370
8266
    return \@IncPaths;
7371
8267
}
7372
8268
 
 
8269
sub push_U($@)
 
8270
{ # push unique
 
8271
    if(my $Array = shift @_)
 
8272
    {
 
8273
        if(@_)
 
8274
        {
 
8275
            my %Exist = map {$_=>1} @{$Array};
 
8276
            foreach my $Elem (@_)
 
8277
            {
 
8278
                if(not defined $Exist{$Elem})
 
8279
                {
 
8280
                    push(@{$Array}, $Elem);
 
8281
                    $Exist{$Elem} = 1;
 
8282
                }
 
8283
            }
 
8284
        }
 
8285
    }
 
8286
}
 
8287
 
7373
8288
sub callPreprocessor($$$)
7374
8289
{
7375
8290
    my ($Path, $Inc, $LibVersion) = @_;
7379
8294
        $IncludeString = getIncString(getIncPaths($Path), "GCC");
7380
8295
    }
7381
8296
    my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
7382
 
    my $Out = $TMP_DIR."/preprocessed";
7383
 
    system($Cmd." >$Out 2>$TMP_DIR/null");
 
8297
    my $Out = $TMP_DIR."/preprocessed.h";
 
8298
    system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
7384
8299
    return $Out;
7385
8300
}
7386
8301
 
7387
 
sub cmd_find($$$$)
 
8302
sub cmd_find($;$$$$)
7388
8303
{ # native "find" is much faster than File::Find (~6x)
7389
8304
  # also the File::Find doesn't support --maxdepth N option
7390
8305
  # so using the cross-platform wrapper for the native one
7391
 
    my ($Path, $Type, $Name, $MaxDepth) = @_;
 
8306
    my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_;
7392
8307
    return () if(not $Path or not -e $Path);
7393
8308
    if($OSgroup eq "windows")
7394
8309
    {
7396
8311
        if(not $DirCmd) {
7397
8312
            exitStatus("Not_Found", "can't find \"dir\" command");
7398
8313
        }
7399
 
        $Path=~s/[\\]+\Z//;
7400
8314
        $Path = get_abs_path($Path);
7401
8315
        $Path = path_format($Path, $OSgroup);
7402
8316
        my $Cmd = $DirCmd." \"$Path\" /B /O";
7406
8320
        if($Type eq "d") {
7407
8321
            $Cmd .= " /AD";
7408
8322
        }
7409
 
        my @Files = ();
 
8323
        elsif($Type eq "f") {
 
8324
            $Cmd .= " /A-D";
 
8325
        }
 
8326
        my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
7410
8327
        if($Name)
7411
 
        { # FIXME: how to search file names in MS shell?
7412
 
            $Name=~s/\*/.*/g if($Name!~/\]/);
7413
 
            foreach my $File (split(/\n/, `$Cmd`))
7414
 
            {
7415
 
                if($File=~/$Name\Z/i) {
7416
 
                    push(@Files, $File);
7417
 
                }
 
8328
        {
 
8329
            if(not $UseRegex)
 
8330
            { # FIXME: how to search file names in MS shell?
 
8331
              # wildcard to regexp
 
8332
                $Name=~s/\*/.*/g;
 
8333
                $Name='\A'.$Name.'\Z';
7418
8334
            }
7419
 
        }
7420
 
        else {
7421
 
            @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
 
8335
            @Files = grep { /$Name/i } @Files;
7422
8336
        }
7423
8337
        my @AbsPaths = ();
7424
8338
        foreach my $File (@Files)
7425
8339
        {
7426
8340
            if(not is_abs($File)) {
7427
 
                $File = joinPath($Path, $File);
 
8341
                $File = join_P($Path, $File);
7428
8342
            }
7429
8343
            if($Type eq "f" and not -f $File)
7430
8344
            { # skip dirs
7456
8370
        if($Type) {
7457
8371
            $Cmd .= " -type $Type";
7458
8372
        }
7459
 
        if($Name)
7460
 
        { # file name
7461
 
            if($Name=~/\]/) {
7462
 
                $Cmd .= " -regex \"$Name\"";
7463
 
            }
7464
 
            else {
7465
 
                $Cmd .= " -name \"$Name\"";
7466
 
            }
7467
 
        }
7468
 
        return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
 
8373
        if($Name and not $UseRegex)
 
8374
        { # wildcards
 
8375
            $Cmd .= " -name \"$Name\"";
 
8376
        }
 
8377
        my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
 
8378
        if($? and $!) {
 
8379
            printMsg("ERROR", "problem with \'find\' utility ($?): $!");
 
8380
        }
 
8381
        my @Files = split(/\n/, $Res);
 
8382
        if($Name and $UseRegex)
 
8383
        { # regex
 
8384
            @Files = grep { /$Name/ } @Files;
 
8385
        }
 
8386
        return @Files;
7469
8387
    }
7470
8388
}
7471
8389
 
7486
8404
            exitStatus("Not_Found", "can't find \"unzip\" command");
7487
8405
        }
7488
8406
        chdir($UnpackDir);
7489
 
        system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
 
8407
        system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\"");
7490
8408
        if($?) {
7491
 
            exitStatus("Error", "can't extract \'$Path\'");
 
8409
            exitStatus("Error", "can't extract \'$Path\' ($?): $!");
7492
8410
        }
7493
8411
        chdir($ORIG_DIR);
7494
 
        my @Contents = ();
7495
 
        foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7496
 
        {
7497
 
            if(/inflating:\s*([^\s]+)/) {
7498
 
                push(@Contents, $1);
7499
 
            }
7500
 
        }
 
8412
        my @Contents = cmd_find($UnpackDir, "f");
7501
8413
        if(not @Contents) {
7502
8414
            exitStatus("Error", "can't extract \'$Path\'");
7503
8415
        }
7504
 
        return joinPath($UnpackDir, $Contents[0]);
 
8416
        return $Contents[0];
7505
8417
    }
7506
 
    elsif($FileName=~s/\Q.tar.gz\E\Z//g)
 
8418
    elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g)
7507
8419
    { # *.tar.gz
7508
8420
        if($OSgroup eq "windows")
7509
8421
        { # -xvzf option is not implemented in tar.exe (2003)
7517
8429
                exitStatus("Not_Found", "can't find \"gzip\" command");
7518
8430
            }
7519
8431
            chdir($UnpackDir);
7520
 
            system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
 
8432
            system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
7521
8433
            if($?) {
7522
8434
                exitStatus("Error", "can't extract \'$Path\'");
7523
8435
            }
7524
 
            system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
 
8436
            system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\"");
7525
8437
            if($?) {
7526
 
                exitStatus("Error", "can't extract \'$Path\'");
 
8438
                exitStatus("Error", "can't extract \'$Path\' ($?): $!");
7527
8439
            }
7528
8440
            chdir($ORIG_DIR);
7529
8441
            unlink($Dir."/".$FileName.".tar");
7530
 
            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
 
8442
            my @Contents = cmd_find($UnpackDir, "f");
7531
8443
            if(not @Contents) {
7532
8444
                exitStatus("Error", "can't extract \'$Path\'");
7533
8445
            }
7534
 
            return joinPath($UnpackDir, $Contents[0]);
 
8446
            return $Contents[0];
7535
8447
        }
7536
8448
        else
7537
 
        { # Unix
 
8449
        { # Unix, Mac
7538
8450
            my $TarCmd = get_CmdPath("tar");
7539
8451
            if(not $TarCmd) {
7540
8452
                exitStatus("Not_Found", "can't find \"tar\" command");
7541
8453
            }
7542
8454
            chdir($UnpackDir);
7543
 
            system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
 
8455
            system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\"");
7544
8456
            if($?) {
7545
 
                exitStatus("Error", "can't extract \'$Path\'");
 
8457
                exitStatus("Error", "can't extract \'$Path\' ($?): $!");
7546
8458
            }
7547
8459
            chdir($ORIG_DIR);
7548
 
            # The content file name may be different
7549
 
            # from the package file name
7550
 
            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
 
8460
            my @Contents = cmd_find($UnpackDir, "f");
7551
8461
            if(not @Contents) {
7552
8462
                exitStatus("Error", "can't extract \'$Path\'");
7553
8463
            }
7554
 
            return joinPath($UnpackDir, $Contents[0]);
 
8464
            return $Contents[0];
7555
8465
        }
7556
8466
    }
7557
8467
}
7559
8469
sub createArchive($$)
7560
8470
{
7561
8471
    my ($Path, $To) = @_;
 
8472
    if(not $To) {
 
8473
        $To = ".";
 
8474
    }
7562
8475
    if(not $Path or not -e $Path
7563
8476
    or not -d $To) {
7564
8477
        return "";
7573
8486
        my $Pkg = $To."/".$Name.".zip";
7574
8487
        unlink($Pkg);
7575
8488
        chdir($To);
7576
 
        system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
 
8489
        system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
7577
8490
        if($?)
7578
8491
        { # cannot allocate memory (or other problems with "zip")
7579
8492
            unlink($Path);
7665
8578
        }
7666
8579
        else
7667
8580
        {
7668
 
            if($Header=~/\/include\//
 
8581
            if(index($Header, "/include/")!=-1
7669
8582
            or cmd_file($Header)=~/C[\+]*\s+program/i)
7670
8583
            { # !~/HTML|XML|shared|dynamic/i
7671
8584
                return $Header;
7682
8595
    {
7683
8596
        my $RegDir = get_dirname($RegHeader);
7684
8597
        $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
 
8598
        
 
8599
        if(not $INC_PATH_AUTODETECT{$LibVersion}) {
 
8600
            detect_recursive_includes($RegHeader, $LibVersion);
 
8601
        }
 
8602
        
7685
8603
        foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7686
8604
        {
7687
8605
            my $Dir = get_dirname($RecInc);
7688
 
            if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
 
8606
            
 
8607
            if(familiarDirs($Dir, $RegDir) 
7689
8608
            or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7690
8609
            { # in the same directory or included by #include "..."
7691
8610
                $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7694
8613
    }
7695
8614
}
7696
8615
 
 
8616
sub familiarDirs($$)
 
8617
{
 
8618
    my ($D1, $D2) = @_;
 
8619
    if($D1 eq $D2) {
 
8620
        return 1;
 
8621
    }
 
8622
    while($D1=~s/[\/\\]+.*?\Z//)
 
8623
    {
 
8624
        $D2=~s/[\/\\]+.*?\Z//;
 
8625
        if($D1 eq "/usr/include") {
 
8626
            return 0;
 
8627
        }
 
8628
        if($D1 eq $D2) {
 
8629
            return 1;
 
8630
        }
 
8631
    }
 
8632
    return 0;
 
8633
}
 
8634
 
7697
8635
sub readHeaders($)
7698
8636
{
7699
8637
    $Version = $_[0];
7700
8638
    printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7701
8639
    my $DumpPath = getDump();
7702
 
    if(not $DumpPath) {
7703
 
        exitStatus("Cannot_Compile", "can't compile header(s)");
7704
 
    }
7705
8640
    if($Debug)
7706
8641
    { # debug mode
7707
8642
        mkpath($DEBUG_PATH{$Version});
7737
8672
      # V >= 2.5: array size in bytes
7738
8673
        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7739
8674
        {
7740
 
            my %Type = get_PureType($TypeId, $LibVersion);
 
8675
            my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
7741
8676
            if($Type{"Type"} eq "Array")
7742
8677
            {
7743
 
                if($Type{"Size"})
 
8678
                if(my $Size = $Type{"Size"})
7744
8679
                { # array[N]
7745
 
                    my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7746
 
                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
 
8680
                    my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
 
8681
                    $Size *= $Base{"Size"};
 
8682
                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
7747
8683
                }
7748
8684
                else
7749
8685
                { # array[] is a pointer
7758
8694
      # size of "method ptr" corrected in 2.7
7759
8695
        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7760
8696
        {
7761
 
            my %PureType = get_PureType($TypeId, $LibVersion);
 
8697
            my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
7762
8698
            if($PureType{"Type"} eq "MethodPtr")
7763
8699
            {
7764
8700
                my %Type = get_Type($TypeId, $LibVersion);
7852
8788
        my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
7853
8789
        my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
7854
8790
        
7855
 
        if(not $MnglName)
7856
 
        { # ABI dumps have no mangled names for C-functions
7857
 
            $MnglName = $ShortName;
7858
 
            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7859
 
        }
7860
 
        
7861
8791
        my $SRemangle = 0;
7862
8792
        if(not checkDump(1, "2.12")
7863
8793
        or not checkDump(2, "2.12"))
7880
8810
                }
7881
8811
            }
7882
8812
        }
 
8813
        if(not $CheckHeadersOnly)
 
8814
        { # support for old ABI dumps
 
8815
            if(not checkDump(1, "2.17")
 
8816
            or not checkDump(2, "2.17"))
 
8817
            {
 
8818
                if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
 
8819
                {
 
8820
                    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
 
8821
                    {
 
8822
                        if(link_symbol($ShortName, $LibVersion, "-Deps"))
 
8823
                        {
 
8824
                            $MnglName = $ShortName;
 
8825
                            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
 
8826
                        }
 
8827
                    }
 
8828
                }
 
8829
            }
 
8830
        }
7883
8831
        if($Remangle==1 or $SRemangle==1)
7884
8832
        { # support for old ABI dumps: some symbols are not mangled in old dumps
7885
8833
          # mangle both sets of symbols (old and new)
7931
8879
            %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7932
8880
        }
7933
8881
        
 
8882
        if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"})
 
8883
        {
 
8884
            %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
 
8885
            if($SymVer{$LibVersion}{$Alias}) {
 
8886
                %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
 
8887
            }
 
8888
        }
 
8889
        
7934
8890
        # clean memory
7935
8891
        delete($SymbolInfo{$LibVersion}{$InfoId});
7936
8892
    }
7948
8904
    foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
7949
8905
    { # detect allocable classes with public exported constructors
7950
8906
      # or classes with auto-generated or inline-only constructors
 
8907
      # and other temp info
7951
8908
        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
7952
8909
        {
7953
8910
            my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
8019
8976
                }
8020
8977
            }
8021
8978
        }
 
8979
        
 
8980
        # mapping {short name => symbols}
 
8981
        $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
8022
8982
    }
8023
8983
    foreach my $MnglName (keys(%VTableClass))
8024
 
    { # reconstruct header name for v-tables
8025
 
        if($MnglName=~/\A_ZTV/)
 
8984
    { # reconstruct attributes of v-tables
 
8985
        if(index($MnglName, "_ZTV")==0)
8026
8986
        {
8027
8987
            if(my $ClassName = $VTableClass{$MnglName})
8028
8988
            {
8029
 
                if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
 
8989
                if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
 
8990
                {
8030
8991
                    $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
 
8992
                    $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId;
8031
8993
                }
8032
8994
            }
8033
8995
        }
8109
9071
        elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
8110
9072
        {
8111
9073
            $UsedType{$LibVersion}{$TypeId} = 1;
8112
 
            register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
 
9074
            register_TypeUsage($TInfo{"BaseType"}, $LibVersion);
8113
9075
            return 1;
8114
9076
        }
8115
9077
        elsif($TInfo{"Type"} eq "Intrinsic")
8122
9084
}
8123
9085
 
8124
9086
sub selectSymbol($$$$)
8125
 
{
 
9087
{ # select symbol to check or to dump
8126
9088
    my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8127
9089
    
 
9090
    if($Level eq "Dump")
 
9091
    {
 
9092
        if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
 
9093
        { # TODO: check if this symbol is from
 
9094
          # base classes of other target symbols
 
9095
            return 1;
 
9096
        }
 
9097
    }
 
9098
    
8128
9099
    if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8129
9100
    { # stdc++ interfaces
8130
9101
        return 0;
8134
9105
    if(my $Header = $SInfo->{"Header"}) {
8135
9106
        $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8136
9107
    }
 
9108
    if($ExtendedCheck)
 
9109
    {
 
9110
        if(index($Symbol, "external_func_")==0) {
 
9111
            $Target = 1;
 
9112
        }
 
9113
    }
8137
9114
    if($CheckHeadersOnly)
8138
9115
    {
8139
9116
        if($Target)
8171
9148
        }
8172
9149
        if($Level eq "Dump")
8173
9150
        { # dumped
8174
 
            if(not $BinaryOnly)
 
9151
            if($BinaryOnly)
 
9152
            {
 
9153
                if($SInfo->{"Data"})
 
9154
                {
 
9155
                    if($Target) {
 
9156
                        return 1;
 
9157
                    }
 
9158
                }
 
9159
            }
 
9160
            else
8175
9161
            { # SrcBin
8176
9162
                if($Target) {
8177
9163
                    return 1;
8178
9164
                }
8179
9165
            }
8180
 
            if($SInfo->{"Data"})
8181
 
            {
8182
 
                if($Target) {
8183
 
                    return 1;
8184
 
                }
8185
 
            }
8186
9166
        }
8187
9167
        elsif($Level eq "Source")
8188
9168
        { # checked
8189
 
            if($Target) {
8190
 
                return 1;
 
9169
            if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
 
9170
            or isInLineInst($Symbol, $SInfo, $LibVersion))
 
9171
            { # skip LOCAL symbols
 
9172
                if($Target) {
 
9173
                    return 1;
 
9174
                }
8191
9175
            }
8192
9176
        }
8193
9177
        elsif($Level eq "Binary")
8225
9209
        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8226
9210
            delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8227
9211
        }
 
9212
        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
 
9213
            delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
 
9214
        }
8228
9215
    }
8229
9216
    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8230
9217
    {
 
9218
        delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
8231
9219
        foreach my $Attr ("Header", "Line", "Size", "NameSpace")
8232
9220
        {
8233
9221
            if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8234
9222
                delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8235
9223
            }
8236
9224
        }
 
9225
        if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
 
9226
            delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
 
9227
        }
8237
9228
    }
8238
9229
}
8239
9230
 
8240
9231
sub selectType($$)
8241
9232
{
8242
9233
    my ($Tid, $LibVersion) = @_;
 
9234
    
 
9235
    if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
 
9236
    {
 
9237
        if(defined $TypeInfo{$LibVersion}{$Dupl})
 
9238
        {
 
9239
            if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
 
9240
            { # duplicate
 
9241
                return 0;
 
9242
            }
 
9243
        }
 
9244
    }
 
9245
    
8243
9246
    if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8244
9247
    {
8245
9248
        if(not isBuiltIn($THeader))
8277
9280
            { # register "this" pointer
8278
9281
                $UsedType{$LibVersion}{$ThisId} = 1;
8279
9282
                if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8280
 
                    register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
 
9283
                    register_TypeUsage($ThisType{"BaseType"}, $LibVersion);
8281
9284
                }
8282
9285
            }
8283
9286
        }
8298
9301
    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8299
9302
    {
8300
9303
        if($UsedType{$LibVersion}{$Tid})
8301
 
        { # All & Derived
 
9304
        { # All & Extended
8302
9305
            next;
8303
9306
        }
8304
9307
        
8305
 
        if($Kind eq "Derived")
 
9308
        if($Kind eq "Extended")
8306
9309
        {
8307
9310
            if(selectType($Tid, $LibVersion)) {
8308
9311
                register_TypeUsage($Tid, $LibVersion);
8312
9315
    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8313
9316
    { # remove unused types
8314
9317
        if($UsedType{$LibVersion}{$Tid})
8315
 
        { # All & Derived
 
9318
        { # All & Extended
8316
9319
            next;
8317
9320
        }
8318
9321
        # remove type
8329
9332
    my %Type = get_Type($TypeId, $LibVersion);
8330
9333
    if($Type{"Type"} eq "Typedef")
8331
9334
    {
8332
 
        my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
 
9335
        my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
8333
9336
        if($Base{"Type"}=~/Class|Struct/)
8334
9337
        {
8335
9338
            if($Type{"Name"} eq $Base{"Name"}) {
8350
9353
sub addExtension($)
8351
9354
{
8352
9355
    my $LibVersion = $_[0];
8353
 
    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
 
9356
    foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
8354
9357
    {
8355
9358
        if(selectType($Tid, $LibVersion))
8356
9359
        {
8357
 
            my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
 
9360
            my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"};
 
9361
            $TName=~s/\A(struct|union|class|enum) //;
 
9362
            my $Symbol = "external_func_".$TName;
8358
9363
            
8359
9364
            %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8360
9365
                "Header" => "extended.h",
8363
9368
                "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8364
9369
            );
8365
9370
            
8366
 
            $ExtendedSymbols{$Symbol}=1;
8367
 
            $CheckedSymbols{"Binary"}{$Symbol}=1;
8368
 
            $CheckedSymbols{"Source"}{$Symbol}=1;
 
9371
            $ExtendedSymbols{$Symbol} = 1;
 
9372
            $CheckedSymbols{"Binary"}{$Symbol} = 1;
 
9373
            $CheckedSymbols{"Source"}{$Symbol} = 1;
8369
9374
        }
8370
9375
    }
8371
 
    $ExtendedSymbols{"external_func_0"}=1;
8372
 
    $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8373
 
    $CheckedSymbols{"Source"}{"external_func_0"}=1;
 
9376
    $ExtendedSymbols{"external_func_0"} = 1;
 
9377
    $CheckedSymbols{"Binary"}{"external_func_0"} = 1;
 
9378
    $CheckedSymbols{"Source"}{"external_func_0"} = 1;
8374
9379
}
8375
9380
 
8376
9381
sub findMethod($$$)
8399
9404
    { # search for interface with the same parameters suffix (overridden)
8400
9405
        if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8401
9406
        {
8402
 
            if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
 
9407
            if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
 
9408
            {
8403
9409
                if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8404
9410
                {
8405
9411
                    if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8409
9415
                    }
8410
9416
                }
8411
9417
            }
8412
 
            else {
 
9418
            else
 
9419
            {
8413
9420
                if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8414
9421
                    return $Candidate;
8415
9422
                }
8479
9486
    my $LibVersion = $_[0];
8480
9487
    foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8481
9488
    {
8482
 
        my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8483
 
        foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8484
 
        sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
 
9489
        my ($Num, $Rel) = (1, 0);
 
9490
        
 
9491
        if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8485
9492
        {
8486
 
            $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8487
 
            
8488
 
            # set relative positions
8489
 
            if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8490
 
            and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8491
 
            { # relative position excluding added and removed virtual functions
8492
 
                if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8493
 
                and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
8494
 
                    $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
 
9493
            if($UsedDump{$LibVersion}{"DWARF"}) {
 
9494
                @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs;
 
9495
            }
 
9496
            else {
 
9497
                @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs;
 
9498
            }
 
9499
            foreach my $VirtFunc (@Funcs)
 
9500
            {
 
9501
                if($UsedDump{$LibVersion}{"DWARF"}) {
 
9502
                    $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"};
 
9503
                }
 
9504
                else {
 
9505
                    $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++;
 
9506
                }
 
9507
                
 
9508
                # set relative positions
 
9509
                if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
 
9510
                and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
 
9511
                { # relative position excluding added and removed virtual functions
 
9512
                    if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
 
9513
                    and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
 
9514
                        $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++;
 
9515
                    }
8495
9516
                }
8496
9517
            }
8497
9518
        }
8500
9521
    {
8501
9522
        my $AbsNum = 1;
8502
9523
        foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8503
 
            $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
 
9524
            $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++;
8504
9525
        }
8505
9526
    }
8506
9527
}
8554
9575
        {
8555
9576
            if(defined $VirtualTable{$LibVersion}{$BName})
8556
9577
            {
8557
 
                my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8558
 
                @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8559
 
                foreach my $VFunc (@VFunctions) {
 
9578
                my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}});
 
9579
                if($UsedDump{$LibVersion}{"DWARF"}) {
 
9580
                    @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs;
 
9581
                }
 
9582
                else {
 
9583
                    @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs;
 
9584
                }
 
9585
                foreach my $VFunc (@VFuncs) {
8560
9586
                    push(@Elements, $VFunc);
8561
9587
                }
8562
9588
            }
8666
9692
    return 0;
8667
9693
}
8668
9694
 
8669
 
sub getAlignment($$$)
8670
 
{
8671
 
    my ($Pos, $TypePtr, $LibVersion) = @_;
8672
 
    my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
8673
 
    my %Type = get_PureType($Tid, $LibVersion);
8674
 
    my $TSize = $Type{"Size"}*$BYTE_SIZE;
8675
 
    my $MSize = $Type{"Size"}*$BYTE_SIZE;
8676
 
    if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8677
 
    { # bitfields
8678
 
        ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8679
 
    }
8680
 
    elsif($Type{"Type"} eq "Array")
8681
 
    { # in the context of function parameter
8682
 
      # it's passed through the pointer
8683
 
    }
8684
 
    # alignment
8685
 
    my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8686
 
    if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8687
 
    { # computed by GCC
8688
 
        $Alignment = $Computed*$BYTE_SIZE;
8689
 
    }
8690
 
    elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8691
 
    { # bitfields are 1 bit aligned
8692
 
        $Alignment = 1;
8693
 
    }
8694
 
    elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8695
 
    { # model
8696
 
        $Alignment = $TSize;
8697
 
    }
8698
 
    return ($Alignment, $MSize);
8699
 
}
8700
 
 
8701
 
sub getOffset($$$)
8702
 
{ # offset of the field including padding
8703
 
    my ($FieldPos, $TypePtr, $LibVersion) = @_;
8704
 
    my $Offset = 0;
8705
 
    foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8706
 
    {
8707
 
        my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8708
 
        # padding
8709
 
        my $Padding = 0;
8710
 
        if($Offset % $Alignment!=0)
8711
 
        { # not aligned, add padding
8712
 
            $Padding = $Alignment - $Offset % $Alignment;
8713
 
        }
8714
 
        $Offset += $Padding;
8715
 
        if($Pos==$FieldPos)
8716
 
        { # after the padding
8717
 
          # before the field
8718
 
            return $Offset;
8719
 
        }
8720
 
        $Offset += $MSize;
8721
 
    }
8722
 
    return $FieldPos;# if something is going wrong
8723
 
}
8724
 
 
8725
 
sub isMemPadded($$$$$)
8726
 
{ # check if the target field can be added/removed/changed
8727
 
  # without shifting other fields because of padding bits
8728
 
    my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8729
 
    return 0 if($FieldPos==0);
8730
 
    if(defined $TypePtr->{"Memb"}{""})
8731
 
    {
8732
 
        delete($TypePtr->{"Memb"}{""});
8733
 
        if($Debug) {
8734
 
            printMsg("WARNING", "internal error detected");
8735
 
        }
8736
 
    }
8737
 
    my $Offset = 0;
8738
 
    my (%Alignment, %MSize) = ();
8739
 
    my $MaxAlgn = 0;
8740
 
    my $End = keys(%{$TypePtr->{"Memb"}})-1;
8741
 
    my $NextField = $FieldPos+1;
8742
 
    foreach my $Pos (0 .. $End)
8743
 
    {
8744
 
        if($Skip and $Skip->{$Pos})
8745
 
        { # skip removed/added fields
8746
 
            if($Pos > $FieldPos)
8747
 
            { # after the target
8748
 
                $NextField += 1;
8749
 
                next;
8750
 
            }
8751
 
        }
8752
 
        ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8753
 
        if($Alignment{$Pos}>$MaxAlgn) {
8754
 
            $MaxAlgn = $Alignment{$Pos};
8755
 
        }
8756
 
        if($Pos==$FieldPos)
8757
 
        {
8758
 
            if($Size==-1)
8759
 
            { # added/removed fields
8760
 
                if($Pos!=$End)
8761
 
                { # skip target field and see
8762
 
                  # if enough padding will be
8763
 
                  # created on the next step
8764
 
                  # to include this field
8765
 
                    next;
8766
 
                }
8767
 
            }
8768
 
        }
8769
 
        # padding
8770
 
        my $Padding = 0;
8771
 
        if($Offset % $Alignment{$Pos}!=0)
8772
 
        { # not aligned, add padding
8773
 
            $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8774
 
        }
8775
 
        if($Pos==$NextField)
8776
 
        { # try to place target field in the padding
8777
 
            if($Size==-1)
8778
 
            { # added/removed fields
8779
 
                my $TPadding = 0;
8780
 
                if($Offset % $Alignment{$FieldPos}!=0)
8781
 
                {# padding of the target field
8782
 
                    $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8783
 
                }
8784
 
                if($TPadding+$MSize{$FieldPos}<=$Padding)
8785
 
                { # enough padding to place target field
8786
 
                    return 1;
8787
 
                }
8788
 
                else {
8789
 
                    return 0;
8790
 
                }
8791
 
            }
8792
 
            else
8793
 
            { # changed fields
8794
 
                my $Delta = $Size-$MSize{$FieldPos};
8795
 
                if($Delta>=0)
8796
 
                { # increased
8797
 
                    if($Size-$MSize{$FieldPos}<=$Padding)
8798
 
                    { # enough padding to change target field
8799
 
                        return 1;
8800
 
                    }
8801
 
                    else {
8802
 
                        return 0;
8803
 
                    }
8804
 
                }
8805
 
                else
8806
 
                { # decreased
8807
 
                    $Delta = abs($Delta);
8808
 
                    if($Delta+$Padding>=$MSize{$Pos})
8809
 
                    { # try to place the next field
8810
 
                        if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8811
 
                        { # padding of the next field in new place
8812
 
                            my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8813
 
                            if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8814
 
                            { # enough delta+padding to store next field
8815
 
                                return 0;
8816
 
                            }
8817
 
                        }
8818
 
                        else
8819
 
                        {
8820
 
                            return 0;
8821
 
                        }
8822
 
                    }
8823
 
                    return 1;
8824
 
                }
8825
 
            }
8826
 
        }
8827
 
        elsif($Pos==$End)
8828
 
        { # target field is the last field
8829
 
            if($Size==-1)
8830
 
            { # added/removed fields
8831
 
                if($Offset % $MaxAlgn!=0)
8832
 
                { # tail padding
8833
 
                    my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8834
 
                    if($Padding+$MSize{$Pos}<=$TailPadding)
8835
 
                    { # enough tail padding to place the last field
8836
 
                        return 1;
8837
 
                    }
8838
 
                }
8839
 
                return 0;
8840
 
            }
8841
 
            else
8842
 
            { # changed fields
8843
 
                # scenario #1
8844
 
                my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8845
 
                if($Offset1 % $MaxAlgn != 0)
8846
 
                { # tail padding
8847
 
                    $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8848
 
                }
8849
 
                # scenario #2
8850
 
                my $Offset2 = $Offset+$Padding+$Size;
8851
 
                if($Offset2 % $MaxAlgn != 0)
8852
 
                { # tail padding
8853
 
                    $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8854
 
                }
8855
 
                if($Offset1!=$Offset2)
8856
 
                { # different sizes of structure
8857
 
                    return 0;
8858
 
                }
8859
 
                return 1;
8860
 
            }
8861
 
        }
8862
 
        $Offset += $Padding+$MSize{$Pos};
8863
 
    }
8864
 
    return 0;
8865
 
}
8866
 
 
8867
9695
sub isReserved($)
8868
9696
{ # reserved fields == private
8869
9697
    my $MName = $_[0];
8870
9698
    if($MName=~/reserved|padding|f_spare/i) {
8871
9699
        return 1;
8872
9700
    }
8873
 
    if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
 
9701
    if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
8874
9702
        return 1;
8875
9703
    }
8876
9704
    if($MName=~/(pad\d+)/i) {
9017
9845
            {
9018
9846
                %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
9019
9847
                    "Type_Name"=>$ClassName,
9020
 
                    "Type_Type"=>"Class",
9021
9848
                    "Target"=>$ClassName);
9022
9849
            }
9023
9850
        }
9094
9921
                            next;
9095
9922
                        }
9096
9923
                        $ProblemType = "Pure_Virtual_Replacement";
9097
 
                        @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
 
9924
                        
 
9925
                        # affected all methods (both virtual and non-virtual ones)
 
9926
                        @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
 
9927
                        push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
9098
9928
                    }
 
9929
                    $VTableChanged_M{$ClassName}=1;
9099
9930
                    foreach my $AffectedInt (@Affected)
9100
9931
                    {
9101
9932
                        if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9102
9933
                        { # affected exported methods only
9103
9934
                            next;
9104
9935
                        }
 
9936
                        if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
 
9937
                            next;
 
9938
                        }
9105
9939
                        %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9106
9940
                            "Type_Name"=>$Class_Type{"Name"},
9107
 
                            "Type_Type"=>"Class",
9108
9941
                            "Target"=>get_Signature($AddedVFunc, 2),
9109
9942
                            "Old_Value"=>get_Signature($RemovedVFunc, 1));
9110
9943
                    }
9115
9948
    if(not checkDump(1, "2.0")
9116
9949
    or not checkDump(2, "2.0"))
9117
9950
    { # support for old ABI dumps
9118
 
      # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
 
9951
      # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
9119
9952
        return;
9120
9953
    }
9121
9954
    foreach my $ClassName (sort keys(%{$ClassNames{1}}))
9144
9977
            }
9145
9978
            if($Level eq "Source")
9146
9979
            {
9147
 
                %Class_New = get_PureType($ClassId_New, 2);
 
9980
                %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
9148
9981
                if($Class_New{"Type"}!~/Class|Struct/) {
9149
9982
                    next;
9150
9983
                }
9153
9986
        }
9154
9987
        my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9155
9988
        my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
 
9989
        
 
9990
        my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
 
9991
        my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
 
9992
        
9156
9993
        my ($BNum1, $BNum2) = (1, 1);
9157
 
        my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9158
 
        my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
9159
 
        my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9160
 
        my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
 
9994
        my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
 
9995
        my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
 
9996
        my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old;
 
9997
        my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New;
9161
9998
        my $Shift_Old = getShift($ClassId_Old, 1);
9162
9999
        my $Shift_New = getShift($ClassId_New, 2);
9163
 
        my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
 
10000
        my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
9164
10001
        my ($Added, $Removed) = (0, 0);
9165
10002
        my @StableBases_Old = ();
9166
10003
        foreach my $BaseId (@Bases_Old)
9167
10004
        {
9168
10005
            my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
9169
 
            if($BasePos_New{$BaseName}) {
 
10006
            if($BasePos_New{$Tr_Old{$BaseName}}) {
9170
10007
                push(@StableBases_Old, $BaseId);
9171
10008
            }
9172
 
            elsif(not $ShortBase_New{$BaseName}
9173
 
            and not $ShortBase_New{get_ShortType($BaseId, 1)})
 
10009
            elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
 
10010
            and not $ShortBase_New{get_ShortClass($BaseId, 1)})
9174
10011
            { # removed base
9175
10012
              # excluding namespace::SomeClass to SomeClass renaming
9176
10013
                my $ProblemKind = "Removed_Base_Class";
9195
10032
                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
9196
10033
                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9197
10034
                {
9198
 
                    my $SubName = $TypeInfo{1}{$SubId}{"Name"};
9199
 
                    push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9200
 
                    if($ProblemKind=~/VTable/) {
9201
 
                        $VTableChanged_M{$SubName}=1;
 
10035
                    if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
 
10036
                    {
 
10037
                        push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
 
10038
                        if($ProblemKind=~/VTable/) {
 
10039
                            $VTableChanged_M{$SubName}=1;
 
10040
                        }
9202
10041
                    }
9203
10042
                }
9204
10043
                foreach my $Interface (@Affected)
9205
10044
                {
 
10045
                    if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10046
                        next;
 
10047
                    }
9206
10048
                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
9207
10049
                        "Type_Name"=>$ClassName,
9208
 
                        "Type_Type"=>"Class",
9209
10050
                        "Target"=>$BaseName,
9210
10051
                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9211
10052
                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9218
10059
        foreach my $BaseId (@Bases_New)
9219
10060
        {
9220
10061
            my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
9221
 
            if($BasePos_Old{$BaseName}) {
 
10062
            if($BasePos_Old{$Tr_New{$BaseName}}) {
9222
10063
                push(@StableBases_New, $BaseId);
9223
10064
            }
9224
 
            elsif(not $ShortBase_Old{$BaseName}
9225
 
            and not $ShortBase_Old{get_ShortType($BaseId, 2)})
 
10065
            elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
 
10066
            and not $ShortBase_Old{get_ShortClass($BaseId, 2)})
9226
10067
            { # added base
9227
10068
              # excluding namespace::SomeClass to SomeClass renaming
9228
10069
                my $ProblemKind = "Added_Base_Class";
9247
10088
                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
9248
10089
                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9249
10090
                {
9250
 
                    my $SubName = $TypeInfo{1}{$SubId}{"Name"};
9251
 
                    push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9252
 
                    if($ProblemKind=~/VTable/) {
9253
 
                        $VTableChanged_M{$SubName}=1;
 
10091
                    if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
 
10092
                    {
 
10093
                        push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
 
10094
                        if($ProblemKind=~/VTable/) {
 
10095
                            $VTableChanged_M{$SubName}=1;
 
10096
                        }
9254
10097
                    }
9255
10098
                }
9256
10099
                foreach my $Interface (@Affected)
9257
10100
                {
 
10101
                    if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10102
                        next;
 
10103
                    }
9258
10104
                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
9259
10105
                        "Type_Name"=>$ClassName,
9260
 
                        "Type_Type"=>"Class",
9261
10106
                        "Target"=>$BaseName,
9262
10107
                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9263
10108
                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9269
10114
        if($Level eq "Binary")
9270
10115
        { # Binary-level
9271
10116
            ($BNum1, $BNum2) = (1, 1);
9272
 
            my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9273
 
            my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
 
10117
            my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
 
10118
            my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
9274
10119
            foreach my $BaseId (@Bases_Old)
9275
10120
            {
9276
10121
                my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
9277
 
                if(my $NewPos = $BaseRelPos_New{$BaseName})
 
10122
                if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
9278
10123
                {
9279
 
                    my $BaseNewId = $BaseId_New{$BaseName};
9280
 
                    my $OldPos = $BaseRelPos_Old{$BaseName};
 
10124
                    my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
 
10125
                    my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
9281
10126
                    if($NewPos!=$OldPos)
9282
10127
                    { # changed position of the base class
9283
10128
                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9284
10129
                        {
 
10130
                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10131
                                next;
 
10132
                            }
9285
10133
                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9286
10134
                                "Type_Name"=>$ClassName,
9287
 
                                "Type_Type"=>"Class",
9288
10135
                                "Target"=>$BaseName,
9289
10136
                                "Old_Value"=>$OldPos-1,
9290
10137
                                "New_Value"=>$NewPos-1  );
9295
10142
                    { # became non-virtual base
9296
10143
                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9297
10144
                        {
 
10145
                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10146
                                next;
 
10147
                            }
9298
10148
                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9299
10149
                                "Type_Name"=>$ClassName,
9300
 
                                "Type_Type"=>"Class",
9301
10150
                                "Target"=>$BaseName  );
9302
10151
                        }
9303
10152
                    }
9306
10155
                    { # became virtual base
9307
10156
                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9308
10157
                        {
 
10158
                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10159
                                next;
 
10160
                            }
9309
10161
                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9310
10162
                                "Type_Name"=>$ClassName,
9311
 
                                "Type_Type"=>"Class",
9312
10163
                                "Target"=>$BaseName  );
9313
10164
                        }
9314
10165
                    }
9321
10172
                { # search for changed base
9322
10173
                    my %BaseType = get_Type($BaseId, 1);
9323
10174
                    my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9324
 
                    my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
 
10175
                    my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
9325
10176
                    if($Size_Old ne $Size_New
9326
10177
                    and $Size_Old and $Size_New)
9327
10178
                    {
9347
10198
                        next if(not $ProblemType);
9348
10199
                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9349
10200
                        { # base class size changes affecting current class
 
10201
                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
 
10202
                                next;
 
10203
                            }
9350
10204
                            %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9351
10205
                                "Type_Name"=>$BaseType{"Name"},
9352
 
                                "Type_Type"=>"Class",
9353
10206
                                "Target"=>$BaseType{"Name"},
9354
10207
                                "Old_Size"=>$Size_Old*$BYTE_SIZE,
9355
10208
                                "New_Size"=>$Size_New*$BYTE_SIZE  );
9357
10210
                    }
9358
10211
                }
9359
10212
            }
9360
 
            if(defined $VirtualTable{1}{$ClassName}
 
10213
            if(defined $VirtualTable_Model{1}{$ClassName}
9361
10214
            and cmpVTables_Real($ClassName, 1)==1
9362
 
            and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
 
10215
            and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
9363
10216
            { # compare virtual tables size in base classes
9364
10217
                my $VShift_Old = getVShift($ClassId_Old, 1);
9365
10218
                my $VShift_New = getVShift($ClassId_New, 2);
9368
10221
                    my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9369
10222
                    my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9370
10223
                    ($BNum1, $BNum2) = (1, 1);
9371
 
                    my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
 
10224
                    my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
9372
10225
                    foreach my $BaseId (@AllBases_Old)
9373
10226
                    {
9374
10227
                        my %BaseType = get_Type($BaseId, 1);
9375
 
                        if(not $StableBase{$BaseType{"Name"}})
 
10228
                        if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
9376
10229
                        { # lost base
9377
10230
                            next;
9378
10231
                        }
9381
10234
                        if($VSize_Old!=$VSize_New)
9382
10235
                        {
9383
10236
                            foreach my $Symbol (@VFunctions)
9384
 
                            {
9385
 
                                if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
 
10237
                            { # TODO: affected non-virtual methods?
 
10238
                                if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
9386
10239
                                { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9387
10240
                                    next;
9388
10241
                                }
9404
10257
                                    }
9405
10258
                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
9406
10259
                                        "Type_Name"=>$BaseType{"Name"},
9407
 
                                        "Type_Type"=>"Class",
9408
10260
                                        "Target"=>get_Signature($VirtFunc, 2)  );
9409
10261
                                }
9410
10262
                                foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9416
10268
                                    }
9417
10269
                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
9418
10270
                                        "Type_Name"=>$BaseType{"Name"},
9419
 
                                        "Type_Type"=>"Class",
9420
10271
                                        "Target"=>get_Signature($VirtFunc, 1)  );
9421
10272
                                }
9422
10273
                            }
9503
10354
            { # became pure virtual
9504
10355
                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9505
10356
                    "Type_Name"=>$CName,
9506
 
                    "Type_Type"=>"Class",
9507
10357
                    "Target"=>get_Signature_M($Func, 1)  );
9508
10358
                $VTableChanged_M{$CName} = 1;
9509
10359
            }
9512
10362
            { # became non-pure virtual
9513
10363
                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9514
10364
                    "Type_Name"=>$CName,
9515
 
                    "Type_Type"=>"Class",
9516
10365
                    "Target"=>get_Signature_M($Func, 1)  );
9517
10366
                $VTableChanged_M{$CName} = 1;
9518
10367
            }
9530
10379
            { # pure virtual methods affect all others (virtual and non-virtual)
9531
10380
                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9532
10381
                    "Type_Name"=>$CName,
9533
 
                    "Type_Type"=>"Class",
9534
10382
                    "Target"=>get_Signature($AddedVFunc, 2)  );
9535
10383
                $VTableChanged_M{$CName} = 1;
9536
10384
            }
9541
10389
                { # became polymorphous class, added v-table pointer
9542
10390
                    %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9543
10391
                        "Type_Name"=>$CName,
9544
 
                        "Type_Type"=>"Class",
9545
10392
                        "Target"=>get_Signature($AddedVFunc, 2)  );
9546
10393
                    $VTableChanged_M{$CName} = 1;
9547
10394
                }
9549
10396
                {
9550
10397
                    my $VSize_Old = getVTable_Size($CName, 1);
9551
10398
                    my $VSize_New = getVTable_Size($CName, 2);
9552
 
                    next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
 
10399
                    next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
9553
10400
                    if(isCopyingClass($Class_Id, 1))
9554
10401
                    { # class has no constructors and v-table will be copied by applications, this may affect all methods
9555
10402
                        my $ProblemType = "Added_Virtual_Method";
9558
10405
                        }
9559
10406
                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9560
10407
                            "Type_Name"=>$CName,
9561
 
                            "Type_Type"=>"Class",
9562
10408
                            "Target"=>get_Signature($AddedVFunc, 2)  );
9563
10409
                        $VTableChanged_M{$CName} = 1;
9564
10410
                    }
9570
10416
                        }
9571
10417
                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9572
10418
                            "Type_Name"=>$CName,
9573
 
                            "Type_Type"=>"Class",
9574
10419
                            "Target"=>get_Signature($AddedVFunc, 2)  );
9575
10420
                        $VTableChanged_M{$CName} = 1;
9576
10421
                    }
9584
10429
                {
9585
10430
                    my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9586
10431
                    my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
 
10432
                    
9587
10433
                    if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
9588
10434
                    {
9589
10435
                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9591
10437
                        {
9592
10438
                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9593
10439
                            {
9594
 
                                if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
 
10440
                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
9595
10441
                                    next;
9596
10442
                                }
9597
10443
                            }
9598
10444
                            $CheckedSymbols{$Level}{$ASymbol} = 1;
9599
10445
                            %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9600
10446
                                "Type_Name"=>$CName,
9601
 
                                "Type_Type"=>"Class",
9602
10447
                                "Target"=>get_Signature($AddedVFunc, 2)  );
9603
10448
                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
9604
10449
                        }
9615
10460
            if($RemovedVFunc eq $Interface
9616
10461
            and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9617
10462
            { # This case is for removed virtual methods
9618
 
            # implemented in both versions of a library
 
10463
              # implemented in both versions of a library
9619
10464
                next;
9620
10465
            }
9621
10466
            if(not keys(%{$VirtualTable_Model{2}{$CName}}))
9622
10467
            { # became non-polymorphous class, removed v-table pointer
9623
10468
                %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9624
10469
                    "Type_Name"=>$CName,
9625
 
                    "Type_Type"=>"Class",
9626
10470
                    "Target"=>get_Signature($RemovedVFunc, 1)  );
9627
10471
                $VTableChanged_M{$CName} = 1;
9628
10472
            }
9654
10498
                        {
9655
10499
                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9656
10500
                            {
9657
 
                                if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
 
10501
                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
9658
10502
                                    next;
9659
10503
                                }
9660
10504
                            }
9665
10509
                            $CheckedSymbols{$Level}{$ASymbol} = 1;
9666
10510
                            %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9667
10511
                                "Type_Name"=>$CName,
9668
 
                                "Type_Type"=>"Class",
9669
10512
                                "Target"=>get_Signature($RemovedVFunc, 1)  );
9670
10513
                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
9671
10514
                        }
9683
10526
            {
9684
10527
                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9685
10528
                    "Type_Name"=>$CName,
9686
 
                    "Type_Type"=>"Class",
9687
10529
                    "Target"=>get_Signature($AddedVFunc, 2)  );
9688
10530
            }
9689
10531
        }
9693
10535
            {
9694
10536
                %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9695
10537
                    "Type_Name"=>$CName,
9696
 
                    "Type_Type"=>"Class",
9697
10538
                    "Target"=>get_Signature($RemovedVFunc, 1)  );
9698
10539
            }
9699
10540
        }
9767
10608
    return $CompatRules{$Level}{$Kind}{"Severity"};
9768
10609
}
9769
10610
 
9770
 
sub isRecurType($$)
 
10611
sub isRecurType($$$)
9771
10612
{
9772
 
    foreach (@RecurTypes)
 
10613
    foreach (@{$_[2]})
9773
10614
    {
9774
10615
        if( $_->{"T1"} eq $_[0]
9775
10616
        and $_->{"T2"} eq $_[1] )
9780
10621
    return 0;
9781
10622
}
9782
10623
 
9783
 
sub pushType($$)
 
10624
sub pushType($$$)
9784
10625
{
9785
 
    my %TypeIDs=(
9786
 
        "T1" => $_[0], #Tid1
9787
 
        "T2" => $_[1] #Tid2
 
10626
    my %IDs = (
 
10627
        "T1" => $_[0],
 
10628
        "T2" => $_[1]
9788
10629
    );
9789
 
    push(@RecurTypes, \%TypeIDs);
 
10630
    push(@{$_[2]}, \%IDs);
9790
10631
}
9791
10632
 
9792
10633
sub isRenamed($$$$$)
9794
10635
    my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9795
10636
    my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9796
10637
    my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
9797
 
    my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
 
10638
    my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
9798
10639
    if(not defined $Type2->{"Memb"}{$MemPos}) {
9799
10640
        return "";
9800
10641
    }
9801
10642
    my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9802
 
    my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
 
10643
    my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
9803
10644
    
9804
10645
    my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9805
10646
    my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
9848
10689
sub nonComparable($$)
9849
10690
{
9850
10691
    my ($T1, $T2) = @_;
9851
 
    if($T1->{"Name"} ne $T2->{"Name"}
9852
 
    and not isAnon($T1->{"Name"})
9853
 
    and not isAnon($T2->{"Name"}))
 
10692
    
 
10693
    my $N1 = $T1->{"Name"};
 
10694
    my $N2 = $T2->{"Name"};
 
10695
    
 
10696
    $N1=~s/\A(struct|union|enum) //;
 
10697
    $N2=~s/\A(struct|union|enum) //;
 
10698
    
 
10699
    if($N1 ne $N2
 
10700
    and not isAnon($N1)
 
10701
    and not isAnon($N2))
9854
10702
    { # different names
9855
10703
        if($T1->{"Type"} ne "Pointer"
9856
10704
        or $T2->{"Type"} ne "Pointer")
9857
10705
        { # compare base types
9858
10706
            return 1;
9859
10707
        }
9860
 
        if($T1->{"Name"}!~/\Avoid\s*\*/
9861
 
        and $T2->{"Name"}=~/\Avoid\s*\*/)
 
10708
        if($N1!~/\Avoid\s*\*/
 
10709
        and $N2=~/\Avoid\s*\*/)
9862
10710
        {
9863
10711
            return 1;
9864
10712
        }
9885
10733
    return 0;
9886
10734
}
9887
10735
 
 
10736
sub isOpaque($)
 
10737
{
 
10738
    my $T = $_[0];
 
10739
    if(not defined $T->{"Memb"})
 
10740
    {
 
10741
        return 1;
 
10742
    }
 
10743
    return 0;
 
10744
}
 
10745
 
 
10746
sub removeVPtr($)
 
10747
{ # support for old ABI dumps
 
10748
    my $TPtr = $_[0];
 
10749
    my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}});
 
10750
    if($#Pos>=1)
 
10751
    {
 
10752
        foreach my $Pos (0 .. $#Pos-1)
 
10753
        {
 
10754
            %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}};
 
10755
        }
 
10756
        delete($TPtr->{"Memb"}{$#Pos});
 
10757
    }
 
10758
}
 
10759
 
9888
10760
sub mergeTypes($$$)
9889
10761
{
9890
10762
    my ($Type1_Id, $Type2_Id, $Level) = @_;
9899
10771
    if(not $Type1{"Name"} or not $Type2{"Name"}) {
9900
10772
        return ();
9901
10773
    }
9902
 
    $CheckedTypes{$Level}{$Type1{"Name"}}=1;
9903
 
    my %Type1_Pure = get_PureType($Type1_Id, 1);
9904
 
    my %Type2_Pure = get_PureType($Type2_Id, 2);
9905
 
    $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
 
10774
    
 
10775
    $CheckedTypes{$Level}{$Type1{"Name"}} = 1;
 
10776
    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
 
10777
    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
 
10778
    $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1;
 
10779
    
 
10780
    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
 
10781
    {
 
10782
        if($Type1_Pure{"Type"}=~/Struct|Union/
 
10783
        and $Type2_Pure{"Type"}=~/Struct|Union/)
 
10784
        {
 
10785
            if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure))
 
10786
            {
 
10787
                %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=(
 
10788
                    "Target"=>$Type1_Pure{"Name"},
 
10789
                    "Type_Name"=>$Type1_Pure{"Name"}  );
 
10790
                
 
10791
                %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
 
10792
                return %SubProblems;
 
10793
            }
 
10794
        }
 
10795
    }
 
10796
    
9906
10797
    if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
9907
10798
    { # including a case when "class Class { ... };" changed to "class Class;"
9908
10799
        return ();
9909
10800
    }
9910
 
    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
 
10801
    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes))
9911
10802
    { # skip recursive declarations
9912
10803
        return ();
9913
10804
    }
9915
10806
    return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9916
10807
    return () if($SkipTypes{1}{$Type1{"Name"}});
9917
10808
    
 
10809
    if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/)
 
10810
    { # support for old ABI dumps
 
10811
      # _vptr field added in 3.0
 
10812
        if(not checkDump(1, "3.0") and checkDump(2, "3.0"))
 
10813
        {
 
10814
            if(defined $Type2_Pure{"Memb"}
 
10815
            and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr")
 
10816
            {
 
10817
                if(keys(%{$Type2_Pure{"Memb"}})==1) {
 
10818
                    delete($Type2_Pure{"Memb"}{0});
 
10819
                }
 
10820
                else {
 
10821
                    removeVPtr(\%Type2_Pure);
 
10822
                }
 
10823
            }
 
10824
        }
 
10825
        if(checkDump(1, "3.0") and not checkDump(2, "3.0"))
 
10826
        {
 
10827
            if(defined $Type1_Pure{"Memb"}
 
10828
            and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr")
 
10829
            {
 
10830
                if(keys(%{$Type1_Pure{"Memb"}})==1) {
 
10831
                    delete($Type1_Pure{"Memb"}{0});
 
10832
                }
 
10833
                else {
 
10834
                    removeVPtr(\%Type1_Pure);
 
10835
                }
 
10836
            }
 
10837
        }
 
10838
    }
 
10839
    
9918
10840
    my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
9919
10841
    my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
 
10842
    
9920
10843
    if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9921
10844
    and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9922
10845
    and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
9923
10846
    {
9924
 
        my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
9925
 
        my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
 
10847
        my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
 
10848
        my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
9926
10849
        if($Base_1{"Name"} ne $Base_2{"Name"})
9927
10850
        {
9928
10851
            if(differentDumps("G")
9933
10856
                # std::__va_list and __va_list
9934
10857
                $Base_1{"Name"}=~s/\A(\w+::)+//;
9935
10858
                $Base_2{"Name"}=~s/\A(\w+::)+//;
9936
 
                $Base_1{"Name"} = formatName($Base_1{"Name"});
9937
 
                $Base_2{"Name"} = formatName($Base_2{"Name"});
 
10859
                $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
 
10860
                $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
9938
10861
            }
9939
10862
        }
9940
10863
        if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9946
10869
                %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9947
10870
                    "Target"=>$Typedef_1{"Name"},
9948
10871
                    "Type_Name"=>$Typedef_1{"Name"},
9949
 
                    "Type_Type"=>"Typedef",
9950
10872
                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9951
10873
                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE  );
9952
10874
            }
9953
 
            %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9954
 
                "Target"=>$Typedef_1{"Name"},
9955
 
                "Type_Name"=>$Typedef_1{"Name"},
9956
 
                "Type_Type"=>"Typedef",
9957
 
                "Old_Value"=>$Base_1{"Name"},
9958
 
                "New_Value"=>$Base_2{"Name"}  );
 
10875
            my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1});
 
10876
            my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2});
 
10877
            if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"}))
 
10878
            {
 
10879
                if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level))
 
10880
                {
 
10881
                    %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=(
 
10882
                        "Target"=>$Typedef_1{"Name"},
 
10883
                        "Type_Name"=>$Typedef_1{"Name"},
 
10884
                        "Old_Value"=>$Base_1{"Name"},
 
10885
                        "New_Value"=>$Base_2{"Name"}  );
 
10886
                }
 
10887
                else
 
10888
                {
 
10889
                    %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
 
10890
                        "Target"=>$Typedef_1{"Name"},
 
10891
                        "Type_Name"=>$Typedef_1{"Name"},
 
10892
                        "Old_Value"=>$Base_1{"Name"},
 
10893
                        "New_Value"=>$Base_2{"Name"}  );
 
10894
                }
 
10895
            }
9959
10896
        }
9960
10897
    }
9961
10898
    if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9962
10899
    { # different types (reported in detectTypeChange(...))
9963
 
        if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9964
 
        and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9965
 
        and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
 
10900
        my $TT1 = $Type1_Pure{"Type"};
 
10901
        my $TT2 = $Type2_Pure{"Type"};
 
10902
        
 
10903
        if($TT1 ne $TT2
 
10904
        and $TT1!~/Intrinsic|Pointer|Ref|Typedef/)
9966
10905
        { # different type of the type
9967
 
            %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9968
 
                "Target"=>$Type1_Pure{"Name"},
9969
 
                "Type_Name"=>$Type1_Pure{"Name"},
9970
 
                "Type_Type"=>$Type1_Pure{"Type"},
9971
 
                "Old_Value"=>lc($Type1_Pure{"Type"}),
9972
 
                "New_Value"=>lc($Type2_Pure{"Type"})  );
 
10906
            my $Short1 = $Type1_Pure{"Name"};
 
10907
            my $Short2 = $Type2_Pure{"Name"};
 
10908
            
 
10909
            $Short1=~s/\A\Q$TT1\E //ig;
 
10910
            $Short2=~s/\A\Q$TT2\E //ig;
 
10911
            
 
10912
            if($Short1 eq $Short2)
 
10913
            {
 
10914
                %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
 
10915
                    "Target"=>$Type1_Pure{"Name"},
 
10916
                    "Type_Name"=>$Type1_Pure{"Name"},
 
10917
                    "Old_Value"=>lc($Type1_Pure{"Type"}),
 
10918
                    "New_Value"=>lc($Type2_Pure{"Type"})  );
 
10919
            }
9973
10920
        }
9974
10921
        %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
9975
10922
        return %SubProblems;
9976
10923
    }
9977
 
    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
 
10924
    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes);
9978
10925
    if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9979
10926
    or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9980
10927
    and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9994
10941
                    if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9995
10942
                        $ProblemKind = "Size_Of_Allocable_Class_Increased";
9996
10943
                    }
9997
 
                    else {
 
10944
                    else
 
10945
                    {
9998
10946
                        # descreased size of allocable class
9999
10947
                        # it has no special effects
10000
10948
                    }
10003
10951
            %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10004
10952
                "Target"=>$Type1_Pure{"Name"},
10005
10953
                "Type_Name"=>$Type1_Pure{"Name"},
10006
 
                "Type_Type"=>$Type1_Pure{"Type"},
10007
10954
                "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10008
10955
                "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10009
10956
                "InitialType_Type"=>$Type1_Pure{"Type"}  );
10010
10957
        }
10011
10958
    }
10012
 
    if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10013
 
    and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
 
10959
    if(defined $Type1_Pure{"BaseType"}
 
10960
    and defined $Type2_Pure{"BaseType"})
10014
10961
    { # checking base types
10015
 
        %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
 
10962
        %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level);
10016
10963
        foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10017
10964
        {
10018
10965
            foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10172
11119
                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10173
11120
                        "Target"=>$Member_Name,
10174
11121
                        "Type_Name"=>$Type1_Pure{"Name"},
10175
 
                        "Type_Type"=>$Type1_Pure{"Type"},
10176
11122
                        "Old_Value"=>$RPos1,
10177
11123
                        "New_Value"=>$RPos2 );
10178
11124
                }
10185
11131
        next if(not $Member_Name);
10186
11132
        if(my $RenamedTo = $RenamedField{$Member_Pos})
10187
11133
        { # renamed
 
11134
            if(defined $Constants{2}{$Member_Name})
 
11135
            {
 
11136
                if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo)
 
11137
                { # define OLD NEW
 
11138
                    next; # Safe
 
11139
                }
 
11140
            }
 
11141
            
10188
11142
            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10189
11143
            {
10190
11144
                if(isPublic(\%Type1_Pure, $Member_Pos))
10192
11146
                    %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10193
11147
                        "Target"=>$Member_Name,
10194
11148
                        "Type_Name"=>$Type1_Pure{"Name"},
10195
 
                        "Type_Type"=>$Type1_Pure{"Type"},
 
11149
                        "Old_Value"=>$Member_Name,
 
11150
                        "New_Value"=>$RenamedTo  );
 
11151
                }
 
11152
                elsif(isReserved($Member_Name))
 
11153
                {
 
11154
                    %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
 
11155
                        "Target"=>$Member_Name,
 
11156
                        "Type_Name"=>$Type1_Pure{"Name"},
10196
11157
                        "Old_Value"=>$Member_Name,
10197
11158
                        "New_Value"=>$RenamedTo  );
10198
11159
                }
10202
11163
                %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10203
11164
                    "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10204
11165
                    "Type_Name"=>$Type1_Pure{"Name"},
10205
 
                    "Type_Type"=>$Type1_Pure{"Type"},
10206
11166
                    "Old_Value"=>$Member_Name,
10207
11167
                    "New_Value"=>$RenamedTo  );
10208
11168
            }
10221
11181
                    $ProblemType = "Removed_Private_Field";
10222
11182
                }
10223
11183
                if($Level eq "Binary"
10224
 
                and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
 
11184
                and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
10225
11185
                {
10226
11186
                    if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10227
11187
                    { # affected fields
10228
 
                        if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
 
11188
                        if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2}))
10229
11189
                        { # changed offset
10230
11190
                            $ProblemType .= "_And_Layout";
10231
11191
                        }
10240
11200
                }
10241
11201
                %{$SubProblems{$ProblemType}{$Member_Name}}=(
10242
11202
                    "Target"=>$Member_Name,
10243
 
                    "Type_Name"=>$Type1_Pure{"Name"},
10244
 
                    "Type_Type"=>$Type1_Pure{"Type"}  );
 
11203
                    "Type_Name"=>$Type1_Pure{"Name"}  );
10245
11204
            }
10246
11205
            elsif($Type2_Pure{"Type"} eq "Union")
10247
11206
            {
10250
11209
                {
10251
11210
                    %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10252
11211
                        "Target"=>$Member_Name,
10253
 
                        "Type_Name"=>$Type1_Pure{"Name"},
10254
 
                        "Type_Type"=>$Type1_Pure{"Type"}  );
 
11212
                        "Type_Name"=>$Type1_Pure{"Name"}  );
10255
11213
                }
10256
11214
                else
10257
11215
                {
10258
11216
                    %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10259
11217
                        "Target"=>$Member_Name,
10260
 
                        "Type_Name"=>$Type1_Pure{"Name"},
10261
 
                        "Type_Type"=>$Type1_Pure{"Type"}  );
 
11218
                        "Type_Name"=>$Type1_Pure{"Name"}  );
10262
11219
                }
10263
11220
            }
10264
11221
            elsif($Type1_Pure{"Type"} eq "Enum")
10266
11223
                %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10267
11224
                    "Target"=>$Member_Name,
10268
11225
                    "Type_Name"=>$Type1_Pure{"Name"},
10269
 
                    "Type_Type"=>$Type1_Pure{"Type"},
10270
11226
                    "Old_Value"=>$Member_Name  );
10271
11227
            }
10272
11228
        }
10285
11241
                    if(isLastElem($Member_Pos, \%Type1_Pure)) {
10286
11242
                        $ProblemType = "Enum_Last_Member_Value";
10287
11243
                    }
 
11244
                    if($SkipConstants{1}{$Member_Name}) {
 
11245
                        $ProblemType = "Enum_Private_Member_Value";
 
11246
                    }
10288
11247
                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10289
11248
                        "Target"=>$Member_Name,
10290
11249
                        "Type_Name"=>$Type1_Pure{"Name"},
10291
 
                        "Type_Type"=>$Type1_Pure{"Type"},
10292
11250
                        "Old_Value"=>$Member_Value1,
10293
11251
                        "New_Value"=>$Member_Value2  );
10294
11252
                }
10295
11253
            }
10296
11254
            elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10297
11255
            {
 
11256
                my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"};
 
11257
                my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"};
 
11258
                
 
11259
                if($Access1 ne "private"
 
11260
                and $Access2 eq "private")
 
11261
                {
 
11262
                    %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=(
 
11263
                        "Target"=>$Member_Name,
 
11264
                        "Type_Name"=>$Type1_Pure{"Name"});
 
11265
                }
 
11266
                elsif($Access1 ne "protected"
 
11267
                and $Access1 ne "private"
 
11268
                and $Access2 eq "protected")
 
11269
                {
 
11270
                    %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=(
 
11271
                        "Target"=>$Member_Name,
 
11272
                        "Type_Name"=>$Type1_Pure{"Name"});
 
11273
                }
 
11274
                
10298
11275
                my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10299
11276
                my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
10300
11277
                my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
10323
11300
                          # example: "abidata" members in GStreamer types
10324
11301
                            $ProblemType = "Private_".$ProblemType;
10325
11302
                        }
10326
 
                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
 
11303
                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
10327
11304
                        { # check an effect
10328
 
                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
 
11305
                            if($Type2_Pure{"Type"} ne "Union"
 
11306
                            and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10329
11307
                            { # public fields after the current
10330
 
                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
 
11308
                                if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2}))
10331
11309
                                { # changed offset
10332
11310
                                    $ProblemType .= "_And_Layout";
10333
11311
                                }
10345
11323
                            %{$SubProblems{$ProblemType}{$Member_Name}}=(
10346
11324
                                "Target"=>$Member_Name,
10347
11325
                                "Type_Name"=>$Type1_Pure{"Name"},
10348
 
                                "Type_Type"=>$Type1_Pure{"Type"},
10349
11326
                                "Old_Size"=>$SizeV1,
10350
11327
                                "New_Size"=>$SizeV2);
10351
11328
                        }
10363
11340
                    {
10364
11341
                        %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10365
11342
                            "Target"=>$Member_Name,
10366
 
                            "Type_Name"=>$Type1_Pure{"Name"},
10367
 
                            "Type_Type"=>$Type1_Pure{"Type"});
 
11343
                            "Type_Name"=>$Type1_Pure{"Name"});
10368
11344
                    }
10369
11345
                    elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10370
11346
                    and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10371
11347
                    {
10372
 
                        %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
 
11348
                        %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=(
10373
11349
                            "Target"=>$Member_Name,
10374
 
                            "Type_Name"=>$Type1_Pure{"Name"},
10375
 
                            "Type_Type"=>$Type1_Pure{"Type"});
 
11350
                            "Type_Name"=>$Type1_Pure{"Name"});
10376
11351
                    }
10377
11352
                }
10378
11353
                %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
10380
11355
                {
10381
11356
                    my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10382
11357
                    my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
 
11358
                    
 
11359
                    # quals
10383
11360
                    if($ProblemType eq "Field_Type"
10384
 
                    or $ProblemType eq "Field_Type_And_Size")
 
11361
                    or $ProblemType eq "Field_Type_And_Size"
 
11362
                    or $ProblemType eq "Field_Type_Format")
10385
11363
                    {
10386
11364
                        if(checkDump(1, "2.6") and checkDump(2, "2.6"))
10387
11365
                        {
10388
 
                            if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
10389
 
                            {
 
11366
                            if(addedQual($Old_Value, $New_Value, "volatile")) {
10390
11367
                                %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10391
 
                                if($Level eq "Source"
10392
 
                                and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10393
 
                                    delete($Sub_SubProblems{$ProblemType});
10394
 
                                }
10395
11368
                            }
10396
 
                            elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10397
 
                            {
10398
 
                                %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10399
 
                                if($Level eq "Source"
10400
 
                                and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10401
 
                                    delete($Sub_SubProblems{$ProblemType});
10402
 
                                }
 
11369
                            elsif(removedQual($Old_Value, $New_Value, "volatile")) {
 
11370
                                %{$Sub_SubProblems{"Field_Became_Non_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10403
11371
                            }
10404
11372
                        }
10405
11373
                        if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10410
11378
                            else {
10411
11379
                                %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10412
11380
                            }
10413
 
                            if($Level eq "Source"
10414
 
                            and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10415
 
                                delete($Sub_SubProblems{$ProblemType});
10416
 
                            }
10417
11381
                        }
10418
11382
                        elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10419
11383
                        {
10421
11385
                                %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10422
11386
                            }
10423
11387
                            else {
10424
 
                                %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
 
11388
                                %{$Sub_SubProblems{"Field_Became_Non_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10425
11389
                            }
10426
 
                            if($Level eq "Source"
10427
 
                            and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
 
11390
                        }
 
11391
                    }
 
11392
                }
 
11393
                
 
11394
                if($Level eq "Source")
 
11395
                {
 
11396
                    foreach my $ProblemType (keys(%Sub_SubProblems))
 
11397
                    {
 
11398
                        my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
 
11399
                        my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
 
11400
                        
 
11401
                        if($ProblemType eq "Field_Type")
 
11402
                        {
 
11403
                            if(cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10428
11404
                                delete($Sub_SubProblems{$ProblemType});
10429
11405
                            }
10430
11406
                        }
10431
11407
                    }
10432
11408
                }
 
11409
                
10433
11410
                foreach my $ProblemType (keys(%Sub_SubProblems))
10434
11411
                {
10435
11412
                    my $ProblemType_Init = $ProblemType;
10439
11416
                        or isUnnamed($Member_Name)) {
10440
11417
                            $ProblemType = "Private_".$ProblemType;
10441
11418
                        }
10442
 
                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
 
11419
                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
10443
11420
                        { # check an effect
10444
 
                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
 
11421
                            if($Type2_Pure{"Type"} ne "Union"
 
11422
                            and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10445
11423
                            { # public fields after the current
10446
 
                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
 
11424
                                if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2}))
10447
11425
                                { # changed offset
10448
11426
                                    $ProblemType .= "_And_Layout";
10449
11427
                                }
10466
11444
                    }
10467
11445
                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10468
11446
                        "Target"=>$Member_Name,
10469
 
                        "Type_Name"=>$Type1_Pure{"Name"},
10470
 
                        "Type_Type"=>$Type1_Pure{"Type"}  );
 
11447
                        "Type_Name"=>$Type1_Pure{"Name"});
 
11448
                    
10471
11449
                    foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10472
11450
                    { # other properties
10473
11451
                        $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10516
11494
                    $ProblemType = "Added_Private_Field";
10517
11495
                }
10518
11496
                if($Level eq "Binary"
10519
 
                and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
 
11497
                and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2}))
10520
11498
                {
10521
11499
                    if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10522
11500
                    { # public fields after the current
10523
 
                        if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
 
11501
                        if(getOffset($MNum-1, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
10524
11502
                        { # changed offset
10525
11503
                            $ProblemType .= "_And_Layout";
10526
11504
                        }
10535
11513
                }
10536
11514
                %{$SubProblems{$ProblemType}{$Member_Name}}=(
10537
11515
                    "Target"=>$Member_Name,
10538
 
                    "Type_Name"=>$Type1_Pure{"Name"},
10539
 
                    "Type_Type"=>$Type1_Pure{"Type"}  );
 
11516
                    "Type_Name"=>$Type1_Pure{"Name"});
10540
11517
            }
10541
11518
            elsif($Type2_Pure{"Type"} eq "Union")
10542
11519
            {
10545
11522
                {
10546
11523
                    %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10547
11524
                        "Target"=>$Member_Name,
10548
 
                        "Type_Name"=>$Type1_Pure{"Name"},
10549
 
                        "Type_Type"=>$Type1_Pure{"Type"}  );
 
11525
                        "Type_Name"=>$Type1_Pure{"Name"});
10550
11526
                }
10551
11527
                else
10552
11528
                {
10553
11529
                    %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10554
11530
                        "Target"=>$Member_Name,
10555
 
                        "Type_Name"=>$Type1_Pure{"Name"},
10556
 
                        "Type_Type"=>$Type1_Pure{"Type"}  );
 
11531
                        "Type_Name"=>$Type1_Pure{"Name"});
10557
11532
                }
10558
11533
            }
10559
11534
            elsif($Type2_Pure{"Type"} eq "Enum")
10563
11538
                %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10564
11539
                    "Target"=>$Member_Name,
10565
11540
                    "Type_Name"=>$Type2_Pure{"Name"},
10566
 
                    "Type_Type"=>$Type2_Pure{"Type"},
10567
 
                    "New_Value"=>$Member_Value  );
 
11541
                    "New_Value"=>$Member_Value);
10568
11542
            }
10569
11543
        }
10570
11544
    }
10577
11551
    return $_[0]=~/\Aunnamed\d+\Z/;
10578
11552
}
10579
11553
 
10580
 
sub get_ShortType($$)
 
11554
sub get_ShortClass($$)
10581
11555
{
10582
11556
    my ($TypeId, $LibVersion) = @_;
10583
11557
    my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
 
11558
    if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) {
 
11559
        $TypeName = uncover_typedefs($TypeName, $LibVersion);
 
11560
    }
10584
11561
    if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
10585
 
        $TypeName=~s/\A$NameSpace\:\://g;
 
11562
        $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g;
10586
11563
    }
10587
11564
    return $TypeName;
10588
11565
}
10599
11576
    return () if(not $Type{"Type"});
10600
11577
    if($Type{"Type"} ne $Type_Type)
10601
11578
    {
10602
 
        return () if(not defined $Type{"BaseType"});
10603
 
        return () if(not $Type{"BaseType"}{"Tid"});
10604
 
        %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
 
11579
        return () if(not $Type{"BaseType"});
 
11580
        %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type);
10605
11581
    }
10606
11582
    $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
10607
11583
    return %Type;
10617
11593
 
10618
11594
sub get_PureType($$)
10619
11595
{
10620
 
    my ($TypeId, $LibVersion) = @_;
10621
 
    return () if(not $TypeId);
10622
 
    if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10623
 
        return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
10624
 
    }
10625
 
    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10626
 
    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10627
 
    return %Type if(not defined $Type{"BaseType"});
10628
 
    return %Type if(not $Type{"BaseType"}{"Tid"});
 
11596
    my ($TypeId, $Info) = @_;
 
11597
    if(not $TypeId or not $Info
 
11598
    or not $Info->{$TypeId}) {
 
11599
        return ();
 
11600
    }
 
11601
    if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
 
11602
        return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
 
11603
    }
 
11604
    my %Type = %{$Info->{$TypeId}};
 
11605
    return %Type if(not $Type{"BaseType"});
10629
11606
    if($TypeSpecAttributes{$Type{"Type"}}) {
10630
 
        %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
 
11607
        %Type = get_PureType($Type{"BaseType"}, $Info);
10631
11608
    }
10632
 
    $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
 
11609
    $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
10633
11610
    return %Type;
10634
11611
}
10635
11612
 
10642
11619
    }
10643
11620
    return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10644
11621
    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10645
 
    return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
10646
 
    return 0 if(not defined $Type{"BaseType"});
10647
 
    return 0 if(not $Type{"BaseType"}{"Tid"});
10648
 
    my $PointerLevel = 0;
10649
 
    if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10650
 
        $PointerLevel += 1;
 
11622
    return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/);
 
11623
    my $PLevel = 0;
 
11624
    if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) {
 
11625
        $PLevel += 1;
10651
11626
    }
10652
 
    $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10653
 
    $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
10654
 
    return $PointerLevel;
 
11627
    return $PLevel if(not $Type{"BaseType"});
 
11628
    $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion);
 
11629
    $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel;
 
11630
    return $PLevel;
10655
11631
}
10656
11632
 
10657
11633
sub get_BaseType($$)
10663
11639
    }
10664
11640
    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10665
11641
    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10666
 
    return %Type if(not defined $Type{"BaseType"});
10667
 
    return %Type if(not $Type{"BaseType"}{"Tid"});
10668
 
    %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
 
11642
    return %Type if(not $Type{"BaseType"});
 
11643
    %Type = get_BaseType($Type{"BaseType"}, $LibVersion);
10669
11644
    $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
10670
11645
    return %Type;
10671
11646
}
10676
11651
    return "" if(not $TypeId);
10677
11652
    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10678
11653
    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10679
 
    return "" if(not defined $Type{"BaseType"});
10680
 
    return "" if(not $Type{"BaseType"}{"Tid"});
 
11654
    return "" if(not $Type{"BaseType"});
10681
11655
    my $Qual = "";
10682
11656
    if($Type{"Type"} eq "Pointer") {
10683
11657
        $Qual .= "*";
10693
11667
    or $Type{"Type"} eq "Restrict") {
10694
11668
        $Qual .= lc($Type{"Type"});
10695
11669
    }
10696
 
    my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
 
11670
    my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion);
10697
11671
    return $BQual.$Qual;
10698
11672
}
10699
11673
 
10700
11674
sub get_OneStep_BaseType($$)
10701
11675
{
10702
 
    my ($TypeId, $LibVersion) = @_;
10703
 
    return () if(not $TypeId);
10704
 
    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10705
 
    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10706
 
    return %Type if(not defined $Type{"BaseType"});
10707
 
    return %Type if(not $Type{"BaseType"}{"Tid"});
10708
 
    return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
 
11676
    my ($TypeId, $Info) = @_;
 
11677
    if(not $TypeId or not $Info
 
11678
    or not $Info->{$TypeId}) {
 
11679
        return ();
 
11680
    }
 
11681
    my %Type = %{$Info->{$TypeId}};
 
11682
    return %Type if(not $Type{"BaseType"});
 
11683
    if(my $BTid = $Type{"BaseType"})
 
11684
    {
 
11685
        if($Info->{$BTid}) {
 
11686
            return %{$Info->{$BTid}};
 
11687
        }
 
11688
        else { # something is going wrong
 
11689
            return ();
 
11690
        }
 
11691
    }
 
11692
    else {
 
11693
        return %Type;
 
11694
    }
10709
11695
}
10710
11696
 
10711
11697
sub get_Type($$)
10722
11708
    return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10723
11709
}
10724
11710
 
10725
 
sub isTemplateInstance($$)
 
11711
sub isInLineInst($$$) {
 
11712
    return (isTemplateInstance(@_) and not isTemplateSpec(@_));
 
11713
}
 
11714
 
 
11715
sub isTemplateInstance($$$)
10726
11716
{
10727
 
    my ($Symbol, $LibVersion) = @_;
 
11717
    my ($Symbol, $SInfo, $LibVersion) = @_;
10728
11718
    if($CheckObjectsOnly)
10729
11719
    {
10730
11720
        if($Symbol!~/\A(_Z|\?)/) {
10737
11727
            }
10738
11728
            if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10739
11729
            {
10740
 
                if($ShortName=~/<.+>/) {
 
11730
                if(index($ShortName,"<")!=-1
 
11731
                and index($ShortName,">")!=-1) {
10741
11732
                    return 1;
10742
11733
                }
10743
11734
            }
10745
11736
    }
10746
11737
    else
10747
11738
    {
10748
 
        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
 
11739
        if(my $ClassId = $SInfo->{"Class"})
10749
11740
        {
10750
11741
            if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10751
11742
            {
10754
11745
                }
10755
11746
            }
10756
11747
        }
10757
 
        if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
 
11748
        if(my $ShortName = $SInfo->{"ShortName"})
10758
11749
        {
10759
 
            if($ShortName=~/<.+>/) {
 
11750
            if(index($ShortName,"<")!=-1
 
11751
            and index($ShortName,">")!=-1) {
10760
11752
                return 1;
10761
11753
            }
10762
11754
        }
10764
11756
    return 0;
10765
11757
}
10766
11758
 
10767
 
sub isTemplateSpec($$)
 
11759
sub isTemplateSpec($$$)
10768
11760
{
10769
 
    my ($Symbol, $LibVersion) = @_;
10770
 
    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
 
11761
    my ($Symbol, $SInfo, $LibVersion) = @_;
 
11762
    if(my $ClassId = $SInfo->{"Class"})
10771
11763
    {
10772
11764
        if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
10773
11765
        { # class specialization
10774
11766
            return 1;
10775
11767
        }
10776
 
        elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
 
11768
        elsif($SInfo->{"Spec"})
10777
11769
        { # method specialization
10778
11770
            return 1;
10779
11771
        }
10841
11833
        { # user defined symbols
10842
11834
            return 0;
10843
11835
        }
 
11836
        if($SkipSymbolsListPath and $SkipSymbolsList{$Symbol})
 
11837
        { # user defined symbols
 
11838
            return 0;
 
11839
        }
10844
11840
        if($AppPath and not $SymbolsList_App{$Symbol})
10845
11841
        { # user defined symbols (in application)
10846
11842
            return 0;
10853
11849
        {
10854
11850
            if($CheckObjectsOnly)
10855
11851
            {
10856
 
                if(isTemplateInstance($Symbol, $LibVersion)) {
 
11852
                if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
10857
11853
                    return 0;
10858
11854
                }
10859
11855
            }
10860
11856
            else
10861
11857
            {
10862
11858
                if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10863
 
                or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
 
11859
                or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
10864
11860
                {
10865
11861
                    if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10866
11862
                    { # inline virtual methods
10916
11912
        {
10917
11913
            writeFile("$TMP_DIR/impl1", $Impl1);
10918
11914
            writeFile("$TMP_DIR/impl2", $Impl2);
10919
 
            my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
 
11915
            my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
10920
11916
            $Diff=~s/(---|\+\+\+).+\n//g;
10921
11917
            $Diff=~s/[ ]{3,}/ /g;
10922
11918
            $Diff=~s/\n\@\@/\n \n\@\@/g;
10923
 
            unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10924
 
            %{$ImplProblems{$Interface}}=(
 
11919
            unlink("$TMP_DIR/impl1");
 
11920
            unlink("$TMP_DIR/impl2");
 
11921
            %{$CompatProblems_Impl{$Interface}}=(
10925
11922
                "Diff" => get_CodeView($Diff)  );
10926
11923
        }
10927
11924
    }
10975
11972
            exitStatus("Not_Found", "can't find \"otool\"");
10976
11973
        }
10977
11974
        my $CurInterface = "";
10978
 
        foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
 
11975
        foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
10979
11976
        {
10980
11977
            if($Line=~/\A\s*_(\w+)\s*:/i) {
10981
11978
                $CurInterface = $1;
10992
11989
            exitStatus("Not_Found", "can't find \"objdump\"");
10993
11990
        }
10994
11991
        my $CurInterface = "";
10995
 
        foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
 
11992
        foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
10996
11993
        {
10997
11994
            if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10998
11995
                $CurInterface = $1;
11055
12052
    { # checking added symbols
11056
12053
        next if($CompleteSignature{2}{$Symbol}{"Private"});
11057
12054
        next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11058
 
        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
 
12055
        next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level));
11059
12056
        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
11060
12057
    }
11061
12058
    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11062
12059
    { # checking removed symbols
11063
12060
        next if($CompleteSignature{1}{$Symbol}{"Private"});
11064
12061
        next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11065
 
        if($Symbol=~/\A_ZTV/)
 
12062
        if(index($Symbol, "_ZTV")==0)
11066
12063
        { # skip v-tables for templates, that should not be imported by applications
11067
12064
            next if($tr_name{$Symbol}=~/</);
11068
12065
            if(my $CName = $VTableClass{$Symbol})
11075
12072
            }
11076
12073
        }
11077
12074
        else {
11078
 
            next if(not symbolFilter($Symbol, 1, "Affected", $Level));
 
12075
            next if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level));
11079
12076
        }
11080
12077
        if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11081
12078
        { # symbols for pure virtual methods cannot be called by clients
11205
12202
                    next;
11206
12203
                }
11207
12204
            }
 
12205
            if(not $CompleteSignature{1}{$Symbol}{"Class"})
 
12206
            {
 
12207
                if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
 
12208
                {
 
12209
                    if(defined $Constants{2}{$Short})
 
12210
                    {
 
12211
                        my $Val = $Constants{2}{$Short}{"Value"};
 
12212
                        if(defined $Func_ShortName{2}{$Val})
 
12213
                        { # old name defined to new
 
12214
                            next;
 
12215
                        }
 
12216
                    }
 
12217
                }
 
12218
                
 
12219
            }
11208
12220
            $RemovedInt{$Level}{$Symbol} = 1;
11209
12221
            if($Level eq "Source")
11210
12222
            { # search for a source-compatible equivalent
11220
12232
    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
11221
12233
    { # checking added symbols
11222
12234
        next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
 
12235
        next if($CompleteSignature{2}{$Symbol}{"Private"});
 
12236
        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
11223
12237
        if($Level eq "Binary")
11224
12238
        {
11225
12239
            if($CompleteSignature{2}{$Symbol}{"InLine"})
11236
12250
                next;
11237
12251
            }
11238
12252
        }
11239
 
        next if($CompleteSignature{2}{$Symbol}{"Private"});
11240
 
        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
11241
12253
        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
11242
12254
    }
11243
12255
    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11244
12256
    { # checking removed symbols
11245
12257
        next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
 
12258
        next if($CompleteSignature{1}{$Symbol}{"Private"});
 
12259
        next if(not symbolFilter($Symbol, 1, "Affected", $Level));
11246
12260
        if($Level eq "Binary")
11247
12261
        {
11248
12262
            if($CompleteSignature{1}{$Symbol}{"InLine"})
11263
12277
                    my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11264
12278
                    %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
11265
12279
                        "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
11266
 
                        "Type_Type"=>"Class",
11267
 
                        "Target"=>get_Signature($Alt, 1)  );
 
12280
                        "Target"=>get_Signature($Alt, 1));
11268
12281
                }
11269
12282
                else
11270
12283
                { # do NOT show removed symbol
11272
12285
                }
11273
12286
            }
11274
12287
        }
11275
 
        next if($CompleteSignature{1}{$Symbol}{"Private"});
11276
 
        next if(not symbolFilter($Symbol, 1, "Affected", $Level));
11277
12288
        %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
11278
12289
    }
11279
12290
}
11330
12341
{
11331
12342
    my ($Symbol, $Full) = @_;
11332
12343
    my ($SN, $SO, $SV) = separate_symbol($Symbol);
11333
 
    $Symbol=$SN;# remove version
 
12344
    $Symbol=$SN; # remove version
11334
12345
    my $Signature = $tr_name{$Symbol};
11335
12346
    my $Suffix = substr($Signature, find_center($Signature, "("));
11336
12347
    if(not $Full) {
11417
12428
    return "Function";
11418
12429
}
11419
12430
 
11420
 
sub mergeSignatures($)
 
12431
sub mergeSymbols($)
11421
12432
{
11422
12433
    my $Level = $_[0];
11423
12434
    my %SubProblems = ();
11455
12466
                    { # old v-table is NOT copied by old applications
11456
12467
                        %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11457
12468
                            "Type_Name"=>$AffectedClass_Name,
11458
 
                            "Type_Type"=>"Class",
11459
12469
                            "Target"=>get_Signature($Symbol, 2),
11460
12470
                            "Old_Value"=>get_Signature($OverriddenMethod, 2),
11461
 
                            "New_Value"=>get_Signature($Symbol, 2)  );
 
12471
                            "New_Value"=>get_Signature($Symbol, 2));
11462
12472
                    }
11463
12473
                }
11464
12474
            }
11495
12505
                    { # old v-table is NOT copied by old applications
11496
12506
                        %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11497
12507
                            "Type_Name"=>$AffectedClass_Name,
11498
 
                            "Type_Type"=>"Class",
11499
12508
                            "Target"=>get_Signature($OverriddenMethod, 1),
11500
12509
                            "Old_Value"=>get_Signature($Symbol, 1),
11501
 
                            "New_Value"=>get_Signature($OverriddenMethod, 1)  );
 
12510
                            "New_Value"=>get_Signature($OverriddenMethod, 1));
11502
12511
                    }
11503
12512
                }
11504
12513
            }
11521
12530
                        }
11522
12531
                        else
11523
12532
                        {
11524
 
                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
 
12533
                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=(
11525
12534
                                "Target"=>$tr_name{$Symbol},
11526
12535
                                "Old_Value"=>$Symbol,
11527
12536
                                "New_Value"=>$NewSym  );
11538
12547
                        }
11539
12548
                        else
11540
12549
                        {
11541
 
                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
 
12550
                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=(
11542
12551
                                "Target"=>$tr_name{$Symbol},
11543
12552
                                "Old_Value"=>$Symbol,
11544
12553
                                "New_Value"=>$NewSym  );
11594
12603
                    if($CompleteSignature{1}{$Symbol}{"Const"}
11595
12604
                    and not $CompleteSignature{2}{$NewSym}{"Const"})
11596
12605
                    { # "const" to non-"const"
11597
 
                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
 
12606
                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=(
11598
12607
                            "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
11599
12608
                            "Target"=>$tr_name{$Symbol},
11600
12609
                            "New_Signature"=>get_Signature($NewSym, 2),
11614
12623
                    and not $CompleteSignature{2}{$NewSym}{"Volatile"})
11615
12624
                    { # "volatile" to non-"volatile"
11616
12625
                        
11617
 
                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
 
12626
                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=(
11618
12627
                            "Target"=>$tr_name{$Symbol},
11619
12628
                            "New_Signature"=>get_Signature($NewSym, 2),
11620
12629
                            "Old_Value"=>$Symbol,
11691
12700
        { # without a header
11692
12701
            next;
11693
12702
        }
 
12703
        
 
12704
        if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
 
12705
        and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
 
12706
        { # became pure
 
12707
            next;
 
12708
        }
 
12709
        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
 
12710
        and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
 
12711
        { # became non-pure
 
12712
            next;
 
12713
        }
 
12714
        
 
12715
        if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
 
12716
        { # exported, target, inline virtual and pure virtual
 
12717
            next;
 
12718
        }
 
12719
        if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
 
12720
        { # exported, target, inline virtual and pure virtual
 
12721
            next;
 
12722
        }
 
12723
        
11694
12724
        if(checkDump(1, "2.13") and checkDump(2, "2.13"))
11695
12725
        {
11696
12726
            if($CompleteSignature{1}{$Symbol}{"Data"}
11716
12746
            }
11717
12747
        }
11718
12748
        
11719
 
        if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11720
 
        and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11721
 
        { # became pure
11722
 
            next;
11723
 
        }
11724
 
        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11725
 
        and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11726
 
        { # became non-pure
11727
 
            next;
11728
 
        }
11729
 
        
11730
 
        if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11731
 
        { # exported, target, inline virtual and pure virtual
11732
 
            next;
11733
 
        }
11734
 
        if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11735
 
        { # exported, target, inline virtual and pure virtual
11736
 
            next;
11737
 
        }
11738
 
        
11739
12749
        if($CompleteSignature{2}{$PSymbol}{"Private"})
11740
12750
        {
11741
12751
            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11767
12777
            }
11768
12778
            if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
11769
12779
            and not $CompleteSignature{2}{$PSymbol}{"Data"})
11770
 
            {# missed information about parameters in older version
 
12780
            { # missed information about parameters in older version
11771
12781
                next;
11772
12782
            }
11773
12783
        }
11774
12784
        my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
11775
12785
        # checking attributes
11776
12786
        if($CompleteSignature{2}{$PSymbol}{"Static"}
11777
 
        and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
 
12787
        and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
 
12788
        {
11778
12789
            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11779
12790
                "Target"=>get_Signature($Symbol, 1)
11780
12791
            );
11781
12792
        }
11782
12793
        elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11783
 
        and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11784
 
            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
 
12794
        and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
 
12795
        {
 
12796
            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=(
11785
12797
                "Target"=>get_Signature($Symbol, 1)
11786
12798
            );
11787
12799
        }
11806
12818
                        if(isUsedClass($Class_Id, 1, $Level))
11807
12819
                        {
11808
12820
                            my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11809
 
                            foreach my $AffectedInterface (@Affected)
 
12821
                            foreach my $ASymbol (@Affected)
11810
12822
                            {
11811
 
                                %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
 
12823
                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
 
12824
                                    next;
 
12825
                                }
 
12826
                                %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
11812
12827
                                    "Type_Name"=>$Class_Type{"Name"},
11813
 
                                    "Type_Type"=>"Class",
11814
12828
                                    "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11815
12829
                                    "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11816
 
                                    "Target"=>get_Signature($Symbol, 1)  );
 
12830
                                    "Target"=>get_Signature($Symbol, 1));
11817
12831
                            }
11818
12832
                            $VTableChanged_M{$Class_Type{"Name"}} = 1;
11819
12833
                        }
11826
12840
        { # do NOT check type changes in pure virtuals
11827
12841
            next;
11828
12842
        }
11829
 
        $CheckedSymbols{$Level}{$Symbol}=1;
 
12843
        $CheckedSymbols{$Level}{$Symbol} = 1;
11830
12844
        if($Symbol=~/\A(_Z|\?)/
11831
12845
        or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
11832
12846
        { # C/C++: changes in parameters
11833
12847
            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
11834
12848
            { # checking parameters
11835
 
                mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
 
12849
                mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1);
11836
12850
            }
11837
12851
        }
11838
12852
        else
11872
12886
                    }
11873
12887
                    else
11874
12888
                    {
11875
 
                        my %ParamType_Pure = get_PureType($PType2_Id, 2);
 
12889
                        my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
11876
12890
                        my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11877
 
                        my %PairType_Pure = get_PureType($PairType_Id, 1);
 
12891
                        my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
11878
12892
                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
11879
12893
                        and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
11880
12894
                        {
11915
12929
                    my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11916
12930
                    if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
11917
12931
                    or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
11918
 
                        mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
 
12932
                        mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0);
11919
12933
                    }
11920
12934
                }
11921
12935
            }
11924
12938
                my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11925
12939
                my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
11926
12940
                last if($PType1_Name eq "...");
11927
 
                my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
11928
 
                my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
 
12941
                my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
 
12942
                my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
11929
12943
                my $ParamPos_New = "-1";
11930
 
                if($Parameter_Name=~/\Ap\d+\Z/i)
 
12944
                if($PName=~/\Ap\d+\Z/i)
11931
12945
                { # removed unnamed parameter ( pN )
11932
12946
                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
11933
12947
                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
11936
12950
                    }
11937
12951
                }
11938
12952
                else {
11939
 
                    $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
 
12953
                    $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2);
11940
12954
                }
11941
12955
                if($ParamPos_New eq "lost")
11942
12956
                {
11943
12957
                    if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
11944
12958
                    {
11945
12959
                        my $ProblemType = "Removed_Parameter";
11946
 
                        if($Parameter_Name=~/\Ap\d+\Z/) {
 
12960
                        if($PName=~/\Ap\d+\Z/) {
11947
12961
                            $ProblemType = "Removed_Unnamed_Parameter";
11948
12962
                        }
11949
12963
                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
11950
 
                            "Target"=>$Parameter_Name,
 
12964
                            "Target"=>$PName,
11951
12965
                            "Param_Pos"=>$ParamPos,
11952
12966
                            "Param_Type"=>$PType1_Name,
11953
12967
                            "New_Signature"=>get_Signature($Symbol, 2)  );
11954
12968
                    }
11955
12969
                    elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
11956
12970
                    {
11957
 
                        my %ParamType_Pure = get_PureType($PType1_Id, 1);
 
12971
                        my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
11958
12972
                        my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11959
 
                        my %PairType_Pure = get_PureType($PairType_Id, 2);
 
12973
                        my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
11960
12974
                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
11961
 
                        and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
 
12975
                        and find_ParamPair_Pos_byName($PName_New, $Symbol, 1) eq "lost")
11962
12976
                        {
11963
 
                            if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
 
12977
                            if($PName_New!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
11964
12978
                            {
11965
12979
                                %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
11966
 
                                    "Target"=>$Parameter_Name,
 
12980
                                    "Target"=>$PName,
11967
12981
                                    "Param_Pos"=>$ParamPos,
11968
12982
                                    "Param_Type"=>$PType1_Name,
11969
 
                                    "Old_Value"=>$Parameter_Name,
11970
 
                                    "New_Value"=>$Parameter_NewName,
 
12983
                                    "Old_Value"=>$PName,
 
12984
                                    "New_Value"=>$PName_New,
11971
12985
                                    "New_Signature"=>get_Signature($Symbol, 2)  );
11972
12986
                            }
11973
12987
                        }
11974
12988
                        else
11975
12989
                        {
11976
12990
                            my $ProblemType = "Removed_Middle_Parameter";
11977
 
                            if($Parameter_Name=~/\Ap\d+\Z/) {
 
12991
                            if($PName=~/\Ap\d+\Z/) {
11978
12992
                                $ProblemType = "Removed_Middle_Unnamed_Parameter";
11979
12993
                            }
11980
12994
                            %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
11981
 
                                "Target"=>$Parameter_Name,
 
12995
                                "Target"=>$PName,
11982
12996
                                "Param_Pos"=>$ParamPos,
11983
12997
                                "Param_Type"=>$PType1_Name,
11984
12998
                                "New_Signature"=>get_Signature($Symbol, 2)  );
11991
13005
        my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11992
13006
        my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11993
13007
        %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
 
13008
        
11994
13009
        foreach my $SubProblemType (keys(%SubProblems))
11995
13010
        {
11996
13011
            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11997
13012
            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11998
 
            my $NewProblemType = $SubProblemType;
11999
 
            if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
12000
 
            and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12001
 
            { # parameters stack has been affected
12002
 
                $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12003
 
            }
12004
 
            elsif($Level eq "Binary"
12005
 
            and $SubProblemType eq "Return_Type_From_Void")
12006
 
            { # parameters stack has been affected
12007
 
                if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
12008
 
                    $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12009
 
                }
12010
 
                else
12011
 
                { # safe
12012
 
                    delete($SubProblems{$SubProblemType});
12013
 
                    next;
12014
 
                }
12015
 
            }
12016
 
            elsif($SubProblemType eq "Return_Type_And_Size"
12017
 
            and $CompleteSignature{1}{$Symbol}{"Data"}) {
12018
 
                $NewProblemType = "Global_Data_Type_And_Size";
12019
 
            }
12020
 
            elsif($SubProblemType eq "Return_Type")
12021
 
            {
12022
 
                if($CompleteSignature{1}{$Symbol}{"Data"})
12023
 
                {
12024
 
                    if(removedQual($Old_Value, $New_Value, "const"))
12025
 
                    { # const -> non-const global data
12026
 
                        $NewProblemType = "Global_Data_Became_Non_Const";
12027
 
                    }
12028
 
                    elsif(addedQual($Old_Value, $New_Value, "const"))
12029
 
                    { # non-const -> const global data
12030
 
                        $NewProblemType = "Global_Data_Became_Const";
12031
 
                    }
12032
 
                    else {
12033
 
                        $NewProblemType = "Global_Data_Type";
12034
 
                    }
12035
 
                }
12036
 
                else
12037
 
                {
12038
 
                    if(addedQual($Old_Value, $New_Value, "const")) {
12039
 
                        $NewProblemType = "Return_Type_Became_Const";
12040
 
                    }
12041
 
                }
12042
 
            }
12043
 
            elsif($SubProblemType eq "Return_Type_Format")
12044
 
            {
12045
 
                if($CompleteSignature{1}{$Symbol}{"Data"}) {
12046
 
                    $NewProblemType = "Global_Data_Type_Format";
12047
 
                }
12048
 
            }
12049
 
            @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
 
13013
            my %ProblemTypes = ();
 
13014
            
 
13015
            if($CompleteSignature{1}{$Symbol}{"Data"})
 
13016
            {
 
13017
                if($SubProblemType eq "Return_Type_And_Size") {
 
13018
                    $ProblemTypes{"Global_Data_Type_And_Size"} = 1;
 
13019
                }
 
13020
                elsif($SubProblemType eq "Return_Type_Format") {
 
13021
                    $ProblemTypes{"Global_Data_Type_Format"} = 1;
 
13022
                }
 
13023
                else {
 
13024
                    $ProblemTypes{"Global_Data_Type"} = 1;
 
13025
                }
 
13026
                
 
13027
                # quals
 
13028
                if($SubProblemType eq "Return_Type"
 
13029
                or $SubProblemType eq "Return_Type_And_Size"
 
13030
                or $SubProblemType eq "Return_Type_Format")
 
13031
                {
 
13032
                    if(my $RR = removedQual($Old_Value, $New_Value, "const"))
 
13033
                    { # const to non-const
 
13034
                        if($RR==2) {
 
13035
                            $ProblemTypes{"Global_Data_Removed_Const"} = 1;
 
13036
                        }
 
13037
                        else {
 
13038
                            $ProblemTypes{"Global_Data_Became_Non_Const"} = 1;
 
13039
                        }
 
13040
                        $ProblemTypes{"Global_Data_Type"} = 1;
 
13041
                    }
 
13042
                    elsif(my $RA = addedQual($Old_Value, $New_Value, "const"))
 
13043
                    { # non-const to const
 
13044
                        if($RA==2) {
 
13045
                            $ProblemTypes{"Global_Data_Added_Const"} = 1;
 
13046
                        }
 
13047
                        else {
 
13048
                            $ProblemTypes{"Global_Data_Became_Const"} = 1;
 
13049
                        }
 
13050
                        $ProblemTypes{"Global_Data_Type"} = 1;
 
13051
                    }
 
13052
                }
 
13053
            }
 
13054
            else
 
13055
            {
 
13056
                # quals
 
13057
                if($SubProblemType eq "Return_Type"
 
13058
                or $SubProblemType eq "Return_Type_And_Size"
 
13059
                or $SubProblemType eq "Return_Type_Format")
 
13060
                {
 
13061
                    if(checkDump(1, "2.6") and checkDump(2, "2.6"))
 
13062
                    {
 
13063
                        if(addedQual($Old_Value, $New_Value, "volatile"))
 
13064
                        {
 
13065
                            $ProblemTypes{"Return_Value_Became_Volatile"} = 1;
 
13066
                            if($Level ne "Source"
 
13067
                            or not cmpBTypes($Old_Value, $New_Value, 1, 2)) {
 
13068
                                $ProblemTypes{"Return_Type"} = 1;
 
13069
                            }
 
13070
                        }
 
13071
                    }
 
13072
                    if(my $RA = addedQual($Old_Value, $New_Value, "const"))
 
13073
                    {
 
13074
                        if($RA==2) {
 
13075
                            $ProblemTypes{"Return_Type_Added_Const"} = 1;
 
13076
                        }
 
13077
                        else {
 
13078
                            $ProblemTypes{"Return_Type_Became_Const"} = 1;
 
13079
                        }
 
13080
                        if($Level ne "Source"
 
13081
                        or not cmpBTypes($Old_Value, $New_Value, 1, 2)) {
 
13082
                            $ProblemTypes{"Return_Type"} = 1;
 
13083
                        }
 
13084
                    }
 
13085
                }
 
13086
            }
 
13087
            if($Level eq "Binary"
 
13088
            and not $CompleteSignature{1}{$Symbol}{"Data"})
 
13089
            {
 
13090
                my ($Arch1, $Arch2) = (getArch(1), getArch(2));
 
13091
                if($Arch1 eq "unknown" or $Arch2 eq "unknown")
 
13092
                { # if one of the architectures is unknown
 
13093
                    # then set other arhitecture to unknown too
 
13094
                    ($Arch1, $Arch2) = ("unknown", "unknown");
 
13095
                }
 
13096
                my (%Conv1, %Conv2) = ();
 
13097
                if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"})
 
13098
                {
 
13099
                    %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
 
13100
                    %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
 
13101
                }
 
13102
                else
 
13103
                {
 
13104
                    %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
 
13105
                    %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
 
13106
                }
 
13107
                
 
13108
                if($SubProblemType eq "Return_Type_Became_Void")
 
13109
                {
 
13110
                    if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
 
13111
                    { # parameters stack has been affected
 
13112
                        if($Conv1{"Method"} eq "stack") {
 
13113
                            $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1;
 
13114
                        }
 
13115
                        elsif($Conv1{"Hidden"}) {
 
13116
                            $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1;
 
13117
                        }
 
13118
                    }
 
13119
                }
 
13120
                elsif($SubProblemType eq "Return_Type_From_Void")
 
13121
                {
 
13122
                    if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
 
13123
                    { # parameters stack has been affected
 
13124
                        if($Conv2{"Method"} eq "stack") {
 
13125
                            $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1;
 
13126
                        }
 
13127
                        elsif($Conv2{"Hidden"}) {
 
13128
                            $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1;
 
13129
                        }
 
13130
                    }
 
13131
                }
 
13132
                elsif($SubProblemType eq "Return_Type"
 
13133
                or $SubProblemType eq "Return_Type_And_Size"
 
13134
                or $SubProblemType eq "Return_Type_Format")
 
13135
                {
 
13136
                    if($Conv1{"Method"} ne $Conv2{"Method"})
 
13137
                    {
 
13138
                        if($Conv1{"Method"} eq "stack")
 
13139
                        { # returns in a register instead of a hidden first parameter
 
13140
                            $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1;
 
13141
                        }
 
13142
                        else {
 
13143
                            $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1;
 
13144
                        }
 
13145
                    }
 
13146
                    else
 
13147
                    {
 
13148
                        if($Conv1{"Method"} eq "reg")
 
13149
                        {
 
13150
                            if($Conv1{"Registers"} ne $Conv2{"Registers"})
 
13151
                            {
 
13152
                                if($Conv1{"Hidden"}) {
 
13153
                                    $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1;
 
13154
                                }
 
13155
                                elsif($Conv2{"Hidden"}) {
 
13156
                                    $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1;
 
13157
                                }
 
13158
                                else {
 
13159
                                    $ProblemTypes{"Return_Type_And_Register"} = 1;
 
13160
                                }
 
13161
                            }
 
13162
                        }
 
13163
                    }
 
13164
                }
 
13165
            }
 
13166
            
 
13167
            if(not keys(%ProblemTypes))
 
13168
            { # default
 
13169
                $ProblemTypes{$SubProblemType} = 1;
 
13170
            }
 
13171
            
 
13172
            foreach my $ProblemType (keys(%ProblemTypes))
 
13173
            { # additional
 
13174
                @{$CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
 
13175
            }
12050
13176
        }
12051
13177
        if($ReturnType1_Id and $ReturnType2_Id)
12052
13178
        {
12053
13179
            @RecurTypes = ();
12054
13180
            %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
12055
 
            foreach my $SubProblemType (keys(%SubProblems))
12056
 
            { # add "Global_Data_Size" problem
12057
 
                my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12058
 
                my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12059
 
                if($SubProblemType eq "DataType_Size"
12060
 
                and $CompleteSignature{1}{$Symbol}{"Data"}
12061
 
                and get_PLevel($ReturnType1_Id, 1)==0)
12062
 
                { # add a new problem
12063
 
                    %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
 
13181
            
 
13182
            if($CompleteSignature{1}{$Symbol}{"Data"})
 
13183
            {
 
13184
                if($Level eq "Binary")
 
13185
                {
 
13186
                    if(get_PLevel($ReturnType1_Id, 1)==0)
 
13187
                    {
 
13188
                        foreach my $SubProblemType (keys(%SubProblems))
 
13189
                        { # add "Global_Data_Size" problem
 
13190
                            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
 
13191
                            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
 
13192
                            if($SubProblemType eq "DataType_Size")
 
13193
                            { # add a new problem
 
13194
                                %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
 
13195
                            }
 
13196
                        }
 
13197
                    }
 
13198
                    if(not defined $SubProblems{"Global_Data_Size"})
 
13199
                    {
 
13200
                        if(defined $GlobalDataObject{1}{$Symbol}
 
13201
                        and defined $GlobalDataObject{2}{$Symbol})
 
13202
                        {
 
13203
                            my $Old_Size = $GlobalDataObject{1}{$Symbol};
 
13204
                            my $New_Size = $GlobalDataObject{2}{$Symbol};
 
13205
                            if($Old_Size!=$New_Size)
 
13206
                            {
 
13207
                                %{$SubProblems{"Global_Data_Size"}{"retval"}} = (
 
13208
                                    "Old_Size"=>$Old_Size*$BYTE_SIZE,
 
13209
                                    "New_Size"=>$New_Size*$BYTE_SIZE );
 
13210
                            }
 
13211
                        }
 
13212
                    }
12064
13213
                }
12065
13214
            }
12066
13215
            foreach my $SubProblemType (keys(%SubProblems))
12125
13274
        $Qual = "const|volatile|restrict";
12126
13275
    }
12127
13276
    while($Value=~s/\b$Qual\b//) {
12128
 
        $Value = formatName($Value);
 
13277
        $Value = formatName($Value, "T");
12129
13278
    }
12130
13279
    return $Value;
12131
13280
}
12141
13290
sub addedQual($$$)
12142
13291
{
12143
13292
    my ($Old_Value, $New_Value, $Qual) = @_;
12144
 
    return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
 
13293
    return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual);
12145
13294
}
12146
13295
 
12147
13296
sub removedQual($$$)
12148
13297
{
12149
13298
    my ($Old_Value, $New_Value, $Qual) = @_;
12150
 
    return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
 
13299
    return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual);
12151
13300
}
12152
13301
 
12153
 
sub removedQual_($$$$$)
 
13302
sub removedQual_I($$$$$)
12154
13303
{
12155
13304
    my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12156
13305
    $Old_Value = uncover_typedefs($Old_Value, $V1);
12217
13366
    return @Model;
12218
13367
}
12219
13368
 
 
13369
my %StringTypes = map {$_=>1} (
 
13370
    "char*",
 
13371
    "char const*"
 
13372
);
 
13373
 
 
13374
my %CharTypes = map {$_=>1} (
 
13375
    "char",
 
13376
    "char const"
 
13377
);
 
13378
 
12220
13379
sub showVal($$$)
12221
13380
{
12222
13381
    my ($Value, $TypeId, $LibVersion) = @_;
12223
 
    my %PureType = get_PureType($TypeId, $LibVersion);
12224
 
    if($PureType{"Name"}=~/\A(char(| const)\*|std::string(|&))\Z/)
 
13382
    my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
 
13383
    my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
 
13384
    if(substr($Value, 0, 2) eq "_Z")
 
13385
    {
 
13386
        if(my $Unmangled = $tr_name{$Value}) {
 
13387
            return $Unmangled;
 
13388
        }
 
13389
    }
 
13390
    elsif(defined $StringTypes{$TName} or $TName=~/string/i)
12225
13391
    { # strings
12226
13392
        return "\"$Value\"";
12227
13393
    }
12228
 
    elsif($PureType{"Name"}=~/\Achar(| const)\Z/)
 
13394
    elsif(defined $CharTypes{$TName})
12229
13395
    { # characters
12230
13396
        return "\'$Value\'";
12231
13397
    }
 
13398
    if($Value eq "")
 
13399
    { # other
 
13400
        return "\'\'";
 
13401
    }
12232
13402
    return $Value;
12233
13403
}
12234
13404
 
12235
 
sub mergeParameters($$$$$)
12236
 
{
12237
 
    my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
 
13405
sub getRegs($$$)
 
13406
{
 
13407
    my ($LibVersion, $Symbol, $Pos) = @_;
 
13408
    
 
13409
    if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"})
 
13410
    {
 
13411
        my %Regs = ();
 
13412
        foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}}))
 
13413
        {
 
13414
            if($Elem=~/\A$Pos([\.\+]|\Z)/) {
 
13415
                $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1;
 
13416
            }
 
13417
        }
 
13418
        
 
13419
        return join(", ", sort keys(%Regs));
 
13420
    }
 
13421
    
 
13422
    return undef;
 
13423
}
 
13424
 
 
13425
sub mergeParameters($$$$$$)
 
13426
{
 
13427
    my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_;
12238
13428
    if(not $Symbol) {
12239
13429
        return;
12240
13430
    }
12246
13436
    or not $PType2_Id) {
12247
13437
        return;
12248
13438
    }
 
13439
    
 
13440
    if(index($Symbol, "_Z")==0)
 
13441
    { # do not merge this
 
13442
        if($PName1 eq "this" or $PName2 eq "this") {
 
13443
            return;
 
13444
        }
 
13445
    }
 
13446
    
12249
13447
    my %Type1 = get_Type($PType1_Id, 1);
12250
13448
    my %Type2 = get_Type($PType2_Id, 2);
12251
13449
    my %BaseType1 = get_BaseType($PType1_Id, 1);
12252
13450
    my %BaseType2 = get_BaseType($PType2_Id, 2);
12253
13451
    my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
 
13452
    
12254
13453
    if($Level eq "Binary")
12255
13454
    {
12256
13455
        if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
12270
13469
                    "Param_Pos"=>$ParamPos1  );
12271
13470
            }
12272
13471
        }
 
13472
        
 
13473
        if(defined $UsedDump{1}{"DWARF"}
 
13474
        and defined $UsedDump{2}{"DWARF"})
 
13475
        {
 
13476
            if(checkDump(1, "3.0") and checkDump(2, "3.0"))
 
13477
            {
 
13478
                my $Old_Regs = getRegs(1, $Symbol, $ParamPos1);
 
13479
                my $New_Regs = getRegs(2, $PSymbol, $ParamPos2);
 
13480
                if($Old_Regs and $New_Regs)
 
13481
                {
 
13482
                    if($Old_Regs ne $New_Regs)
 
13483
                    {
 
13484
                        %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=(
 
13485
                            "Target"=>$PName1,
 
13486
                            "Param_Pos"=>$ParamPos1,
 
13487
                            "Old_Value"=>$Old_Regs,
 
13488
                            "New_Value"=>$New_Regs  );
 
13489
                    }
 
13490
                }
 
13491
                elsif($Old_Regs and not $New_Regs)
 
13492
                {
 
13493
                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=(
 
13494
                        "Target"=>$PName1,
 
13495
                        "Param_Pos"=>$ParamPos1,
 
13496
                        "Old_Value"=>$Old_Regs  );
 
13497
                }
 
13498
                elsif(not $Old_Regs and $New_Regs)
 
13499
                {
 
13500
                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=(
 
13501
                        "Target"=>$PName1,
 
13502
                        "Param_Pos"=>$ParamPos1,
 
13503
                        "New_Value"=>$New_Regs  );
 
13504
                }
 
13505
                if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne ""
 
13506
                and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "")
 
13507
                {
 
13508
                    if($Old_Offset ne $New_Offset)
 
13509
                    {
 
13510
                        %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=(
 
13511
                            "Target"=>$PName1,
 
13512
                            "Param_Pos"=>$ParamPos1,
 
13513
                            "Old_Value"=>$Old_Offset,
 
13514
                            "New_Value"=>$New_Offset  );
 
13515
                    }
 
13516
                }
 
13517
            }
 
13518
        }
12273
13519
    }
12274
13520
    if(checkDump(1, "2.0") and checkDump(2, "2.0"))
12275
13521
    { # "default" attribute added in ACC 1.22 (dump 2.0 format)
12289
13535
                }
12290
13536
            }
12291
13537
        }
 
13538
        if(not checkDump(1, "2.18")
 
13539
        and checkDump(2, "2.18"))
 
13540
        { # support for old ABI dumps
 
13541
            if(not defined $Value_Old
 
13542
            and substr($Value_New, 0, 2) eq "_Z") {
 
13543
                $Value_Old = $Value_New;
 
13544
            }
 
13545
        }
12292
13546
        if(defined $Value_Old)
12293
13547
        {
12294
13548
            $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12321
13575
                "New_Value"=>$Value_New  );
12322
13576
        }
12323
13577
    }
12324
 
    if($PName1 and $PName2 and $PName1 ne $PName2
12325
 
    and $PType1_Id!=-1 and $PType2_Id!=-1
12326
 
    and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
12327
 
    { # except unnamed "..." value list (Id=-1)
12328
 
        %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
12329
 
            "Target"=>$PName1,
12330
 
            "Param_Pos"=>$ParamPos1,
12331
 
            "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
12332
 
            "Old_Value"=>$PName1,
12333
 
            "New_Value"=>$PName2,
12334
 
            "New_Signature"=>get_Signature($Symbol, 2)  );
 
13578
    
 
13579
    if($ChkRnmd)
 
13580
    {
 
13581
        if($PName1 and $PName2 and $PName1 ne $PName2
 
13582
        and $PType1_Id!=-1 and $PType2_Id!=-1
 
13583
        and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
 
13584
        { # except unnamed "..." value list (Id=-1)
 
13585
            %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
 
13586
                "Target"=>$PName1,
 
13587
                "Param_Pos"=>$ParamPos1,
 
13588
                "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
 
13589
                "Old_Value"=>$PName1,
 
13590
                "New_Value"=>$PName2,
 
13591
                "New_Signature"=>get_Signature($Symbol, 2)  );
 
13592
        }
12335
13593
    }
 
13594
    
12336
13595
    # checking type change (replace)
12337
13596
    my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
12338
13597
    foreach my $SubProblemType (keys(%SubProblems))
12339
13598
    { # add new problems, remove false alarms
12340
13599
        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12341
13600
        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12342
 
        if($SubProblemType eq "Parameter_Type")
 
13601
        
 
13602
        # quals
 
13603
        if($SubProblemType eq "Parameter_Type"
 
13604
        or $SubProblemType eq "Parameter_Type_And_Size"
 
13605
        or $SubProblemType eq "Parameter_Type_Format")
12343
13606
        {
12344
13607
            if(checkDump(1, "2.6") and checkDump(2, "2.6"))
12345
13608
            {
12346
 
                if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
12347
 
                {
 
13609
                if(addedQual($Old_Value, $New_Value, "restrict")) {
12348
13610
                    %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12349
 
                    if($Level eq "Source"
12350
 
                    and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
12351
 
                        delete($SubProblems{$SubProblemType});
12352
 
                    }
12353
 
                }
12354
 
                elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12355
 
                {
12356
 
                    %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12357
 
                    if($Level eq "Source"
12358
 
                    and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
12359
 
                        delete($SubProblems{$SubProblemType});
12360
 
                    }
 
13611
                }
 
13612
                elsif(removedQual($Old_Value, $New_Value, "restrict")) {
 
13613
                    %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}};
 
13614
                }
 
13615
            }
 
13616
            if(checkDump(1, "2.6") and checkDump(2, "2.6"))
 
13617
            {
 
13618
                if(removedQual($Old_Value, $New_Value, "volatile")) {
 
13619
                    %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}};
12361
13620
                }
12362
13621
            }
12363
13622
            if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12365
13624
            { # int to "int const"
12366
13625
                delete($SubProblems{$SubProblemType});
12367
13626
            }
12368
 
            if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
 
13627
            elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12369
13628
            and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12370
13629
            { # "int const" to int
12371
13630
                delete($SubProblems{$SubProblemType});
12372
13631
            }
12373
 
        }
12374
 
    }
 
13632
            elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
 
13633
            { # "const" to non-"const"
 
13634
                if($RR==2) {
 
13635
                    %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}};
 
13636
                }
 
13637
                else {
 
13638
                    %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}};
 
13639
                }
 
13640
            }
 
13641
        }
 
13642
    }
 
13643
    
 
13644
    if($Level eq "Source")
 
13645
    {
 
13646
        foreach my $SubProblemType (keys(%SubProblems))
 
13647
        {
 
13648
            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
 
13649
            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
 
13650
            
 
13651
            if($SubProblemType eq "Parameter_Type")
 
13652
            {
 
13653
                if(cmpBTypes($Old_Value, $New_Value, 1, 2)) {
 
13654
                    delete($SubProblems{$SubProblemType});
 
13655
                }
 
13656
            }
 
13657
        }
 
13658
    }
 
13659
    
12375
13660
    foreach my $SubProblemType (keys(%SubProblems))
12376
13661
    { # modify/register problems
12377
13662
        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12378
13663
        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
 
13664
        my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
 
13665
        my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
 
13666
        
12379
13667
        my $NewProblemType = $SubProblemType;
12380
13668
        if($Old_Value eq "..." and $New_Value ne "...")
12381
13669
        { # change from "..." to "int"
12383
13671
            { # ISO C requires a named argument before "..."
12384
13672
                next;
12385
13673
            }
12386
 
            $NewProblemType = "Parameter_Became_NonVaList";
 
13674
            $NewProblemType = "Parameter_Became_Non_VaList";
12387
13675
        }
12388
13676
        elsif($New_Value eq "..." and $Old_Value ne "...")
12389
13677
        { # change from "int" to "..."
12393
13681
            }
12394
13682
            $NewProblemType = "Parameter_Became_VaList";
12395
13683
        }
12396
 
        elsif($SubProblemType eq "Parameter_Type"
12397
 
        and removedQual($Old_Value, $New_Value, "const"))
12398
 
        { # parameter: "const" to non-"const"
12399
 
            $NewProblemType = "Parameter_Became_Non_Const";
12400
 
        }
12401
13684
        elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12402
 
        or $SubProblemType eq "Parameter_Type"))
 
13685
        or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
12403
13686
        {
12404
13687
            my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12405
 
            if($Arch1 eq "unknown" or $Arch2 eq "unknown")
 
13688
            if($Arch1 eq "unknown"
 
13689
            or $Arch2 eq "unknown")
12406
13690
            { # if one of the architectures is unknown
12407
 
                # then set other arhitecture to unknown too
 
13691
              # then set other arhitecture to unknown too
12408
13692
                ($Arch1, $Arch2) = ("unknown", "unknown");
12409
13693
            }
12410
 
            my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12411
 
            my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
12412
 
            if($Method1 eq $Method2)
12413
 
            {
12414
 
                if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12415
 
                    $NewProblemType = "Parameter_Type_And_Stack";
12416
 
                }
12417
 
                elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12418
 
                    $NewProblemType = "Parameter_Type_And_Register";
12419
 
                }
12420
 
            }
12421
 
            else
12422
 
            {
12423
 
                if($Method1 eq "stack") {
12424
 
                    $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12425
 
                }
12426
 
                elsif($Method1 eq "register") {
12427
 
                    $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12428
 
                }
12429
 
            }
12430
 
            $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12431
 
            $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
 
13694
            my (%Conv1, %Conv2) = ();
 
13695
            if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"})
 
13696
            { # real
 
13697
                %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
 
13698
                %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
 
13699
            }
 
13700
            else
 
13701
            { # model
 
13702
                %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
 
13703
                %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
 
13704
            }
 
13705
            if($Conv1{"Method"} eq $Conv2{"Method"})
 
13706
            {
 
13707
                if($Conv1{"Method"} eq "stack")
 
13708
                {
 
13709
                    if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
 
13710
                        $NewProblemType = "Parameter_Type_And_Stack";
 
13711
                    }
 
13712
                }
 
13713
                elsif($Conv1{"Method"} eq "reg")
 
13714
                {
 
13715
                    if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
 
13716
                        $NewProblemType = "Parameter_Type_And_Register";
 
13717
                    }
 
13718
                }
 
13719
            }
 
13720
            else
 
13721
            {
 
13722
                if($Conv1{"Method"} eq "stack") {
 
13723
                    $NewProblemType = "Parameter_Type_From_Stack_To_Register";
 
13724
                }
 
13725
                elsif($Conv1{"Method"} eq "register") {
 
13726
                    $NewProblemType = "Parameter_Type_From_Register_To_Stack";
 
13727
                }
 
13728
            }
 
13729
            $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
 
13730
            $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
12432
13731
        }
12433
13732
        %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
12434
13733
            "Target"=>$PName1,
12465
13764
    }
12466
13765
}
12467
13766
 
12468
 
sub callingConvention($$$$)
12469
 
{ # calling conventions for different compilers and operating systems
12470
 
    my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12471
 
    my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
12472
 
    my %Type = get_PureType($ParamTypeId, $LibVersion);
12473
 
    my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12474
 
    if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
12475
 
    { # GCC
12476
 
        if($Arch eq "x86")
12477
 
        { # System V ABI Intel386 ("Function Calling Sequence")
12478
 
          # The stack is word aligned. Although the architecture does not require any
12479
 
          # alignment of the stack, software convention and the operating system
12480
 
          # requires that the stack be aligned on a word boundary.
12481
 
 
12482
 
          # Argument words are pushed onto the stack in reverse order (that is, the
12483
 
          # rightmost argument in C call syntax has the highest address), preserving the
12484
 
          # stackā€™s word alignment. All incoming arguments appear on the stack, residing
12485
 
          # in the stack frame of the caller.
12486
 
 
12487
 
          # An argumentā€™s size is increased, if necessary, to make it a multiple of words.
12488
 
          # This may require tail padding, depending on the size of the argument.
12489
 
 
12490
 
          # Other areas depend on the compiler and the code being compiled. The stan-
12491
 
          # dard calling sequence does not define a maximum stack frame size, nor does
12492
 
          # it restrict how a language system uses the ā€˜ā€˜unspecifiedā€™ā€™ area of the stan-
12493
 
          # dard stack frame.
12494
 
            ($Method, $Alignment) = ("stack", 4);
12495
 
        }
12496
 
        elsif($Arch eq "x86_64")
12497
 
        { # System V AMD64 ABI ("Function Calling Sequence")
12498
 
            ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12499
 
        }
12500
 
        elsif($Arch eq "arm")
12501
 
        { # Procedure Call Standard for the ARM Architecture
12502
 
          # The stack must be double-word aligned
12503
 
            ($Method, $Alignment) = ("stack", 8);# double-word
12504
 
        }
12505
 
    }
12506
 
    elsif($OSgroup eq "windows")
12507
 
    { # MS C++ Compiler
12508
 
        if($Arch eq "x86")
12509
 
        {
12510
 
            if($ParamPos==0) {
12511
 
                ($Method, $Register, $Passed) = ("register", "ecx", "value");
12512
 
            }
12513
 
            elsif($ParamPos==1) {
12514
 
                ($Method, $Register, $Passed) = ("register", "edx", "value");
12515
 
            }
12516
 
            else {
12517
 
                ($Method, $Alignment) = ("stack", 4);
12518
 
            }
12519
 
        }
12520
 
        elsif($Arch eq "x86_64")
12521
 
        {
12522
 
            if($ParamPos<=3)
12523
 
            {
12524
 
                if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12525
 
                    ($Method, $Passed) = ("xmm".$ParamPos, "value");
12526
 
                }
12527
 
                elsif(isScalar($Type{"Name"})
12528
 
                or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12529
 
                or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12530
 
                {
12531
 
                    if($ParamPos==0) {
12532
 
                        ($Method, $Register, $Passed) = ("register", "rcx", "value");
12533
 
                    }
12534
 
                    elsif($ParamPos==1) {
12535
 
                        ($Method, $Register, $Passed) = ("register", "rdx", "value");
12536
 
                    }
12537
 
                    elsif($ParamPos==2) {
12538
 
                        ($Method, $Register, $Passed) = ("register", "r8", "value");
12539
 
                    }
12540
 
                    elsif($ParamPos==3) {
12541
 
                        ($Method, $Register, $Passed) = ("register", "r9", "value");
12542
 
                    }
12543
 
                    if($Type{"Size"}>64
12544
 
                    or $Type{"Type"} eq "Array") {
12545
 
                        $Passed = "pointer";
12546
 
                    }
12547
 
                }
12548
 
            }
12549
 
            else {
12550
 
                ($Method, $Alignment) = ("stack", 8);# word alignment
12551
 
            }
12552
 
        }
12553
 
    }
12554
 
    if($Method eq "register") {
12555
 
        return ("register", $Passed, "", $Register);
12556
 
    }
12557
 
    else
12558
 
    { # on the stack
12559
 
        if(not $Alignment)
12560
 
        { # default convention
12561
 
            $Alignment = $WORD_SIZE{$LibVersion};
12562
 
        }
12563
 
        if(not $Passed)
12564
 
        { # default convention
12565
 
            $Passed = "value";
12566
 
        }
12567
 
        my $SizeOnStack = $Type{"Size"};
12568
 
        # FIXME: improve stack alignment
12569
 
        if($SizeOnStack!=$Alignment) {
12570
 
            $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12571
 
        }
12572
 
        return ("stack", $Passed, $SizeOnStack, "");
12573
 
    }
12574
 
}
12575
 
 
12576
13767
sub find_ParamPair_Pos_byName($$$)
12577
13768
{
12578
13769
    my ($Name, $Symbol, $LibVersion) = @_;
12607
13798
sub getTypeIdByName($$)
12608
13799
{
12609
13800
    my ($TypeName, $Version) = @_;
12610
 
    return $TName_Tid{$Version}{formatName($TypeName)};
12611
 
}
12612
 
 
12613
 
sub checkFormatChange($$$)
 
13801
    return $TName_Tid{$Version}{formatName($TypeName, "T")};
 
13802
}
 
13803
 
 
13804
sub diffTypes($$$)
 
13805
{
 
13806
    if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) {
 
13807
        return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]};
 
13808
    }
 
13809
    if(isRecurType($_[0], $_[1], \@RecurTypes_Diff))
 
13810
    { # skip recursive declarations
 
13811
        return 0;
 
13812
    }
 
13813
    
 
13814
    pushType($_[0], $_[1], \@RecurTypes_Diff);
 
13815
    my $Diff = diffTypes_I(@_);
 
13816
    pop(@RecurTypes_Diff);
 
13817
    
 
13818
    return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff);
 
13819
}
 
13820
 
 
13821
sub diffTypes_I($$$)
12614
13822
{
12615
13823
    my ($Type1_Id, $Type2_Id, $Level) = @_;
12616
 
    my %Type1_Pure = get_PureType($Type1_Id, 1);
12617
 
    my %Type2_Pure = get_PureType($Type2_Id, 2);
 
13824
    
 
13825
    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
 
13826
    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
 
13827
    
12618
13828
    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12619
13829
    { # equal types
12620
13830
        return 0;
12621
13831
    }
 
13832
    if($Type1_Pure{"Name"} eq "void")
 
13833
    { # from void* to something
 
13834
        return 0;
 
13835
    }
12622
13836
    if($Type1_Pure{"Name"}=~/\*/
12623
13837
    or $Type2_Pure{"Name"}=~/\*/)
12624
13838
    { # compared in detectTypeChange()
12625
13839
        return 0;
12626
13840
    }
 
13841
    
12627
13842
    my %FloatType = map {$_=>1} (
12628
13843
        "float",
12629
13844
        "double",
12630
13845
        "long double"
12631
13846
    );
12632
 
    if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
 
13847
    
 
13848
    my $T1 = $Type1_Pure{"Type"};
 
13849
    my $T2 = $Type2_Pure{"Type"};
 
13850
    
 
13851
    if($T1 eq "Struct"
 
13852
    and $T2 eq "Class")
 
13853
    { # compare as data structures
 
13854
        $T2 = "Struct";
 
13855
    }
 
13856
    
 
13857
    if($T1 eq "Class"
 
13858
    and $T2 eq "Struct")
 
13859
    { # compare as data structures
 
13860
        $T1 = "Struct";
 
13861
    }
 
13862
    
 
13863
    if($T1 ne $T2)
12633
13864
    { # different types
12634
 
        if($Type1_Pure{"Type"} eq "Intrinsic"
12635
 
        and $Type2_Pure{"Type"} eq "Enum")
 
13865
        if($T1 eq "Intrinsic"
 
13866
        and $T2 eq "Enum")
12636
13867
        { # "int" to "enum"
12637
13868
            return 0;
12638
13869
        }
12639
 
        elsif($Type2_Pure{"Type"} eq "Intrinsic"
12640
 
        and $Type1_Pure{"Type"} eq "Enum")
 
13870
        elsif($T2 eq "Intrinsic"
 
13871
        and $T1 eq "Enum")
12641
13872
        { # "enum" to "int"
12642
13873
            return 0;
12643
13874
        }
12644
13875
        else
12645
 
        { # "union" to "struct"
 
13876
        { # union to struct
12646
13877
          #  ...
12647
13878
            return 1;
12648
13879
        }
12649
13880
    }
12650
13881
    else
12651
13882
    {
12652
 
        if($Type1_Pure{"Type"} eq "Intrinsic")
 
13883
        if($T1 eq "Intrinsic")
12653
13884
        {
12654
13885
            if($FloatType{$Type1_Pure{"Name"}}
12655
13886
            or $FloatType{$Type2_Pure{"Name"}})
12664
13895
                }
12665
13896
            }
12666
13897
        }
12667
 
        elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
 
13898
        elsif($T1=~/Class|Struct|Union|Enum/)
12668
13899
        {
12669
13900
            my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12670
13901
            my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
 
13902
            if(not @Membs1
 
13903
            or not @Membs2)
 
13904
            { # private
 
13905
                return 0;
 
13906
            }
12671
13907
            if($#Membs1!=$#Membs2)
12672
13908
            { # different number of elements
12673
13909
                return 1;
12674
13910
            }
12675
 
            if($Type1_Pure{"Type"} eq "Enum")
 
13911
            if($T1 eq "Enum")
12676
13912
            {
12677
13913
                foreach my $Pos (@Membs1)
12678
13914
                { # compare elements by name and value
12686
13922
            else
12687
13923
            {
12688
13924
                foreach my $Pos (@Membs1)
12689
 
                { # compare elements by type name
12690
 
                    my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12691
 
                    my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12692
 
                    if($MT1 ne $MT2)
12693
 
                    { # different types
12694
 
                        return 1;
12695
 
                    }
 
13925
                {
12696
13926
                    if($Level eq "Source")
12697
13927
                    {
12698
13928
                        if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12700
13930
                            return 1;
12701
13931
                        }
12702
13932
                    }
 
13933
                    
 
13934
                    my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}};
 
13935
                    my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}};
 
13936
                    
 
13937
                    if($MT1{"Name"} ne $MT2{"Name"}
 
13938
                    or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"}))
 
13939
                    {
 
13940
                        my $PL1 = get_PLevel($MT1{"Tid"}, 1);
 
13941
                        my $PL2 = get_PLevel($MT2{"Tid"}, 2);
 
13942
                        
 
13943
                        if($PL1 ne $PL2)
 
13944
                        { # different pointer level
 
13945
                            return 1;
 
13946
                        }
 
13947
                        
 
13948
                        # compare base types
 
13949
                        my %BT1 = get_BaseType($MT1{"Tid"}, 1);
 
13950
                        my %BT2 = get_BaseType($MT2{"Tid"}, 2);
 
13951
                        
 
13952
                        if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level))
 
13953
                        { # different types
 
13954
                            return 1;
 
13955
                        }
 
13956
                    }
12703
13957
                }
12704
13958
            }
12705
13959
        }
 
13960
        else
 
13961
        {
 
13962
            # TODO: arrays, etc.
 
13963
        }
12706
13964
    }
12707
13965
    return 0;
12708
13966
}
12709
13967
 
12710
 
sub isScalar($) {
12711
 
    return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12712
 
}
12713
 
 
12714
 
sub isFloat($) {
12715
 
    return ($_[0]=~/\A(float|double|long double)\Z/);
12716
 
}
12717
 
 
12718
13968
sub detectTypeChange($$$$)
12719
13969
{
12720
13970
    my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
12724
13974
    my %LocalProblems = ();
12725
13975
    my %Type1 = get_Type($Type1_Id, 1);
12726
13976
    my %Type2 = get_Type($Type2_Id, 2);
12727
 
    my %Type1_Pure = get_PureType($Type1_Id, 1);
12728
 
    my %Type2_Pure = get_PureType($Type2_Id, 2);
12729
 
    my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12730
 
    my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
 
13977
    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
 
13978
    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
 
13979
    my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
 
13980
    my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2);
 
13981
    
12731
13982
    my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12732
13983
    my $Type2_PLevel = get_PLevel($Type2_Id, 2);
12733
13984
    return () if(not $Type1{"Name"} or not $Type2{"Name"});
12737
13988
    and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12738
13989
    and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12739
13990
    { # base type change
12740
 
        if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12741
 
        and $Type1{"Name"} eq $Type2{"Name"})
12742
 
        { # will be reported in mergeTypes() as typedef problem
12743
 
            return ();
 
13991
        if($Type1{"Name"} eq $Type2{"Name"})
 
13992
        {
 
13993
            if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
 
13994
            { # will be reported in mergeTypes() as typedef problem
 
13995
                return ();
 
13996
            }
 
13997
            my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
 
13998
            my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
 
13999
            if(%Typedef_1 and %Typedef_2)
 
14000
            {
 
14001
                if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
 
14002
                and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
 
14003
                { # const Typedef
 
14004
                    return ();
 
14005
                }
 
14006
            }
12744
14007
        }
12745
14008
        if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12746
14009
        {
12747
14010
            if($Level eq "Binary"
12748
 
            and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
12749
 
            and $Type1_Base{"Size"} and $Type2_Base{"Size"})
 
14011
            and $Type1_Base{"Size"} and $Type2_Base{"Size"}
 
14012
            and $Type1_Base{"Size"} ne $Type2_Base{"Size"})
12750
14013
            {
12751
14014
                %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12752
14015
                    "Old_Value"=>$Type1_Base{"Name"},
12757
14020
            }
12758
14021
            else
12759
14022
            {
12760
 
                if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
 
14023
                if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
12761
14024
                { # format change
12762
14025
                    %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12763
14026
                        "Old_Value"=>$Type1_Base{"Name"},
12764
14027
                        "New_Value"=>$Type2_Base{"Name"},
 
14028
                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
 
14029
                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12765
14030
                        "InitialType_Type"=>$Type1_Pure{"Type"});
12766
14031
                }
12767
14032
                elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12769
14034
                    %{$LocalProblems{$Prefix."_BaseType"}}=(
12770
14035
                        "Old_Value"=>$Type1_Base{"Name"},
12771
14036
                        "New_Value"=>$Type2_Base{"Name"},
 
14037
                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
 
14038
                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12772
14039
                        "InitialType_Type"=>$Type1_Pure{"Type"});
12773
14040
                }
12774
14041
            }
12778
14045
    { # type change
12779
14046
        if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12780
14047
        {
12781
 
            if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12782
 
            and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12783
 
                # safe change
12784
 
            }
12785
 
            elsif($Level eq "Binary"
12786
 
            and $Prefix eq "Return"
 
14048
            if($Prefix eq "Return"
12787
14049
            and $Type1_Pure{"Name"} eq "void")
12788
14050
            {
12789
14051
                %{$LocalProblems{"Return_Type_From_Void"}}=(
12791
14053
                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12792
14054
                    "InitialType_Type"=>$Type1_Pure{"Type"});
12793
14055
            }
12794
 
            elsif($Level eq "Binary"
12795
 
            and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
12796
 
            and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12797
 
            { # returns into hidden first parameter instead of a register
12798
 
                
12799
 
                # System V ABI Intel386 ("Function Calling Sequence")
12800
 
                # A function that returns an integral or pointer value places its result in register %eax.
12801
 
 
12802
 
                # A floating-point return value appears on the top of the Intel387 register stack. The
12803
 
                # caller then must remove the value from the Intel387 stack, even if it doesnā€™t use the
12804
 
                # value.
12805
 
 
12806
 
                # If a function returns a structure or union, then the caller provides space for the
12807
 
                # return value and places its address on the stack as argument word zero. In effect,
12808
 
                # this address becomes a ā€˜ā€˜hiddenā€™ā€™ first argument.
12809
 
                
12810
 
                %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12811
 
                    "Old_Value"=>$Type1{"Name"},
12812
 
                    "New_Value"=>$Type2{"Name"},
12813
 
                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12814
 
                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12815
 
                    "InitialType_Type"=>$Type1_Pure{"Type"});
12816
 
            }
12817
14056
            elsif($Prefix eq "Return"
12818
14057
            and $Type2_Pure{"Name"} eq "void")
12819
14058
            {
12822
14061
                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12823
14062
                    "InitialType_Type"=>$Type1_Pure{"Type"});
12824
14063
            }
12825
 
            elsif($Level eq "Binary" and $Prefix eq "Return"
12826
 
            and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12827
 
            or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12828
 
            { # The scalar and floating-point values are passed in different registers
12829
 
                %{$LocalProblems{"Return_Type_And_Register"}}=(
12830
 
                    "Old_Value"=>$Type1{"Name"},
12831
 
                    "New_Value"=>$Type2{"Name"},
12832
 
                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12833
 
                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12834
 
                    "InitialType_Type"=>$Type1_Pure{"Type"});
12835
 
            }
12836
 
            elsif($Level eq "Binary"
12837
 
            and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
12838
 
            and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12839
 
            { # returns in a register instead of a hidden first parameter
12840
 
                %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12841
 
                    "Old_Value"=>$Type1{"Name"},
12842
 
                    "New_Value"=>$Type2{"Name"},
12843
 
                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12844
 
                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12845
 
                    "InitialType_Type"=>$Type1_Pure{"Type"});
12846
 
            }
12847
14064
            else
12848
14065
            {
12849
14066
                if($Level eq "Binary"
12859
14076
                }
12860
14077
                else
12861
14078
                {
12862
 
                    if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
 
14079
                    if(diffTypes($Type1_Id, $Type2_Id, $Level))
12863
14080
                    { # format change
12864
14081
                        %{$LocalProblems{$Prefix."_Type_Format"}}=(
12865
14082
                            "Old_Value"=>$Type1{"Name"},
12866
14083
                            "New_Value"=>$Type2{"Name"},
 
14084
                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
 
14085
                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12867
14086
                            "InitialType_Type"=>$Type1_Pure{"Type"});
12868
14087
                    }
12869
14088
                    elsif(tNameLock($Type1_Id, $Type2_Id))
12871
14090
                        %{$LocalProblems{$Prefix."_Type"}}=(
12872
14091
                            "Old_Value"=>$Type1{"Name"},
12873
14092
                            "New_Value"=>$Type2{"Name"},
 
14093
                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
 
14094
                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12874
14095
                            "InitialType_Type"=>$Type1_Pure{"Type"});
12875
14096
                    }
12876
14097
                }
12890
14111
            }
12891
14112
            else
12892
14113
            {
12893
 
                if($Type2_PLevel>$Type1_PLevel) {
 
14114
                if($Type2_PLevel>$Type1_PLevel)
 
14115
                {
12894
14116
                    %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
12895
14117
                        "Old_Value"=>$Type1_PLevel,
12896
14118
                        "New_Value"=>$Type2_PLevel);
12897
14119
                }
12898
 
                else {
 
14120
                else
 
14121
                {
12899
14122
                    %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
12900
14123
                        "Old_Value"=>$Type1_PLevel,
12901
14124
                        "New_Value"=>$Type2_PLevel);
12929
14152
    }
12930
14153
    elsif(differentDumps("V"))
12931
14154
    { # different versions of ABI dumps
12932
 
        if(not checkDump(1, "2.13")
12933
 
        or not checkDump(2, "2.13"))
 
14155
        if(not checkDump(1, "2.20")
 
14156
        or not checkDump(2, "2.20"))
12934
14157
        { # latest names update
12935
14158
          # 2.6: added restrict qualifier
12936
14159
          # 2.13: added missed typedefs to qualified types
 
14160
          # 2.20: prefix for struct, union and enum types
12937
14161
            $Changed = 1;
12938
14162
        }
12939
14163
    }
 
14164
    
 
14165
    my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
 
14166
    my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
 
14167
    
12940
14168
    if($Changed)
12941
14169
    { # different formats
12942
14170
        if($UseOldDumps)
12943
14171
        { # old dumps
12944
14172
            return 0;
12945
14173
        }
12946
 
        my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
12947
 
        my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
12948
14174
        
12949
14175
        my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
12950
14176
        my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
12951
14177
        
12952
14178
        my %Base1 = get_Type($Tid1, 1);
12953
14179
        while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
12954
 
            %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
 
14180
            %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
12955
14181
        }
12956
14182
        my %Base2 = get_Type($Tid2, 2);
12957
14183
        while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
12958
 
            %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
 
14184
            %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
12959
14185
        }
12960
14186
        my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
12961
14187
        my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
12968
14194
        or not checkDump(2, "2.13"))
12969
14195
        { # broken array names in ABI dumps < 2.13
12970
14196
            if($TT1 eq "Array"
12971
 
            and $TT2 eq "Array")
12972
 
            {
 
14197
            and $TT2 eq "Array") {
12973
14198
                return 0;
12974
14199
            }
12975
14200
        }
12978
14203
        or not checkDump(2, "2.6"))
12979
14204
        { # added restrict attribute in 2.6
12980
14205
            if($TN1!~/\brestrict\b/
12981
 
            and $TN2=~/\brestrict\b/)
12982
 
            {
 
14206
            and $TN2=~/\brestrict\b/) {
 
14207
                return 0;
 
14208
            }
 
14209
        }
 
14210
        
 
14211
        if(not checkDump(1, "2.20")
 
14212
        or not checkDump(2, "2.20"))
 
14213
        { # added restrict attribute in 2.6
 
14214
            if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/
 
14215
            or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
 
14216
                return 0;
 
14217
            }
 
14218
        }
 
14219
    }
 
14220
    else
 
14221
    {
 
14222
        # typedef struct {...} type_t
 
14223
        # typedef struct type_t {...} type_t
 
14224
        if(index($TN1, " ".$TN2)!=-1)
 
14225
        {
 
14226
            if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) {
 
14227
                return 0;
 
14228
            }
 
14229
        }
 
14230
        if(index($TN2, " ".$TN1)!=-1)
 
14231
        {
 
14232
            if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
12983
14233
                return 0;
12984
14234
            }
12985
14235
        }
13024
14274
sub htmlSpecChars($)
13025
14275
{
13026
14276
    my $Str = $_[0];
13027
 
    if($Str eq "") {
13028
 
        return "";
 
14277
    if(not $Str) {
 
14278
        return $Str;
13029
14279
    }
13030
14280
    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13031
14281
    $Str=~s/</&lt;/g;
13032
14282
    $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13033
14283
    $Str=~s/>/&gt;/g;
13034
 
    $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
 
14284
    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
 
14285
    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
13035
14286
    $Str=~s/ /&#160;/g; # &nbsp;
13036
 
    $Str=~s/\@ALONE_SP\@/ /g;
 
14287
    $Str=~s/\@SP\@/ /g;
13037
14288
    $Str=~s/\n/<br\/>/g;
13038
14289
    $Str=~s/\"/&quot;/g;
13039
14290
    $Str=~s/\'/&#39;/g;
13040
14291
    return $Str;
13041
14292
}
13042
14293
 
 
14294
sub xmlSpecChars($)
 
14295
{
 
14296
    my $Str = $_[0];
 
14297
    if(not $Str) {
 
14298
        return $Str;
 
14299
    }
 
14300
    
 
14301
    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
 
14302
    $Str=~s/</&lt;/g;
 
14303
    $Str=~s/>/&gt;/g;
 
14304
    
 
14305
    $Str=~s/\"/&quot;/g;
 
14306
    $Str=~s/\'/&#39;/g;
 
14307
    
 
14308
    return $Str;
 
14309
}
 
14310
 
 
14311
sub xmlSpecChars_R($)
 
14312
{
 
14313
    my $Str = $_[0];
 
14314
    if(not $Str) {
 
14315
        return $Str;
 
14316
    }
 
14317
    
 
14318
    $Str=~s/&amp;/&/g;
 
14319
    $Str=~s/&lt;/</g;
 
14320
    $Str=~s/&gt;/>/g;
 
14321
    
 
14322
    $Str=~s/&quot;/"/g;
 
14323
    $Str=~s/&#39;/'/g;
 
14324
    
 
14325
    return $Str;
 
14326
}
 
14327
 
13043
14328
sub black_name($)
13044
14329
{
13045
14330
    my $Name = $_[0];
13092
14377
    if(not $SCenter)
13093
14378
    { # global data
13094
14379
        $Signature = htmlSpecChars($Signature);
13095
 
        $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
 
14380
        $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g;
13096
14381
        $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
13097
14382
        if($Return and $ShowReturn) {
13098
14383
            $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
13103
14388
    $Begin.=" " if($Begin!~/ \Z/);
13104
14389
    $End = cut_f_attrs($Signature);
13105
14390
    my @Parts = ();
13106
 
    my @SParts = get_s_params($Signature, 1);
 
14391
    my ($Short, $Params) = split_Signature($Signature);
 
14392
    my @SParts = separate_Params($Params, 1, 1);
13107
14393
    foreach my $Pos (0 .. $#SParts)
13108
14394
    {
13109
14395
        my $Part = $SParts[$Pos];
13115
14401
        elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13116
14402
            $ParamName = $1;
13117
14403
        }
13118
 
        if(not $ParamName) {
 
14404
        if(not $ParamName)
 
14405
        {
13119
14406
            push(@Parts, $Part_Styled);
13120
14407
            next;
13121
14408
        }
13157
14444
    }
13158
14445
    $Signature=~s!\[\]![&#160;]!g;
13159
14446
    $Signature=~s!operator=!operator&#160;=!g;
13160
 
    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13161
 
    return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
13162
 
}
13163
 
 
13164
 
sub get_s_params($$)
13165
 
{
13166
 
    my ($Signature, $Comma) = @_;
13167
 
    my @Parts = ();
13168
 
    my $ShortName = substr($Signature, 0, find_center($Signature, "("));
13169
 
    $Signature=~s/\A\Q$ShortName\E\(//g;
13170
 
    cut_f_attrs($Signature);
13171
 
    $Signature=~s/\)\Z//;
13172
 
    return separate_params($Signature, $Comma);
13173
 
}
13174
 
 
13175
 
sub separate_params($$)
13176
 
{
13177
 
    my ($Params, $Comma) = @_;
 
14447
    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g;
 
14448
    if($SymbolVersion) {
 
14449
        $Signature .= "<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>";
 
14450
    }
 
14451
    return $Signature;
 
14452
}
 
14453
 
 
14454
sub split_Signature($)
 
14455
{
 
14456
    my $Signature = $_[0];
 
14457
    if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
 
14458
    {
 
14459
        $Signature=~s/\A\Q$ShortName\E\(//g;
 
14460
        cut_f_attrs($Signature);
 
14461
        $Signature=~s/\)\Z//;
 
14462
        return ($ShortName, $Signature);
 
14463
    }
 
14464
    
 
14465
    # error
 
14466
    return ($Signature, "");
 
14467
}
 
14468
 
 
14469
sub separate_Params($$$)
 
14470
{
 
14471
    my ($Params, $Comma, $Sp) = @_;
13178
14472
    my @Parts = ();
13179
14473
    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13180
14474
    my $Part = 0;
13182
14476
    {
13183
14477
        my $S = substr($Params, $Pos, 1);
13184
14478
        if(defined $B{$S}) {
13185
 
            $B{$S}+=1;
 
14479
            $B{$S} += 1;
13186
14480
        }
13187
14481
        if($S eq "," and
13188
14482
        $B{"("}==$B{")"} and $B{"<"}==$B{">"})
13197
14491
            $Parts[$Part] .= $S;
13198
14492
        }
13199
14493
    }
 
14494
    if(not $Sp)
 
14495
    { # remove spaces
 
14496
        foreach (@Parts)
 
14497
        {
 
14498
            s/\A //g;
 
14499
            s/ \Z//g;
 
14500
        }
 
14501
    }
13200
14502
    return @Parts;
13201
14503
}
13202
14504
 
13346
14648
 
13347
14649
sub get_OSgroup()
13348
14650
{
13349
 
    $_ = $Config{"osname"};
13350
 
    if(/macos|darwin|rhapsody/i) {
 
14651
    my $N = $Config{"osname"};
 
14652
    if($N=~/macos|darwin|rhapsody/i) {
13351
14653
        return "macos";
13352
14654
    }
13353
 
    elsif(/freebsd|openbsd|netbsd/i) {
 
14655
    elsif($N=~/freebsd|openbsd|netbsd/i) {
13354
14656
        return "bsd";
13355
14657
    }
13356
 
    elsif(/haiku|beos/i) {
 
14658
    elsif($N=~/haiku|beos/i) {
13357
14659
        return "beos";
13358
14660
    }
13359
 
    elsif(/symbian|epoc/i) {
 
14661
    elsif($N=~/symbian|epoc/i) {
13360
14662
        return "symbian";
13361
14663
    }
13362
 
    elsif(/win/i) {
 
14664
    elsif($N=~/win/i) {
13363
14665
        return "windows";
13364
14666
    }
13365
14667
    else {
13366
 
        return $_;
 
14668
        return $N;
13367
14669
    }
13368
14670
}
13369
14671
 
13417
14719
        $Arch = $1;
13418
14720
    }
13419
14721
    $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13420
 
    if($OSgroup eq "windows") {
 
14722
    if($OSgroup eq "windows")
 
14723
    {
13421
14724
        $Arch = "x86" if($Arch=~/win32|mingw32/i);
13422
14725
        $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13423
14726
    }
13456
14759
 
13457
14760
sub get_SourceInfo()
13458
14761
{
13459
 
    my ($CheckedHeaders, $CheckedLibs) = ("", "");
 
14762
    my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", "");
13460
14763
    if(not $CheckObjectsOnly)
13461
14764
    {
13462
 
        $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13463
 
        $CheckedHeaders .= "<div class='h_list'>\n";
13464
 
        foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13465
 
        {
13466
 
            my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13467
 
            my $Header_Name = get_filename($Identity);
13468
 
            my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13469
 
            $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13470
 
        }
13471
 
        $CheckedHeaders .= "</div>\n";
13472
 
        $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
 
14765
        if(my @Headers = keys(%{$Registered_Headers{1}}))
 
14766
        {
 
14767
            $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".($#Headers+1).")</h2><hr/>\n";
 
14768
            $CheckedHeaders .= "<div class='h_list'>\n";
 
14769
            foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers)
 
14770
            {
 
14771
                my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
 
14772
                my $Name = get_filename($Identity);
 
14773
                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
 
14774
                $CheckedHeaders .= $Name.$Comment."<br/>\n";
 
14775
            }
 
14776
            $CheckedHeaders .= "</div>\n";
 
14777
            $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
 
14778
        }
 
14779
        
 
14780
        if(my @Sources = keys(%{$Registered_Sources{1}}))
 
14781
        {
 
14782
            $CheckedSources = "<a name='Sources'></a><h2>Source Files (".($#Sources+1).")</h2><hr/>\n";
 
14783
            $CheckedSources .= "<div class='h_list'>\n";
 
14784
            foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources)
 
14785
            {
 
14786
                my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"};
 
14787
                my $Name = get_filename($Identity);
 
14788
                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
 
14789
                $CheckedSources .= $Name.$Comment."<br/>\n";
 
14790
            }
 
14791
            $CheckedSources .= "</div>\n";
 
14792
            $CheckedSources .= "<br/>$TOP_REF<br/>\n";
 
14793
        }
13473
14794
    }
13474
14795
    if(not $CheckHeadersOnly)
13475
14796
    {
13476
 
        $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
 
14797
        $CheckedLibs = "<a name='Libs'></a><h2>".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13477
14798
        $CheckedLibs .= "<div class='lib_list'>\n";
13478
14799
        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
13479
14800
        {
13483
14804
        $CheckedLibs .= "</div>\n";
13484
14805
        $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
13485
14806
    }
13486
 
    return $CheckedHeaders.$CheckedLibs;
 
14807
    return $CheckedHeaders.$CheckedSources.$CheckedLibs;
 
14808
}
 
14809
 
 
14810
sub get_ObjTitle()
 
14811
{
 
14812
    if(defined $UsedDump{1}{"DWARF"}) {
 
14813
        return "Objects";
 
14814
    }
 
14815
    else {
 
14816
        return ucfirst($SLIB_TYPE)." Libraries";
 
14817
    }
13487
14818
}
13488
14819
 
13489
14820
sub get_TypeProblems_Count($$$)
13519
14850
{
13520
14851
    my $Level = $_[0];
13521
14852
    my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13522
 
    $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
 
14853
    $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other, $C_Other) = (0,0,0,0,0,0,0,0,0,0,0,0);
13523
14854
    %{$RESULT{$Level}} = (
13524
14855
        "Problems"=>0,
13525
14856
        "Warnings"=>0,
13540
14871
            }
13541
14872
        }
13542
14873
    }
 
14874
    foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}}))
 
14875
    {
 
14876
        foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
 
14877
        {
 
14878
            if(not defined $CompatRules{$Level}{$Kind})
 
14879
            { # unknown rule
 
14880
                if(not $UnknownRules{$Level}{$Kind})
 
14881
                { # only one warning
 
14882
                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
 
14883
                    $UnknownRules{$Level}{$Kind}=1;
 
14884
                }
 
14885
                delete($CompatProblems_Constants{$Level}{$Constant}{$Kind});
 
14886
            }
 
14887
        }
 
14888
    }
13543
14889
    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
13544
14890
    {
13545
14891
        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
13654
15000
        $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13655
15001
    }
13656
15002
    
13657
 
    if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13658
 
    {
13659
 
        if(defined $CompatRules{$Level}{"Changed_Constant"})
13660
 
        {
13661
 
            if($StrictCompat) {
13662
 
                $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13663
 
            }
13664
 
            else {
13665
 
                $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13666
 
            }
13667
 
        }
13668
 
        else
13669
 
        {
13670
 
            printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13671
 
            $C_Problems_Low = 0;
 
15003
    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
 
15004
    {
 
15005
        foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
 
15006
        {
 
15007
            my $Severity = getProblemSeverity($Level, $Kind);
 
15008
            if($Severity eq "Safe")
 
15009
            {
 
15010
                $C_Other+=1;
 
15011
            }
 
15012
            elsif($Severity eq "Low")
 
15013
            {
 
15014
                $C_Problems_Low+=1;
 
15015
            }
 
15016
        }
 
15017
    }
 
15018
    
 
15019
    if($C_Problems_Low)
 
15020
    {
 
15021
        if($StrictCompat) {
 
15022
            $RESULT{$Level}{"Problems"} += $C_Problems_Low;
 
15023
        }
 
15024
        else {
 
15025
            $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13672
15026
        }
13673
15027
    }
13674
15028
    if($CheckImpl and $Level eq "Binary")
13675
15029
    {
13676
15030
        if($StrictCompat) {
13677
 
            $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
 
15031
            $RESULT{$Level}{"Problems"} += keys(%CompatProblems_Impl);
13678
15032
        }
13679
15033
        else {
13680
 
            $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
 
15034
            $RESULT{$Level}{"Warnings"} += keys(%CompatProblems_Impl);
13681
15035
        }
13682
15036
    }
13683
15037
    if($RESULT{$Level}{"Problems"}
13717
15071
        $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13718
15072
        
13719
15073
        # test results
13720
 
        $TestResults .= "  <headers>\n";
13721
 
        foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13722
 
        {
13723
 
            my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
13724
 
            my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13725
 
            $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
13726
 
        }
13727
 
        $TestResults .= "  </headers>\n";
 
15074
        if(my @Headers = keys(%{$Registered_Headers{1}}))
 
15075
        {
 
15076
            $TestResults .= "  <headers>\n";
 
15077
            foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers)
 
15078
            {
 
15079
                my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
 
15080
                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
 
15081
                $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
 
15082
            }
 
15083
            $TestResults .= "  </headers>\n";
 
15084
        }
 
15085
        
 
15086
        if(my @Sources = keys(%{$Registered_Sources{1}}))
 
15087
        {
 
15088
            $TestResults .= "  <sources>\n";
 
15089
            foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources)
 
15090
            {
 
15091
                my $Identity = $Registered_Sources{1}{$Name}{"Identity"};
 
15092
                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
 
15093
                $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
 
15094
            }
 
15095
            $TestResults .= "  </sources>\n";
 
15096
        }
13728
15097
        
13729
15098
        $TestResults .= "  <libs>\n";
13730
15099
        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
13765
15134
        if($CheckImpl and $Level eq "Binary")
13766
15135
        {
13767
15136
            $Problem_Summary .= "  <impl>\n";
13768
 
            $Problem_Summary .= "    <low>".keys(%ImplProblems)."</low>\n";
 
15137
            $Problem_Summary .= "    <low>".keys(%CompatProblems_Impl)."</low>\n";
13769
15138
            $Problem_Summary .= "  </impl>\n";
13770
15139
        }
13771
15140
        $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13832
15201
        $TestResults = "<h2>Test Results</h2><hr/>\n";
13833
15202
        $TestResults .= "<table class='summary'>";
13834
15203
        
13835
 
        my $Headers_Link = "0";
13836
 
        $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13837
 
        $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
 
15204
        if(my @Headers = keys(%{$Registered_Headers{1}}))
 
15205
        {
 
15206
            my $Headers_Link = "<a href='#Headers' style='color:Blue;'>".($#Headers + 1)."</a>";
 
15207
            $TestResults .= "<tr><th>Total Header Files</th><td>".$Headers_Link."</td></tr>\n";
 
15208
        }
 
15209
        elsif($CheckObjectsOnly) {
 
15210
            $TestResults .= "<tr><th>Total Header Files</th><td>0&#160;(not&#160;analyzed)</td></tr>\n";
 
15211
        }
 
15212
        
 
15213
        if(my @Sources = keys(%{$Registered_Sources{1}}))
 
15214
        {
 
15215
            my $Src_Link = "<a href='#Sources' style='color:Blue;'>".($#Sources + 1)."</a>";
 
15216
            $TestResults .= "<tr><th>Total Source Files</th><td>".$Src_Link."</td></tr>\n";
 
15217
        }
13838
15218
        
13839
15219
        if(not $ExtendedCheck)
13840
15220
        {
13841
15221
            my $Libs_Link = "0";
13842
15222
            $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
13843
 
            $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
 
15223
            $TestResults .= "<tr><th>Total ".get_ObjTitle()."</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
13844
15224
        }
13845
15225
        
13846
15226
        $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
13931
15311
        $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
13932
15312
        
13933
15313
        my $ChangedConstants_Link = "0";
13934
 
        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
13935
 
        {
13936
 
            if($JoinReport) {
13937
 
                $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13938
 
            }
13939
 
            else {
13940
 
                $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13941
 
            }
 
15314
        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) {
 
15315
            $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>";
13942
15316
        }
13943
15317
        $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
13944
15318
        $META_DATA .= "changed_constants:$C_Problems_Low;";
13947
15321
        if($CheckImpl and $Level eq "Binary")
13948
15322
        {
13949
15323
            my $ChangedImpl_Link = "0";
13950
 
            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
 
15324
            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%CompatProblems_Impl)."</a>" if(keys(%CompatProblems_Impl)>0);
13951
15325
            $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
13952
 
            $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
13953
 
            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%ImplProblems))).">$ChangedImpl_Link</td></tr>\n";
 
15326
            $META_DATA .= "changed_implementation:".keys(%CompatProblems_Impl).";";
 
15327
            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%CompatProblems_Impl))).">$ChangedImpl_Link</td></tr>\n";
13954
15328
        }
13955
15329
        # Safe Changes
13956
15330
        if($T_Other and not $CheckObjectsOnly)
13965
15339
            $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
13966
15340
        }
13967
15341
        
 
15342
        if($C_Other and not $CheckObjectsOnly)
 
15343
        {
 
15344
            my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>";
 
15345
            $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "S", $C_Other).">$CS_Link</td></tr>\n";
 
15346
        }
 
15347
        
13968
15348
        $META_DATA .= "tool_version:$TOOL_VERSION";
13969
15349
        $Problem_Summary .= "</table>\n";
13970
15350
        # $TestInfo = getLegend().$TestInfo;
14038
15418
    return $num;
14039
15419
}
14040
15420
 
14041
 
sub get_Report_ChangedConstants($)
 
15421
sub get_Report_ChangedConstants($$)
14042
15422
{
14043
 
    my $Level = $_[0];
 
15423
    my ($TargetSeverity, $Level) = @_;
14044
15424
    my $CHANGED_CONSTANTS = "";
 
15425
    
14045
15426
    my %ReportMap = ();
14046
 
    foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
14047
 
        $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
14048
 
    }
14049
 
    my $Kind = "Changed_Constant";
14050
 
    if(not defined $CompatRules{$Level}{$Kind}) {
14051
 
        return "";
14052
 
    }
 
15427
    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
 
15428
    {
 
15429
        my $Header = $Constants{1}{$Constant}{"Header"};
 
15430
        if(not $Header)
 
15431
        { # added
 
15432
            $Header = $Constants{2}{$Constant}{"Header"}
 
15433
        }
 
15434
        
 
15435
        foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
 
15436
        {
 
15437
            if(not defined $CompatRules{$Level}{$Kind}) {
 
15438
                next;
 
15439
            }
 
15440
            if($TargetSeverity ne getProblemSeverity($Level, $Kind)) {
 
15441
                next;
 
15442
            }
 
15443
            $ReportMap{$Header}{$Constant}{$Kind} = 1;
 
15444
        }
 
15445
    }
 
15446
    
14053
15447
    if($ReportFormat eq "xml")
14054
15448
    { # XML
14055
15449
        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14058
15452
            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14059
15453
            {
14060
15454
                $CHANGED_CONSTANTS .= "    <constant name=\"$Constant\">\n";
14061
 
                my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14062
 
                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14063
 
                my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14064
 
                $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
14065
 
                $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14066
 
                $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14067
 
                $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
14068
 
                $CHANGED_CONSTANTS .= "      </problem>\n";
 
15455
                foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
 
15456
                {
 
15457
                    my $Change = $CompatRules{$Level}{$Kind}{"Change"};
 
15458
                    my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
 
15459
                    my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
 
15460
                    
 
15461
                    $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
 
15462
                    $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n";
 
15463
                    $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n";
 
15464
                    $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n";
 
15465
                    $CHANGED_CONSTANTS .= "      </problem>\n";
 
15466
                }
14069
15467
                $CHANGED_CONSTANTS .= "    </constant>\n";
14070
15468
            }
14071
15469
            $CHANGED_CONSTANTS .= "    </header>\n";
14078
15476
        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14079
15477
        {
14080
15478
            $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
14081
 
            foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
 
15479
            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14082
15480
            {
14083
 
                $Number += 1;
14084
 
                my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14085
 
                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14086
 
                my $Report = "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14087
 
                $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
14088
 
                $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14089
 
                $CHANGED_CONSTANTS .= insertIDs($Report);
 
15481
                my $Report = "";
 
15482
                
 
15483
                foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
 
15484
                {
 
15485
                    my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind});
 
15486
                    my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
 
15487
                    $Report .= "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
 
15488
                    $Number += 1;
 
15489
                }
 
15490
                if($Report)
 
15491
                {
 
15492
                    $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
 
15493
                    $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report;
 
15494
                    $Report = insertIDs($Report);
 
15495
                }
 
15496
                $CHANGED_CONSTANTS .= $Report;
14090
15497
            }
14091
15498
            $CHANGED_CONSTANTS .= "<br/>\n";
14092
15499
        }
14093
15500
        if($CHANGED_CONSTANTS)
14094
15501
        {
14095
 
            my $Anchor = "<a name='Changed_Constants'></a>";
14096
 
            if($JoinReport) {
14097
 
                $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
 
15502
            my $Title = "Problems with Constants, $TargetSeverity Severity";
 
15503
            if($TargetSeverity eq "Safe")
 
15504
            { # Safe Changes
 
15505
                $Title = "Other Changes in Constants";
14098
15506
            }
14099
 
            $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
 
15507
            $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a><h2>$Title ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
14100
15508
        }
14101
15509
    }
14102
15510
    return $CHANGED_CONSTANTS;
14106
15514
{
14107
15515
    my $CHANGED_IMPLEMENTATION = "";
14108
15516
    my %ReportMap = ();
14109
 
    foreach my $Interface (sort keys(%ImplProblems))
 
15517
    foreach my $Interface (sort keys(%CompatProblems_Impl))
14110
15518
    {
14111
15519
        my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14112
15520
        my $DyLib = $Symbol_Library{1}{$Interface};
14117
15525
    {
14118
15526
        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14119
15527
        {
14120
 
            my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14121
 
            if($HeaderName) {
14122
 
                $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14123
 
            }
14124
 
            else {
14125
 
                $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14126
 
            }
14127
15528
            my %NameSpaceSymbols = ();
14128
15529
            foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14129
 
                $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
 
15530
                $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1;
14130
15531
            }
14131
15532
            foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14132
15533
            {
14133
 
                $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
 
15534
                $CHANGED_IMPLEMENTATION .= getTitle($HeaderName, $DyLib, $NameSpace);
14134
15535
                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
14135
15536
                foreach my $Interface (@SortedInterfaces)
14136
15537
                {
14139
15540
                    if($NameSpace) {
14140
15541
                        $Signature=~s/\b\Q$NameSpace\E::\b//g;
14141
15542
                    }
14142
 
                    $CHANGED_IMPLEMENTATION .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>".$ImplProblems{$Interface}{"Diff"}."<br/><br/>".$ContentDivEnd."\n");
 
15543
                    $CHANGED_IMPLEMENTATION .= $ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>".$CompatProblems_Impl{$Interface}{"Diff"}."<br/><br/>".$ContentDivEnd."\n";
14143
15544
                }
 
15545
                $CHANGED_IMPLEMENTATION .= "<br/>\n";
14144
15546
            }
14145
 
            $CHANGED_IMPLEMENTATION .= "<br/>\n";
14146
15547
        }
14147
15548
    }
14148
 
    if($CHANGED_IMPLEMENTATION) {
 
15549
    if($CHANGED_IMPLEMENTATION)
 
15550
    {
 
15551
        $CHANGED_IMPLEMENTATION = insertIDs($CHANGED_IMPLEMENTATION);
14149
15552
        $CHANGED_IMPLEMENTATION = "<a name='Changed_Implementation'></a><h2>Problems with Implementation ($Changed_Number)</h2><hr/>\n".$CHANGED_IMPLEMENTATION.$TOP_REF."<br/>\n";
14150
15553
    }
14151
15554
    
14152
15555
    # clean memory
14153
 
    %ImplProblems = ();
 
15556
    %CompatProblems_Impl = ();
14154
15557
    
14155
15558
    return $CHANGED_IMPLEMENTATION;
14156
15559
}
14174
15577
        $Title .= "<span class='h_name'>$Header</span><br/>\n";
14175
15578
    }
14176
15579
    if($NameSpace) {
14177
 
        $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
 
15580
        $Title .= "<span class='ns'>namespace <b>$NameSpace</b></span><br/>\n";
14178
15581
    }
14179
15582
    return $Title;
14180
15583
}
14226
15629
            {
14227
15630
                my %NameSpaceSymbols = ();
14228
15631
                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14229
 
                    $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
 
15632
                    $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1;
14230
15633
                }
14231
15634
                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14232
15635
                {
14239
15642
                        if($NameSpace) {
14240
15643
                            $Signature=~s/\b\Q$NameSpace\E::\b//g;
14241
15644
                        }
14242
 
                        if($Interface=~/\A(_Z|\?)/) {
 
15645
                        if($Interface=~/\A(_Z|\?)/)
 
15646
                        {
14243
15647
                            if($Signature) {
14244
15648
                                $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span><br/><br/>".$ContentDivEnd."\n");
14245
15649
                            }
14247
15651
                                $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
14248
15652
                            }
14249
15653
                        }
14250
 
                        else {
 
15654
                        else
 
15655
                        {
14251
15656
                            if($Signature) {
14252
15657
                                $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
14253
15658
                            }
14319
15724
            {
14320
15725
                my %NameSpaceSymbols = ();
14321
15726
                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14322
 
                    $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
 
15727
                    $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1;
14323
15728
                }
14324
15729
                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14325
15730
                {
14382
15787
    }
14383
15788
    my @PString = ();
14384
15789
    foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14385
 
        push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
 
15790
        push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
14386
15791
    }
14387
15792
    if(@PString) {
14388
15793
        return " ".join(" ", @PString);
14445
15850
        or $Value eq "") {
14446
15851
            next;
14447
15852
        }
14448
 
        if($Value=~/\s\(/)
 
15853
        if($Value=~/\s\(/ and $Value!~/['"]/)
14449
15854
        { # functions
14450
15855
            $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14451
15856
            $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
14553
15958
            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14554
15959
            {
14555
15960
                $INTERFACE_PROBLEMS .= "    <library name=\"$DyLib\">\n";
14556
 
                foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
 
15961
                foreach my $Symbol (sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%SymbolChanges))
14557
15962
                {
14558
15963
                    $INTERFACE_PROBLEMS .= "      <symbol name=\"$Symbol\">\n";
14559
15964
                    foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14589
15994
            {
14590
15995
                my (%NameSpaceSymbols, %NewSignature) = ();
14591
15996
                foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14592
 
                    $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
 
15997
                    $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1;
14593
15998
                }
14594
15999
                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14595
16000
                {
14596
16001
                    $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14597
 
                    my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
 
16002
                    my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$NameSpaceSymbols{$NameSpace}});
14598
16003
                    foreach my $Symbol (@SortedInterfaces)
14599
16004
                    {
14600
16005
                        my $Signature = get_Signature($Symbol, 1);
14666
16071
{
14667
16072
    my ($TargetSeverity, $Level) = @_;
14668
16073
    my $TYPE_PROBLEMS = "";
14669
 
    my (%ReportMap, %TypeChanges, %TypeType) = ();
 
16074
    my (%ReportMap, %TypeChanges) = ();
14670
16075
    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
14671
16076
    {
14672
16077
        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
14676
16081
                foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
14677
16082
                {
14678
16083
                    my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14679
 
                    my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14680
16084
                    my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14681
 
                    $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14682
16085
                    my $Severity = getProblemSeverity($Level, $Kind);
14683
16086
                    if($Severity eq "Safe"
14684
16087
                    and $TargetSeverity ne "Safe") {
14685
16088
                        next;
14686
16089
                    }
14687
 
                    if(not $TypeType{$TypeName}
14688
 
                    or $TypeType{$TypeName} eq "struct")
14689
 
                    { # register type of the type, select "class" if type has "class"- and "struct"-type changes
14690
 
                        $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14691
 
                    }
14692
16090
                    
14693
16091
                    if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
14694
16092
                    { # select a problem with the highest priority
14740
16138
            $TYPE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
14741
16139
            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
14742
16140
            {
14743
 
                $TYPE_PROBLEMS .= "    <type name=\"".htmlSpecChars($TypeName)."\">\n";
 
16141
                $TYPE_PROBLEMS .= "    <type name=\"".xmlSpecChars($TypeName)."\">\n";
14744
16142
                foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14745
16143
                {
14746
16144
                    foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14773
16171
        {
14774
16172
            my (%NameSpace_Type) = ();
14775
16173
            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
14776
 
                $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
 
16174
                $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1;
14777
16175
            }
14778
16176
            foreach my $NameSpace (sort keys(%NameSpace_Type))
14779
16177
            {
14780
16178
                $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14781
 
                my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
 
16179
                my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}});
14782
16180
                foreach my $TypeName (@SortedTypes)
14783
16181
                {
14784
16182
                    my $ProblemNum = 1;
14805
16203
                        if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
14806
16204
                            $ShowVTables = showVTables($TypeName);
14807
16205
                        }
14808
 
                        $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
 
16206
                        
 
16207
                        $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ".show_Type($TypeName, 1, 1)." ($ProblemNum)".$ContentSpanEnd;
14809
16208
                        $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14810
16209
                        $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14811
16210
                        $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14832
16231
    return $TYPE_PROBLEMS;
14833
16232
}
14834
16233
 
 
16234
sub show_Type($$$)
 
16235
{
 
16236
    my ($Name, $Html, $LibVersion) = @_;
 
16237
    my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"};
 
16238
    $TType = lc($TType);
 
16239
    if($TType=~/struct|union|enum/) {
 
16240
        $Name=~s/\A\Q$TType\E //g;
 
16241
    }
 
16242
    if($Html) {
 
16243
        $Name = "<span class='ttype'>".$TType."</span> ".htmlSpecChars($Name);
 
16244
    }
 
16245
    else {
 
16246
        $Name = $TType." ".$Name;
 
16247
    }
 
16248
    return $Name;
 
16249
}
 
16250
 
14835
16251
sub get_Anchor($$$)
14836
16252
{
14837
16253
    my ($Kind, $Level, $Severity) = @_;
14882
16298
                foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
14883
16299
                {
14884
16300
                    $VTABLES .= "        <entry offset=\"".$Index."\">\n";
14885
 
                    $VTABLES .= "          <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
14886
 
                    $VTABLES .= "          <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
 
16301
                    $VTABLES .= "          <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
 
16302
                    $VTABLES .= "          <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
14887
16303
                    $VTABLES .= "        </entry>\n";
14888
16304
                }
14889
16305
                $VTABLES .= "      </vtable>\n\n";
14934
16350
    if($VEntry=~/\A_ZThn.+\Z/) {
14935
16351
        $VEntry = "non-virtual thunk";
14936
16352
    }
14937
 
    $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
 
16353
    $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i;
14938
16354
    # support for old GCC versions
14939
16355
    $VEntry=~s/\A0u\Z/(int (*)(...))0/;
14940
16356
    $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15058
16474
                $Target = " affected=\"this\"";
15059
16475
            }
15060
16476
            $Affected .= "        <symbol$Target name=\"$Symbol\">\n";
15061
 
            $Affected .= "          <comment>".htmlSpecChars($Description)."</comment>\n";
 
16477
            $Affected .= "          <comment>".xmlSpecChars($Description)."</comment>\n";
15062
16478
            $Affected .= "        </symbol>\n";
15063
16479
        }
15064
16480
        $Affected .= "      </affected>\n";
15070
16486
            my $Description = $SProblems{$Symbol}{"Descr"};
15071
16487
            my $Signature = $SProblems{$Symbol}{"Signature"};
15072
16488
            my $Pos = $SProblems{$Symbol}{"Position"};
15073
 
            $Affected .= "<span class='iname_b'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
 
16489
            $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
15074
16490
        }
15075
16491
        if(keys(%SProblems)>$LIMIT) {
15076
16492
            $Affected .= "and others ...<br/>";
15186
16602
        }
15187
16603
    }
15188
16604
    if($ExtendedSymbols{$Symbol}) {
15189
 
        push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
 
16605
        push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling.");
15190
16606
    }
15191
16607
    return join(" ", @Sentence);
15192
16608
}
15203
16619
        my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
15204
16620
        foreach my $Typedef (keys(%ChangedTypedef))
15205
16621
        {
15206
 
            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
15207
 
            $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
 
16622
            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
 
16623
                $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
 
16624
            }
15208
16625
        }
15209
16626
        $Report .= "    <param pos=\"$Pos\">\n";
15210
16627
        $Report .= "      <name>".$Name."</name>\n";
15211
 
        $Report .= "      <type>".htmlSpecChars($TypeName)."</type>\n";
 
16628
        $Report .= "      <type>".xmlSpecChars($TypeName)."</type>\n";
15212
16629
        $Report .= "    </param>\n";
15213
16630
    }
15214
16631
    if(my $Return = $Info->{"Return"})
15215
16632
    {
15216
16633
        my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
15217
16634
        $Report .= "    <retval>\n";
15218
 
        $Report .= "      <type>".htmlSpecChars($RTName)."</type>\n";
 
16635
        $Report .= "      <type>".xmlSpecChars($RTName)."</type>\n";
15219
16636
        $Report .= "    </retval>\n";
15220
16637
    }
15221
16638
    return $Report;
15259
16676
        }
15260
16677
        if($S1)
15261
16678
        {
15262
 
            $Report .= "    <old signature=\"".htmlSpecChars($S1)."\">\n";
 
16679
            $Report .= "    <old signature=\"".xmlSpecChars($S1)."\">\n";
15263
16680
            $Report .= $P1;
15264
16681
            $Report .= "    </old>\n";
15265
16682
        }
15266
16683
        if($S2 and $S2 ne $S1)
15267
16684
        {
15268
 
            $Report .= "    <new signature=\"".htmlSpecChars($S2)."\">\n";
 
16685
            $Report .= "    <new signature=\"".xmlSpecChars($S2)."\">\n";
15269
16686
            $Report .= $P2;
15270
16687
            $Report .= "    </new>\n";
15271
16688
        }
15314
16731
    my $Cmd = "";
15315
16732
    if($Browse)
15316
16733
    { # user-defined browser
15317
 
        $Cmd = $Browse." \"".$Path."\"";
 
16734
        $Cmd = $Browse." \"$Path\"";
15318
16735
    }
15319
16736
    if(not $Cmd)
15320
16737
    { # default browser
15321
16738
        if($OSgroup eq "macos") {
15322
 
            system("open \"".$Path."\"");
 
16739
            $Cmd = "open \"$Path\"";
15323
16740
        }
15324
16741
        elsif($OSgroup eq "windows") {
15325
 
            system("start \"".$Path."\"");
 
16742
            $Cmd = "start ".path_format($Path, $OSgroup);
15326
16743
        }
15327
16744
        else
15328
16745
        { # linux, freebsd, solaris
15339
16756
            {
15340
16757
                if($Br = get_CmdPath($Br))
15341
16758
                {
15342
 
                    $Cmd = $Br." \"".$Path."\"";
 
16759
                    $Cmd = $Br." \"$Path\"";
15343
16760
                    last;
15344
16761
                }
15345
16762
            }
15350
16767
        if($Debug) {
15351
16768
            printMsg("INFO", "running $Cmd");
15352
16769
        }
15353
 
        if($Cmd!~/lynx|links/) {
15354
 
            $Cmd .= "  >/dev/null 2>&1 &";
 
16770
        if($OSgroup ne "windows"
 
16771
        and $OSgroup ne "macos")
 
16772
        {
 
16773
            if($Cmd!~/lynx|links/) {
 
16774
                $Cmd .= "  >\"/dev/null\" 2>&1 &";
 
16775
            }
15355
16776
        }
15356
16777
        system($Cmd);
15357
16778
    }
15407
16828
            </div>";
15408
16829
            $Report .= "<div id='BinaryTab' class='tab'>\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."<br/><br/><br/></div>";
15409
16830
            $Report .= "<div id='SourceTab' class='tab'>\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."<br/><br/><br/></div>";
15410
 
            $Report .= getReportFooter($TargetLibraryFName);
 
16831
            $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
15411
16832
            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15412
16833
            return $Report;
15413
16834
        }
15430
16851
            $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15431
16852
            $Report .= get_SourceInfo();
15432
16853
            $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15433
 
            $Report .= getReportFooter($TargetLibraryFName);
 
16854
            $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
15434
16855
            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15435
16856
            return $Report;
15436
16857
        }
15472
16893
    }
15473
16894
}
15474
16895
 
15475
 
sub getReportFooter($)
 
16896
sub getReportFooter($$)
15476
16897
{
15477
 
    my $LibName = $_[0];
15478
 
    my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
 
16898
    my ($LibName, $Wide) = @_;
 
16899
    my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
15479
16900
    my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
15480
16901
    $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
15481
16902
    $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15493
16914
    }
15494
16915
    if($Priority eq "Low")
15495
16916
    {
15496
 
        $Report .= get_Report_ChangedConstants($Level);
15497
 
        if($ReportFormat eq "html") {
 
16917
        $Report .= get_Report_ChangedConstants("Low", $Level);
 
16918
        if($ReportFormat eq "html")
 
16919
        {
15498
16920
            if($CheckImpl and $Level eq "Binary") {
15499
16921
                $Report .= get_Report_Impl();
15500
16922
            }
15501
16923
        }
15502
16924
    }
 
16925
    if($Priority eq "Safe")
 
16926
    {
 
16927
        $Report .= get_Report_ChangedConstants("Safe", $Level);
 
16928
    }
15503
16929
    if($ReportFormat eq "html")
15504
16930
    {
15505
16931
        if($Report)
15568
16994
sub checkPreprocessedUnit($)
15569
16995
{
15570
16996
    my $Path = $_[0];
15571
 
    my $CurHeader = "";
 
16997
    my ($CurHeader, $CurHeaderName) = ("", "");
 
16998
    my $CurClass = ""; # extra info
15572
16999
    open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
15573
 
    while(<PREPROC>)
 
17000
    
 
17001
    while(my $Line = <PREPROC>)
15574
17002
    { # detecting public and private constants
15575
 
        next if(not /\A#/);
15576
 
        chomp($_);
15577
 
        if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
15578
 
            $CurHeader=path_format($1, $OSgroup);
15579
 
        }
15580
 
        if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
15581
 
        and not $Registered_Headers{$Version}{$CurHeader})
15582
 
        { # not a target
15583
 
            next;
15584
 
        }
15585
 
        my $HName = get_filename($CurHeader);
15586
 
        if(not is_target_header($HName, 1)
15587
 
        and not is_target_header($HName, 2))
15588
 
        { # user-defined header
15589
 
            next;
15590
 
        }
15591
 
        if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
15592
 
        {
15593
 
            my ($Name, $Value) = ($1, $2);
15594
 
            if(not $Constants{$Version}{$Name}{"Access"})
15595
 
            {
15596
 
                $Constants{$Version}{$Name}{"Access"} = "public";
15597
 
                $Constants{$Version}{$Name}{"Value"} = $Value;
15598
 
                $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
15599
 
            }
15600
 
        }
15601
 
        elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15602
 
            $Constants{$Version}{$1}{"Access"} = "private";
 
17003
        if(substr($Line, 0, 1) eq "#")
 
17004
        {
 
17005
            chomp($Line);
 
17006
            if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
 
17007
            {
 
17008
                $CurHeader = path_format($1, $OSgroup);
 
17009
                $CurHeaderName = get_filename($CurHeader);
 
17010
                $CurClass = "";
 
17011
                
 
17012
                if(index($CurHeader, $TMP_DIR)==0) {
 
17013
                    next;
 
17014
                }
 
17015
                
 
17016
                if(substr($CurHeaderName, 0, 1) eq "<")
 
17017
                { # <built-in>, <command-line>, etc.
 
17018
                    $CurHeaderName = "";
 
17019
                    $CurHeader = "";
 
17020
                }
 
17021
                
 
17022
                if($ExtraInfo)
 
17023
                {
 
17024
                    if($CurHeaderName) {
 
17025
                        $PreprocessedHeaders{$Version}{$CurHeader} = 1;
 
17026
                    }
 
17027
                }
 
17028
            }
 
17029
            if(not $ExtraDump)
 
17030
            {
 
17031
                if($CurHeaderName)
 
17032
                {
 
17033
                    if(not $Include_Neighbors{$Version}{$CurHeaderName}
 
17034
                    and not $Registered_Headers{$Version}{$CurHeader})
 
17035
                    { # not a target
 
17036
                        next;
 
17037
                    }
 
17038
                    if(not is_target_header($CurHeaderName, 1)
 
17039
                    and not is_target_header($CurHeaderName, 2))
 
17040
                    { # user-defined header
 
17041
                        next;
 
17042
                    }
 
17043
                }
 
17044
            }
 
17045
            
 
17046
            if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
 
17047
            {
 
17048
                my ($Name, $Value) = ($1, $2);
 
17049
                if(not $Constants{$Version}{$Name}{"Access"})
 
17050
                {
 
17051
                    $Constants{$Version}{$Name}{"Access"} = "public";
 
17052
                    $Constants{$Version}{$Name}{"Value"} = $Value;
 
17053
                    if($CurHeaderName) {
 
17054
                        $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
 
17055
                    }
 
17056
                }
 
17057
            }
 
17058
            elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
 
17059
                $Constants{$Version}{$1}{"Access"} = "private";
 
17060
            }
 
17061
        }
 
17062
        else
 
17063
        {
 
17064
            if(defined $ExtraDump)
 
17065
            {
 
17066
                if($Line=~/(\w+)\s*\(/)
 
17067
                { # functions
 
17068
                    $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader;
 
17069
                }
 
17070
                #elsif($Line=~/(\w+)\s*;/)
 
17071
                #{ # data
 
17072
                #    $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader;
 
17073
                #}
 
17074
                elsif($Line=~/(\A|\s)class\s+(\w+)/) {
 
17075
                    $CurClass = $2;
 
17076
                }
 
17077
            }
15603
17078
        }
15604
17079
    }
15605
17080
    close(PREPROC);
15606
17081
    foreach my $Constant (keys(%{$Constants{$Version}}))
15607
17082
    {
15608
 
        if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
15609
 
        or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15610
 
        { # skip private constants
 
17083
        if($Constants{$Version}{$Constant}{"Access"} eq "private")
 
17084
        {
 
17085
            delete($Constants{$Version}{$Constant});
 
17086
            next;
 
17087
        }
 
17088
        if(not $ExtraDump and ($Constant=~/_h\Z/i or isBuiltIn($Constants{$Version}{$Constant}{"Header"})))
 
17089
        { # skip
15611
17090
            delete($Constants{$Version}{$Constant});
15612
17091
        }
15613
17092
        else {
15614
17093
            delete($Constants{$Version}{$Constant}{"Access"});
15615
17094
        }
15616
17095
    }
 
17096
    if($Debug)
 
17097
    {
 
17098
        mkpath($DEBUG_PATH{$Version});
 
17099
        copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
 
17100
    }
15617
17101
}
15618
17102
 
15619
17103
sub uncoverConstant($$)
15624
17108
    if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15625
17109
        return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15626
17110
    }
15627
 
    my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15628
 
    if(defined $Value)
 
17111
    
 
17112
    if(defined $Constants{$LibVersion}{$Constant})
15629
17113
    {
15630
 
        if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
 
17114
        my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
 
17115
        if(defined $Constants{$LibVersion}{$Value})
15631
17116
        {
15632
17117
            push(@RecurConstant, $Constant);
15633
17118
            my $Uncovered = uncoverConstant($LibVersion, $Value);
15636
17121
            }
15637
17122
            pop(@RecurConstant);
15638
17123
        }
 
17124
        
15639
17125
        # FIXME: uncover $Value using all the enum constants
15640
 
        # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
 
17126
        # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15641
17127
        return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15642
17128
    }
15643
17129
    return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15644
17130
}
15645
17131
 
15646
 
my %IgnoreConstant=(
15647
 
    "VERSION"=>1,
15648
 
    "VERSIONCODE"=>1,
15649
 
    "VERNUM"=>1,
15650
 
    "VERS_INFO"=>1,
15651
 
    "PATCHLEVEL"=>1,
15652
 
    "INSTALLPREFIX"=>1,
15653
 
    "VBUILD"=>1,
15654
 
    "VPATCH"=>1,
15655
 
    "VMINOR"=>1,
15656
 
    "BUILD_STRING"=>1,
15657
 
    "BUILD_TIME"=>1,
15658
 
    "PACKAGE_STRING"=>1,
15659
 
    "PRODUCTION"=>1,
15660
 
    "CONFIGURE_COMMAND"=>1,
15661
 
    "INSTALLDIR"=>1,
15662
 
    "BINDIR"=>1,
15663
 
    "CONFIG_FILE_PATH"=>1,
15664
 
    "DATADIR"=>1,
15665
 
    "EXTENSION_DIR"=>1,
15666
 
    "INCLUDE_PATH"=>1,
15667
 
    "LIBDIR"=>1,
15668
 
    "LOCALSTATEDIR"=>1,
15669
 
    "SBINDIR"=>1,
15670
 
    "SYSCONFDIR"=>1,
15671
 
    "RELEASE"=>1,
15672
 
    "SOURCE_ID"=>1,
15673
 
    "SUBMINOR"=>1,
15674
 
    "MINOR"=>1,
15675
 
    "MINNOR"=>1,
15676
 
    "MINORVERSION"=>1,
15677
 
    "MAJOR"=>1,
15678
 
    "MAJORVERSION"=>1,
15679
 
    "MICRO"=>1,
15680
 
    "MICROVERSION"=>1,
15681
 
    "BINARY_AGE"=>1,
15682
 
    "INTERFACE_AGE"=>1,
15683
 
    "CORE_ABI"=>1,
15684
 
    "PATCH"=>1,
15685
 
    "COPYRIGHT"=>1,
15686
 
    "TIMESTAMP"=>1,
15687
 
    "REVISION"=>1,
15688
 
    "PACKAGE_TAG"=>1,
15689
 
    "PACKAGEDATE"=>1,
15690
 
    "NUMVERSION"=>1
 
17132
sub simpleConstant($$)
 
17133
{
 
17134
    my ($LibVersion, $Value) = @_;
 
17135
    if($Value=~/\W/)
 
17136
    {
 
17137
        my $Value_Copy = $Value;
 
17138
        while($Value_Copy=~s/([a-z_]\w+)/\@/i)
 
17139
        {
 
17140
            my $Word = $1;
 
17141
            if($Value!~/$Word\s*\(/)
 
17142
            {
 
17143
                my $Val = uncoverConstant($LibVersion, $Word);
 
17144
                if($Val ne "")
 
17145
                {
 
17146
                    $Value=~s/\b$Word\b/$Val/g;
 
17147
                }
 
17148
            }
 
17149
        }
 
17150
    }
 
17151
    return $Value;
 
17152
}
 
17153
 
 
17154
sub computeValue($)
 
17155
{
 
17156
    my $Value = $_[0];
 
17157
    
 
17158
    if($Value=~/\A\((-?[\d]+)\)\Z/) {
 
17159
        return $1;
 
17160
    }
 
17161
    
 
17162
    if($Value=~/\A[\d\-\+()]+\Z/) {
 
17163
        return eval($Value);
 
17164
    }
 
17165
    
 
17166
    return $Value;
 
17167
}
 
17168
 
 
17169
my %IgnoreConstant = map {$_=>1} (
 
17170
    "VERSION",
 
17171
    "VERSIONCODE",
 
17172
    "VERNUM",
 
17173
    "VERS_INFO",
 
17174
    "PATCHLEVEL",
 
17175
    "INSTALLPREFIX",
 
17176
    "VBUILD",
 
17177
    "VPATCH",
 
17178
    "VMINOR",
 
17179
    "BUILD_STRING",
 
17180
    "BUILD_TIME",
 
17181
    "PACKAGE_STRING",
 
17182
    "PRODUCTION",
 
17183
    "CONFIGURE_COMMAND",
 
17184
    "INSTALLDIR",
 
17185
    "BINDIR",
 
17186
    "CONFIG_FILE_PATH",
 
17187
    "DATADIR",
 
17188
    "EXTENSION_DIR",
 
17189
    "INCLUDE_PATH",
 
17190
    "LIBDIR",
 
17191
    "LOCALSTATEDIR",
 
17192
    "SBINDIR",
 
17193
    "SYSCONFDIR",
 
17194
    "RELEASE",
 
17195
    "SOURCE_ID",
 
17196
    "SUBMINOR",
 
17197
    "MINOR",
 
17198
    "MINNOR",
 
17199
    "MINORVERSION",
 
17200
    "MAJOR",
 
17201
    "MAJORVERSION",
 
17202
    "MICRO",
 
17203
    "MICROVERSION",
 
17204
    "BINARY_AGE",
 
17205
    "INTERFACE_AGE",
 
17206
    "CORE_ABI",
 
17207
    "PATCH",
 
17208
    "COPYRIGHT",
 
17209
    "TIMESTAMP",
 
17210
    "REVISION",
 
17211
    "PACKAGE_TAG",
 
17212
    "PACKAGEDATE",
 
17213
    "NUMVERSION",
 
17214
    "Release",
 
17215
    "Version"
15691
17216
);
15692
17217
 
 
17218
sub constantFilter($$$)
 
17219
{
 
17220
    my ($Name, $Value, $Level) = @_;
 
17221
    
 
17222
    if($Level eq "Binary")
 
17223
    {
 
17224
        if($Name=~/_t\Z/)
 
17225
        { # __malloc_ptr_t
 
17226
            return 1;
 
17227
        }
 
17228
        foreach (keys(%IgnoreConstant))
 
17229
        {
 
17230
            if($Name=~/(\A|_)$_(_|\Z)/)
 
17231
            { # version
 
17232
                return 1;
 
17233
            }
 
17234
            if(/\A[A-Z].*[a-z]\Z/)
 
17235
            {
 
17236
                if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/)
 
17237
                { # version
 
17238
                    return 1;
 
17239
                }
 
17240
            }
 
17241
        }
 
17242
        if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
 
17243
        { # version
 
17244
            return 1;
 
17245
        }
 
17246
        if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/)
 
17247
        { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
 
17248
            return 1;
 
17249
        }
 
17250
        
 
17251
        if($Value=~/\A["'].*['"]/i)
 
17252
        { # string
 
17253
            return 0;
 
17254
        }
 
17255
        
 
17256
        if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i)
 
17257
        { # static int gcry_pth_init
 
17258
          # extern ABC
 
17259
          # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
 
17260
          # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ...
 
17261
            return 1;
 
17262
        }
 
17263
        if($Value=~/\w+\s*\(/i)
 
17264
        { # foo(p)
 
17265
            return 1;
 
17266
        }
 
17267
        if($Value=~/\A[a-z_]+\w*\Z/i)
 
17268
        { # asn1_node_st
 
17269
          # __SMTH_P
 
17270
            return 1;
 
17271
        }
 
17272
    }
 
17273
    
 
17274
    return 0;
 
17275
}
 
17276
 
15693
17277
sub mergeConstants($)
15694
17278
{
15695
17279
    my $Level = $_[0];
15699
17283
        { # skipped by the user
15700
17284
            next;
15701
17285
        }
15702
 
        if(not defined $Constants{2}{$Constant}{"Value"}
15703
 
        or $Constants{2}{$Constant}{"Value"} eq "")
 
17286
        
 
17287
        if(my $Header = $Constants{1}{$Constant}{"Header"})
 
17288
        {
 
17289
            if(not is_target_header($Header, 1)
 
17290
            and not is_target_header($Header, 2))
 
17291
            { # user-defined header
 
17292
                next;
 
17293
            }
 
17294
        }
 
17295
        else {
 
17296
            next;
 
17297
        }
 
17298
        
 
17299
        my $Old_Value = uncoverConstant(1, $Constant);
 
17300
        
 
17301
        if(constantFilter($Constant, $Old_Value, $Level))
 
17302
        { # separate binary and source problems
 
17303
            next;
 
17304
        }
 
17305
        
 
17306
        if(not defined $Constants{2}{$Constant}{"Value"})
 
17307
        { # removed
 
17308
            %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = (
 
17309
                "Target"=>$Constant,
 
17310
                "Old_Value"=>$Old_Value  );
 
17311
            next;
 
17312
        }
 
17313
        
 
17314
        if($Constants{2}{$Constant}{"Value"} eq "")
15704
17315
        { # empty value
15705
 
            next;
15706
 
        }
15707
 
        my $Header = $Constants{1}{$Constant}{"Header"};
15708
 
        if(not is_target_header($Header, 1)
15709
 
        and not is_target_header($Header, 2))
15710
 
        { # user-defined header
15711
 
            next;
15712
 
        }
15713
 
        my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
15714
 
        $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15715
 
        $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
 
17316
          # TODO: implement a rule
 
17317
            next;
 
17318
        }
 
17319
        
 
17320
        my $New_Value = uncoverConstant(2, $Constant);
 
17321
        
 
17322
        my $Old_Value_Pure = $Old_Value;
 
17323
        my $New_Value_Pure = $New_Value;
 
17324
        
15716
17325
        $Old_Value_Pure=~s/(\W)\s+/$1/g;
15717
17326
        $Old_Value_Pure=~s/\s+(\W)/$1/g;
15718
17327
        $New_Value_Pure=~s/(\W)\s+/$1/g;
15719
17328
        $New_Value_Pure=~s/\s+(\W)/$1/g;
 
17329
        
15720
17330
        next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
 
17331
        
15721
17332
        if($New_Value_Pure ne $Old_Value_Pure)
15722
17333
        { # different values
15723
 
            if($Level eq "Binary")
15724
 
            {
15725
 
                if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15726
 
                { # ignore library version
15727
 
                    next;
15728
 
                }
15729
 
                if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15730
 
                { # ignore library version
15731
 
                    next;
15732
 
                }
15733
 
                if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15734
 
                { # ignoring path defines:
15735
 
                  #  /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
15736
 
                    next;
15737
 
                }
15738
 
                if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15739
 
                { # ignore source defines:
15740
 
                  #  static int gcry_pth_init ( void) { return ...
15741
 
                  #  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15742
 
                    next;
15743
 
                }
15744
 
                if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15745
 
                { # ignore source defines:
15746
 
                  #  foo(p)
15747
 
                    next;
15748
 
                }
 
17334
            if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value))
 
17335
            { # complex values
 
17336
                next;
 
17337
            }
 
17338
            if(computeValue($Old_Value) eq computeValue($New_Value))
 
17339
            { # expressions
 
17340
                next;
15749
17341
            }
15750
17342
            if(convert_integer($Old_Value) eq convert_integer($New_Value))
15751
17343
            { # 0x0001 and 0x1, 0x1 and 1 equal constants
15759
17351
            { # NULL => 0
15760
17352
                next;
15761
17353
            }
15762
 
            %{$ProblemsWithConstants{$Level}{$Constant}} = (
 
17354
            %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = (
15763
17355
                "Target"=>$Constant,
15764
17356
                "Old_Value"=>$Old_Value,
15765
17357
                "New_Value"=>$New_Value  );
15766
17358
        }
15767
17359
    }
 
17360
    
 
17361
    foreach my $Constant (keys(%{$Constants{2}}))
 
17362
    {
 
17363
        if(not defined $Constants{1}{$Constant}{"Value"})
 
17364
        {
 
17365
            if($SkipConstants{2}{$Constant})
 
17366
            { # skipped by the user
 
17367
                next;
 
17368
            }
 
17369
            
 
17370
            if(my $Header = $Constants{2}{$Constant}{"Header"})
 
17371
            {
 
17372
                if(not is_target_header($Header, 1)
 
17373
                and not is_target_header($Header, 2))
 
17374
                { # user-defined header
 
17375
                    next;
 
17376
                }
 
17377
            }
 
17378
            else {
 
17379
                next;
 
17380
            }
 
17381
            
 
17382
            my $New_Value = uncoverConstant(2, $Constant);
 
17383
            if(not defined $New_Value or $New_Value eq "") {
 
17384
                next;
 
17385
            }
 
17386
            
 
17387
            if(constantFilter($Constant, $New_Value, $Level))
 
17388
            { # separate binary and source problems
 
17389
                next;
 
17390
            }
 
17391
            
 
17392
            %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = (
 
17393
                "Target"=>$Constant,
 
17394
                "New_Value"=>$New_Value  );
 
17395
        }
 
17396
    }
15768
17397
}
15769
17398
 
15770
17399
sub convert_integer($)
15802
17431
            exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15803
17432
        }
15804
17433
    }
15805
 
    my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15806
 
    foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15807
 
        readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
15808
 
    }
 
17434
    
 
17435
    foreach my $LibPath (@LibPaths) {
 
17436
        readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
 
17437
    }
 
17438
    
 
17439
    if($CheckUndefined)
 
17440
    {
 
17441
        my %UndefinedLibs = ();
 
17442
        
 
17443
        my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}}));
 
17444
        
 
17445
        foreach my $LibName (sort @Libs)
 
17446
        {
 
17447
            if(defined $UndefinedSymbols{$LibVersion}{$LibName})
 
17448
            {
 
17449
                foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}}))
 
17450
                {
 
17451
                    if($Symbol_Library{$LibVersion}{$Symbol}
 
17452
                    or $DepSymbol_Library{$LibVersion}{$Symbol})
 
17453
                    { # exported by target library
 
17454
                        next;
 
17455
                    }
 
17456
                    if(index($Symbol, '@')!=-1)
 
17457
                    { # exported default symbol version (@@)
 
17458
                        $Symbol=~s/\@/\@\@/;
 
17459
                        if($Symbol_Library{$LibVersion}{$Symbol}
 
17460
                        or $DepSymbol_Library{$LibVersion}{$Symbol}) {
 
17461
                            next;
 
17462
                        }
 
17463
                    }
 
17464
                    foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) {
 
17465
                        $UndefinedLibs{$Path} = 1;
 
17466
                    }
 
17467
                }
 
17468
            }
 
17469
        }
 
17470
        if($ExtraInfo)
 
17471
        { # extra information for other tools
 
17472
            if(my @Paths = sort keys(%UndefinedLibs))
 
17473
            {
 
17474
                my $LibString = "";
 
17475
                my %Dirs = ();
 
17476
                foreach (@Paths)
 
17477
                {
 
17478
                    $KnownLibs{$_} = 1;
 
17479
                    my ($Dir, $Name) = separate_path($_);
 
17480
                    
 
17481
                    if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) {
 
17482
                        $Dirs{esc($Dir)} = 1;
 
17483
                    }
 
17484
                    
 
17485
                    $Name = parse_libname($Name, "name", $OStarget);
 
17486
                    $Name=~s/\Alib//;
 
17487
                    
 
17488
                    $LibString .= " -l$Name";
 
17489
                }
 
17490
                
 
17491
                foreach my $Dir (sort {$b cmp $a} keys(%Dirs))
 
17492
                {
 
17493
                    $LibString = " -L".esc($Dir).$LibString;
 
17494
                }
 
17495
                
 
17496
                writeFile($ExtraInfo."/libs-string", $LibString);
 
17497
            }
 
17498
        }
 
17499
    }
 
17500
    
 
17501
    if($ExtraInfo) {
 
17502
        writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs)));
 
17503
    }
 
17504
    
15809
17505
    if(not $CheckHeadersOnly)
15810
17506
    {
15811
17507
        if($#LibPaths!=-1)
15819
17515
        }
15820
17516
    }
15821
17517
    
15822
 
    # clean memory
 
17518
   # clean memory
15823
17519
   %SystemObjects = ();
15824
17520
}
15825
17521
 
 
17522
my %Prefix_Lib_Map=(
 
17523
 # symbols for autodetecting library dependencies (by prefix)
 
17524
    "pthread_" => ["libpthread"],
 
17525
    "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"],
 
17526
    "cairo_" => ["libcairo"],
 
17527
    "gtk_" => ["libgtk-x11-2.0"],
 
17528
    "atk_" => ["libatk-1.0"],
 
17529
    "gdk_" => ["libgdk-x11-2.0"],
 
17530
    "gl" => ["libGL"],
 
17531
    "glu" => ["libGLU"],
 
17532
    "popt" => ["libpopt"],
 
17533
    "Py" => ["libpython"],
 
17534
    "jpeg_" => ["libjpeg"],
 
17535
    "BZ2_" => ["libbz2"],
 
17536
    "Fc" => ["libfontconfig"],
 
17537
    "Xft" => ["libXft"],
 
17538
    "SSL_" => ["libssl"],
 
17539
    "sem_" => ["libpthread"],
 
17540
    "snd_" => ["libasound"],
 
17541
    "art_" => ["libart_lgpl_2"],
 
17542
    "dbus_g" => ["libdbus-glib-1"],
 
17543
    "GOMP_" => ["libgomp"],
 
17544
    "omp_" => ["libgomp"],
 
17545
    "cms" => ["liblcms"]
 
17546
);
 
17547
 
 
17548
my %Pattern_Lib_Map=(
 
17549
    "SL[a-z]" => ["libslang"]
 
17550
);
 
17551
 
 
17552
my %Symbol_Lib_Map=(
 
17553
 # symbols for autodetecting library dependencies (by name)
 
17554
    "pow" => "libm",
 
17555
    "fmod" => "libm",
 
17556
    "sin" => "libm",
 
17557
    "floor" => "libm",
 
17558
    "cos" => "libm",
 
17559
    "dlopen" => "libdl",
 
17560
    "deflate" => "libz",
 
17561
    "inflate" => "libz",
 
17562
    "move_panel" => "libpanel",
 
17563
    "XOpenDisplay" => "libX11",
 
17564
    "resize_term" => "libncurses",
 
17565
    "clock_gettime" => "librt",
 
17566
    "crypt" => "libcrypt"
 
17567
);
 
17568
 
 
17569
sub find_SymbolLibs($$)
 
17570
{
 
17571
    my ($LibVersion, $Symbol) = @_;
 
17572
    
 
17573
    if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/)
 
17574
    { # debug symbols
 
17575
        return ();
 
17576
    }
 
17577
    
 
17578
    my %Paths = ();
 
17579
    
 
17580
    if(my $LibName = $Symbol_Lib_Map{$Symbol})
 
17581
    {
 
17582
        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
 
17583
            $Paths{$Path} = 1;
 
17584
        }
 
17585
    }
 
17586
    
 
17587
    if(my $SymbolPrefix = getPrefix($Symbol))
 
17588
    {
 
17589
        if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) {
 
17590
            return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}};
 
17591
        }
 
17592
    
 
17593
        if(not keys(%Paths))
 
17594
        {
 
17595
            if(defined $Prefix_Lib_Map{$SymbolPrefix})
 
17596
            {
 
17597
                foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}})
 
17598
                {
 
17599
                    if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
 
17600
                        $Paths{$Path} = 1;
 
17601
                    }
 
17602
                }
 
17603
            }
 
17604
        }
 
17605
        
 
17606
        if(not keys(%Paths))
 
17607
        {
 
17608
            foreach my $Prefix (sort keys(%Pattern_Lib_Map))
 
17609
            {
 
17610
                if($Symbol=~/\A$Prefix/)
 
17611
                {
 
17612
                    foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}})
 
17613
                    {
 
17614
                        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
 
17615
                            $Paths{$Path} = 1;
 
17616
                        }
 
17617
                    }
 
17618
                }
 
17619
            }
 
17620
        }
 
17621
    
 
17622
        if(not keys(%Paths))
 
17623
        {
 
17624
            if($SymbolPrefix)
 
17625
            { # try to find a library by symbol prefix
 
17626
                if($SymbolPrefix eq "inotify" and
 
17627
                index($Symbol, "\@GLIBC")!=-1)
 
17628
                {
 
17629
                    if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) {
 
17630
                        $Paths{$Path} = 1;
 
17631
                    }
 
17632
                }
 
17633
                else
 
17634
                {
 
17635
                    if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) {
 
17636
                        $Paths{$Path} = 1;
 
17637
                    }
 
17638
                }
 
17639
            }
 
17640
        }
 
17641
        
 
17642
        if(my @Paths = keys(%Paths)) {
 
17643
            $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths;
 
17644
        }
 
17645
    }
 
17646
    return keys(%Paths);
 
17647
}
 
17648
 
 
17649
sub get_LibPath_Prefix($$)
 
17650
{
 
17651
    my ($LibVersion, $Prefix) = @_;
 
17652
    
 
17653
    $Prefix = lc($Prefix);
 
17654
    $Prefix=~s/[_]+\Z//g;
 
17655
    
 
17656
    foreach ("-2", "2", "-1", "1", "")
 
17657
    { # libgnome-2.so
 
17658
      # libxml2.so
 
17659
      # libdbus-1.so
 
17660
        if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) {
 
17661
            return $Path;
 
17662
        }
 
17663
    }
 
17664
    return "";
 
17665
}
 
17666
 
 
17667
sub getPrefix($)
 
17668
{
 
17669
    my $Str = $_[0];
 
17670
    if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
 
17671
    { # XmuValidArea: Xmu
 
17672
        return $1;
 
17673
    }
 
17674
    elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
 
17675
    { # snfReadFont: snf
 
17676
        return $1;
 
17677
    }
 
17678
    elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
 
17679
    { # XRRTimes: XRR
 
17680
        return $1;
 
17681
    }
 
17682
    elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i)
 
17683
    { # H5HF_delete: H5
 
17684
        return $1;
 
17685
    }
 
17686
    elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
 
17687
    { # alarm_event_add: alarm_
 
17688
        return $1;
 
17689
    }
 
17690
    elsif($Str=~/\A(([a-z])\2{1,})/i)
 
17691
    { # ffopen
 
17692
        return $1;
 
17693
    }
 
17694
    return "";
 
17695
}
 
17696
 
15826
17697
sub getSymbolSize($$)
15827
17698
{ # size from the shared library
15828
17699
    my ($Symbol, $LibVersion) = @_;
15841
17712
    return 0;
15842
17713
}
15843
17714
 
15844
 
sub canonifyName($)
 
17715
sub canonifyName($$)
15845
17716
{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
15846
17717
  # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
15847
 
    my $Name = $_[0];
15848
 
    my $Rem = "std::(allocator|less|char_traits|regex_traits)";
15849
 
    while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
 
17718
    my ($Name, $Type) = @_;
 
17719
    
 
17720
    # single
 
17721
    while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
15850
17722
    {
15851
17723
        my $P = $1;
15852
 
        $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
 
17724
        $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
 
17725
    }
 
17726
    
 
17727
    # double
 
17728
    if($Name=~/$DEFAULT_STD_PARMS/)
 
17729
    {
 
17730
        if($Type eq "S")
 
17731
        {
 
17732
            my ($ShortName, $FuncParams) = split_Signature($Name);
 
17733
            
 
17734
            foreach my $FParam (separate_Params($FuncParams, 0, 0))
 
17735
            {
 
17736
                if(index($FParam, "<")!=-1)
 
17737
                {
 
17738
                    $FParam=~s/>([^<>]+)\Z/>/; # remove quals
 
17739
                    my $FParam_N = canonifyName($FParam, "T");
 
17740
                    if($FParam_N ne $FParam) {
 
17741
                        $Name=~s/\Q$FParam\E/$FParam_N/g;
 
17742
                    }
 
17743
                }
 
17744
            }
 
17745
        }
 
17746
        elsif($Type eq "T")
 
17747
        {
 
17748
            my ($ShortTmpl, $TmplParams) = template_Base($Name);
 
17749
            
 
17750
            my @TParams = separate_Params($TmplParams, 0, 0);
 
17751
            if($#TParams>=1)
 
17752
            {
 
17753
                my $FParam = $TParams[0];
 
17754
                foreach my $Pos (1 .. $#TParams)
 
17755
                {
 
17756
                    my $TParam = $TParams[$Pos];
 
17757
                    if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
 
17758
                        $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
 
17759
                    }
 
17760
                }
 
17761
            }
 
17762
        }
 
17763
    }
 
17764
    if($Type eq "S") {
 
17765
        return formatName($Name, "S");
15853
17766
    }
15854
17767
    return $Name;
15855
17768
}
15858
17771
{
15859
17772
    my $LibVersion = pop(@_);
15860
17773
    my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
15861
 
    foreach my $Interface (sort @_)
 
17774
    foreach my $Symbol (sort @_)
15862
17775
    {
15863
 
        if($Interface=~/\A_Z/)
 
17776
        if(index($Symbol, "_Z")==0)
15864
17777
        {
15865
 
            next if($tr_name{$Interface});
15866
 
            $Interface=~s/[\@\$]+(.*)\Z//;
15867
 
            push(@MnglNames1, $Interface);
 
17778
            next if($tr_name{$Symbol});
 
17779
            $Symbol=~s/[\@\$]+(.*)\Z//;
 
17780
            push(@MnglNames1, $Symbol);
15868
17781
        }
15869
 
        elsif($Interface=~/\A\?/) {
15870
 
            push(@MnglNames2, $Interface);
 
17782
        elsif(index($Symbol, "?")==0)
 
17783
        {
 
17784
            next if($tr_name{$Symbol});
 
17785
            push(@MnglNames2, $Symbol);
15871
17786
        }
15872
17787
        else
15873
17788
        { # not mangled
15874
 
            $tr_name{$Interface} = $Interface;
15875
 
            $mangled_name_gcc{$Interface} = $Interface;
15876
 
            $mangled_name{$LibVersion}{$Interface} = $Interface;
 
17789
            $tr_name{$Symbol} = $Symbol;
 
17790
            $mangled_name_gcc{$Symbol} = $Symbol;
 
17791
            $mangled_name{$LibVersion}{$Symbol} = $Symbol;
15877
17792
        }
15878
17793
    }
15879
17794
    if($#MnglNames1 > -1)
15883
17798
        {
15884
17799
            if(my $Unmangled = pop(@UnmangledNames))
15885
17800
            {
15886
 
                $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
 
17801
                $tr_name{$MnglName} = canonifyName($Unmangled, "S");
15887
17802
                if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
15888
17803
                    $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
15889
17804
                }
15890
 
                if($MnglName=~/\A_ZTV/
 
17805
                if(index($MnglName, "_ZTV")==0
15891
17806
                and $tr_name{$MnglName}=~/vtable for (.+)/)
15892
17807
                { # bind class name and v-table symbol
15893
17808
                    my $ClassName = $1;
15904
17819
        {
15905
17820
            if(my $Unmangled = pop(@UnmangledNames))
15906
17821
            {
15907
 
                $tr_name{$MnglName} = formatName($Unmangled);
 
17822
                $tr_name{$MnglName} = formatName($Unmangled, "S");
15908
17823
                $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
15909
17824
            }
15910
17825
        }
15938
17853
    if(my $VSym = $SymVer{$RunWith}{$Symbol})
15939
17854
    { # indirect symbol version, i.e.
15940
17855
      # foo_old and its symlink foo@v (or foo@@v)
15941
 
      # foo_old may be in .symtab table
 
17856
      # foo_old may be in symtab table
15942
17857
        if($Where->{$RunWith}{$VSym}) {
15943
17858
            return 1;
15944
17859
        }
15969
17884
sub readSymbols_App($)
15970
17885
{
15971
17886
    my $Path = $_[0];
15972
 
    return () if(not $Path or not -f $Path);
 
17887
    return () if(not $Path);
15973
17888
    my @Imported = ();
15974
17889
    if($OSgroup eq "macos")
15975
17890
    {
15976
 
        my $OtoolCmd = get_CmdPath("otool");
15977
 
        if(not $OtoolCmd) {
15978
 
            exitStatus("Not_Found", "can't find \"otool\"");
 
17891
        my $NM = get_CmdPath("nm");
 
17892
        if(not $NM) {
 
17893
            exitStatus("Not_Found", "can't find \"nm\"");
15979
17894
        }
15980
 
        open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
15981
 
        while(<APP>) {
15982
 
            if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
 
17895
        open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
 
17896
        while(<APP>)
 
17897
        {
 
17898
            if(/ U _([\w\$]+)\s*\Z/) {
15983
17899
                push(@Imported, $1);
15984
17900
            }
15985
17901
        }
15991
17907
        if(not $DumpBinCmd) {
15992
17908
            exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
15993
17909
        }
15994
 
        open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
15995
 
        while(<APP>) {
 
17910
        open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
 
17911
        while(<APP>)
 
17912
        {
15996
17913
            if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
15997
17914
                push(@Imported, $1);
15998
17915
            }
16005
17922
        if(not $ReadelfCmd) {
16006
17923
            exitStatus("Not_Found", "can't find \"readelf\"");
16007
17924
        }
16008
 
        open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
16009
 
        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
 
17925
        open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
 
17926
        my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
16010
17927
        while(<APP>)
16011
17928
        {
16012
 
            if( /'.dynsym'/ ) {
16013
 
                $symtab=0;
16014
 
            }
16015
 
            elsif($symtab == 1) {
16016
 
                # do nothing with symtab (but there are some plans for the future)
16017
 
                next;
16018
 
            }
16019
 
            elsif( /'.symtab'/ ) {
16020
 
                $symtab=1;
16021
 
            }
16022
 
            elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
 
17929
            if(defined $symtab)
 
17930
            { # do nothing with symtab
 
17931
                if(index($_, "'.dynsym'")!=-1)
 
17932
                { # dynamic table
 
17933
                    $symtab = undef;
 
17934
                }
 
17935
            }
 
17936
            elsif(index($_, "'.symtab'")!=-1)
 
17937
            { # symbol table
 
17938
                $symtab = 1;
 
17939
            }
 
17940
            elsif(my @Info = readline_ELF($_))
16023
17941
            {
16024
 
                if( $Ndx eq "UND" ) {
16025
 
                    #only imported symbols
16026
 
                    push(@Imported, $fullname);
 
17942
                my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
 
17943
                if($Ndx eq "UND")
 
17944
                { # only imported symbols
 
17945
                    push(@Imported, $Symbol);
16027
17946
                }
16028
17947
            }
16029
17948
        }
16032
17951
    return @Imported;
16033
17952
}
16034
17953
 
 
17954
my %ELF_BIND = map {$_=>1} (
 
17955
    "WEAK",
 
17956
    "GLOBAL"
 
17957
);
 
17958
 
 
17959
my %ELF_TYPE = map {$_=>1} (
 
17960
    "FUNC",
 
17961
    "IFUNC",
 
17962
    "OBJECT",
 
17963
    "COMMON"
 
17964
);
 
17965
 
 
17966
my %ELF_VIS = map {$_=>1} (
 
17967
    "DEFAULT",
 
17968
    "PROTECTED"
 
17969
);
 
17970
 
16035
17971
sub readline_ELF($)
16036
 
{
16037
 
    if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16038
 
    { # the line of 'readelf' output corresponding to the interface
16039
 
      # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16040
 
        my ($value, $size, $type, $bind,
16041
 
        $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16042
 
        if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16043
 
            return ();
16044
 
        }
16045
 
        if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16046
 
            return ();
16047
 
        }
16048
 
        if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16049
 
            return ();
16050
 
        }
16051
 
        if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16052
 
            return ();
16053
 
        }
16054
 
        if($OStarget eq "symbian")
16055
 
        {
16056
 
            if($fullname=~/_\._\.absent_export_\d+/)
16057
 
            { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16058
 
                return ();
16059
 
            }
16060
 
            my @Elems = separate_symbol($fullname);
16061
 
            $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
16062
 
        }
16063
 
        return ($fullname, $value, $Ndx, $type, $size, $bind);
16064
 
    }
16065
 
    return ();
16066
 
}
16067
 
 
16068
 
sub read_symlink($)
16069
 
{
16070
 
    my $Path = $_[0];
16071
 
    return "" if(not $Path);
16072
 
    return "" if(not -f $Path and not -l $Path);
16073
 
    if(defined $Cache{"read_symlink"}{$Path}) {
16074
 
        return $Cache{"read_symlink"}{$Path};
16075
 
    }
16076
 
    if(my $Res = readlink($Path)) {
16077
 
        return ($Cache{"read_symlink"}{$Path} = $Res);
16078
 
    }
16079
 
    elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
16080
 
        return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
16081
 
    }
16082
 
    elsif(my $FileCmd = get_CmdPath("file"))
16083
 
    {
16084
 
        my $Info = `$FileCmd $Path`;
16085
 
        if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16086
 
            return ($Cache{"read_symlink"}{$Path} = $1);
16087
 
        }
16088
 
    }
16089
 
    return ($Cache{"read_symlink"}{$Path} = "");
16090
 
}
16091
 
 
16092
 
sub resolve_symlink($)
16093
 
{
16094
 
    my $Path = $_[0];
16095
 
    return "" if(not $Path);
16096
 
    return "" if(not -f $Path and not -l $Path);
16097
 
    if(defined $Cache{"resolve_symlink"}{$Path}) {
16098
 
        return $Cache{"resolve_symlink"}{$Path};
16099
 
    }
16100
 
    return $Path if(isCyclical(\@RecurSymlink, $Path));
16101
 
    push(@RecurSymlink, $Path);
16102
 
    if(-l $Path and my $Redirect=read_symlink($Path))
16103
 
    {
16104
 
        if(is_abs($Redirect))
 
17972
{ # read the line of 'readelf' output corresponding to the symbol
 
17973
    my @Info = split(/\s+/, $_[0]);
 
17974
    #  Num:   Value      Size Type   Bind   Vis       Ndx  Name
 
17975
    #  3629:  000b09c0   32   FUNC   GLOBAL DEFAULT   13   _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
 
17976
    #  135:   00000000    0   FUNC   GLOBAL DEFAULT   UND  av_image_fill_pointers@LIBAVUTIL_52 (3)
 
17977
    shift(@Info); # spaces
 
17978
    shift(@Info); # num
 
17979
    
 
17980
    if($#Info==7)
 
17981
    { # UND SYMBOL (N)
 
17982
        if($Info[7]=~/\(\d+\)/) {
 
17983
            pop(@Info);
 
17984
        }
 
17985
    }
 
17986
    
 
17987
    if($#Info!=6)
 
17988
    { # other lines
 
17989
        return ();
 
17990
    }
 
17991
    return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND");
 
17992
    return () if(not defined $ELF_BIND{$Info[3]});
 
17993
    return () if(not defined $ELF_VIS{$Info[4]});
 
17994
    if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
 
17995
    { # 1272: 00000000     0 OBJECT  GLOBAL DEFAULT  ABS CXXABI_1.3
 
17996
        return ();
 
17997
    }
 
17998
    if($OStarget eq "symbian")
 
17999
    { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
 
18000
        if(index($Info[6], "_._.absent_export_")!=-1)
 
18001
        { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
 
18002
            return ();
 
18003
        }
 
18004
        $Info[6]=~s/\@.+//g; # remove version
 
18005
    }
 
18006
    if(index($Info[2], "0x") == 0)
 
18007
    { # size == 0x3d158
 
18008
        $Info[2] = hex($Info[2]);
 
18009
    }
 
18010
    return @Info;
 
18011
}
 
18012
 
 
18013
sub get_LibPath($$)
 
18014
{
 
18015
    my ($LibVersion, $Name) = @_;
 
18016
    return "" if(not $LibVersion or not $Name);
 
18017
    if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
 
18018
        return $Cache{"get_LibPath"}{$LibVersion}{$Name};
 
18019
    }
 
18020
    return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
 
18021
}
 
18022
 
 
18023
sub get_LibPath_I($$)
 
18024
{
 
18025
    my ($LibVersion, $Name) = @_;
 
18026
    if(is_abs($Name))
 
18027
    {
 
18028
        if(-f $Name)
16105
18029
        { # absolute path
16106
 
            if($SystemRoot and $SystemRoot ne "/"
16107
 
            and $Path=~/\A\Q$SystemRoot\E\//
16108
 
            and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16109
 
            { # symbolic links from the sysroot
16110
 
              # should be corrected to point to
16111
 
              # the files inside sysroot
16112
 
                $Redirect = $SystemRoot.$Redirect;
16113
 
            }
16114
 
            my $Res = resolve_symlink($Redirect);
16115
 
            pop(@RecurSymlink);
16116
 
            return ($Cache{"resolve_symlink"}{$Path} = $Res);
16117
 
        }
16118
 
        elsif($Redirect=~/\.\.[\/\\]/)
16119
 
        { # relative path
16120
 
            $Redirect = joinPath(get_dirname($Path), $Redirect);
16121
 
            while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16122
 
            my $Res = resolve_symlink($Redirect);
16123
 
            pop(@RecurSymlink);
16124
 
            return ($Cache{"resolve_symlink"}{$Path} = $Res);
16125
 
        }
16126
 
        elsif(-f get_dirname($Path)."/".$Redirect)
16127
 
        { # file name in the same directory
16128
 
            my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
16129
 
            pop(@RecurSymlink);
16130
 
            return ($Cache{"resolve_symlink"}{$Path} = $Res);
 
18030
            return $Name;
16131
18031
        }
16132
18032
        else
16133
 
        { # broken link
16134
 
            pop(@RecurSymlink);
16135
 
            return ($Cache{"resolve_symlink"}{$Path} = "");
16136
 
        }
16137
 
    }
16138
 
    pop(@RecurSymlink);
16139
 
    return ($Cache{"resolve_symlink"}{$Path} = $Path);
16140
 
}
16141
 
 
16142
 
sub find_lib_path($$)
16143
 
{
16144
 
    my ($LibVersion, $DyLib) = @_;
16145
 
    return "" if(not $DyLib or not $LibVersion);
16146
 
    return $DyLib if(is_abs($DyLib));
16147
 
    if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16148
 
        return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16149
 
    }
16150
 
    if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16151
 
        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16152
 
    }
16153
 
    elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16154
 
        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16155
 
    }
16156
 
    else
 
18033
        { # broken
 
18034
            return "";
 
18035
        }
 
18036
    }
 
18037
    if(defined $RegisteredObjects{$LibVersion}{$Name})
 
18038
    { # registered paths
 
18039
        return $RegisteredObjects{$LibVersion}{$Name};
 
18040
    }
 
18041
    if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
 
18042
    { # registered paths
 
18043
        return $RegisteredSONAMEs{$LibVersion}{$Name};
 
18044
    }
 
18045
    if(my $DefaultPath = $DyLib_DefaultPath{$Name})
 
18046
    { # ldconfig default paths
 
18047
        return $DefaultPath;
 
18048
    }
 
18049
    foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}})
 
18050
    { # search in default linker directories
 
18051
      # and then in all system paths
 
18052
        if(-f $Dir."/".$Name) {
 
18053
            return join_P($Dir,$Name);
 
18054
        }
 
18055
    }
 
18056
    detectSystemObjects() if(not keys(%SystemObjects));
 
18057
    if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
 
18058
        return $AllObjects[0];
 
18059
    }
 
18060
    if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16157
18061
    {
16158
 
        foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16159
 
        { # search in default linker paths and then in all system paths
16160
 
            if(-f $Dir."/".$DyLib) {
16161
 
                return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16162
 
            }
16163
 
        }
16164
 
        detectSystemObjects() if(not keys(%SystemObjects));
16165
 
        if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16166
 
            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16167
 
        }
16168
 
        my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16169
 
        if($ShortName ne $DyLib
16170
 
        and my $Path = find_lib_path($ShortName))
 
18062
        if($ShortName ne $Name)
16171
18063
        { # FIXME: check this case
16172
 
            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
 
18064
            if(my $Path = get_LibPath($LibVersion, $ShortName)) {
 
18065
                return $Path;
 
18066
            }
16173
18067
        }
16174
 
        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16175
18068
    }
 
18069
    # can't find
 
18070
    return "";
16176
18071
}
16177
18072
 
16178
 
sub readSymbols_Lib($$$$$)
 
18073
sub readSymbols_Lib($$$$$$)
16179
18074
{
16180
 
    my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16181
 
    return if(not $Lib_Path or not -f $Lib_Path);
16182
 
    my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16183
 
    return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16184
 
    return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
 
18075
    my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
 
18076
    return () if(not $LibVersion or not $Lib_Path);
 
18077
    
 
18078
    my $Real_Path = realpath($Lib_Path);
 
18079
    
 
18080
    if(not $Real_Path)
 
18081
    { # broken link
 
18082
        return ();
 
18083
    }
 
18084
    
 
18085
    my $Lib_Name = get_filename($Real_Path);
 
18086
    
 
18087
    if($ExtraInfo)
 
18088
    {
 
18089
        $KnownLibs{$Real_Path} = 1;
 
18090
        $KnownLibs{$Lib_Path} = 1; # links
 
18091
    }
 
18092
    
 
18093
    if($IsNeededLib)
 
18094
    {
 
18095
        if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
 
18096
            return ();
 
18097
        }
 
18098
    }
 
18099
    return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16185
18100
    $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
16186
 
    my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16187
18101
    
16188
 
    if($CheckImpl and not $IsNeededLib) {
16189
 
        getImplementations($LibVersion, $Lib_Path);
 
18102
    if($CheckImpl)
 
18103
    {
 
18104
        if(not $IsNeededLib) {
 
18105
            getImplementations($LibVersion, $Lib_Path);
 
18106
        }
16190
18107
    }
16191
18108
    
16192
18109
    push(@RecurLib, $Lib_Name);
16193
18110
    my (%Value_Interface, %Interface_Value, %NeededLib) = ();
 
18111
    my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
 
18112
    
16194
18113
    if(not $IsNeededLib)
16195
 
    { # libstdc++ and libc are always used by other libs
16196
 
      # if you test one of these libs then you not need
16197
 
      # to find them in the system for reusing
16198
 
        if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16199
 
        { # libstdc++.so.6
16200
 
            $STDCXX_TESTING = 1;
16201
 
        }
16202
 
        if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16203
 
        { # libc-2.11.3.so
16204
 
            $GLIBC_TESTING = 1;
 
18114
    { # special cases: libstdc++ and libc
 
18115
        if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget))
 
18116
        {
 
18117
            if($ShortName eq "libstdc++")
 
18118
            { # libstdc++.so.6
 
18119
                $STDCXX_TESTING = 1;
 
18120
            }
 
18121
            elsif($ShortName eq "libc")
 
18122
            { # libc-2.11.3.so
 
18123
                $GLIBC_TESTING = 1;
 
18124
            }
16205
18125
        }
16206
18126
    }
16207
18127
    my $DebugPath = "";
16208
 
    if($Debug)
 
18128
    if($Debug and not $DumpSystem)
16209
18129
    { # debug mode
16210
18130
        $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
16211
18131
        mkpath(get_dirname($DebugPath));
16212
18132
    }
16213
18133
    if($OStarget eq "macos")
16214
18134
    { # Mac OS X: *.dylib, *.a
16215
 
        my $OtoolCmd = get_CmdPath("otool");
16216
 
        if(not $OtoolCmd) {
16217
 
            exitStatus("Not_Found", "can't find \"otool\"");
 
18135
        my $NM = get_CmdPath("nm");
 
18136
        if(not $NM) {
 
18137
            exitStatus("Not_Found", "can't find \"nm\"");
16218
18138
        }
16219
 
        $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
16220
 
        if($Debug)
 
18139
        $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
 
18140
        if($DebugPath)
16221
18141
        { # debug mode
16222
18142
          # write to file
16223
 
            system($OtoolCmd." >".$DebugPath);
 
18143
            system($NM." >\"$DebugPath\"");
16224
18144
            open(LIB, $DebugPath);
16225
18145
        }
16226
18146
        else
16227
18147
        { # write to pipe
16228
 
            open(LIB, $OtoolCmd." |");
 
18148
            open(LIB, $NM." |");
16229
18149
        }
16230
18150
        while(<LIB>)
16231
18151
        {
16232
 
            if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16233
 
            {
16234
 
                my $realname = $1;
 
18152
            if($CheckUndefined)
 
18153
            {
 
18154
                if(not $IsNeededLib)
 
18155
                {
 
18156
                    if(/ U _([\w\$]+)\s*\Z/)
 
18157
                    {
 
18158
                        $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0;
 
18159
                        next;
 
18160
                    }
 
18161
                }
 
18162
            }
 
18163
            
 
18164
            if(/ [STD] _([\w\$]+)\s*\Z/)
 
18165
            {
 
18166
                my $Symbol = $1;
16235
18167
                if($IsNeededLib)
16236
18168
                {
16237
 
                    if(not $GroupNames->{$Lib_SName})
 
18169
                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
16238
18170
                    {
16239
 
                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16240
 
                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
 
18171
                        $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
 
18172
                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
16241
18173
                    }
16242
18174
                }
16243
18175
                else
16244
18176
                {
16245
 
                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16246
 
                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16247
 
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16248
 
                    and $realname=~/\A(_Z|\?)/) {
16249
 
                        setLanguage($LibVersion, "C++");
 
18177
                    $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
 
18178
                    $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
 
18179
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
 
18180
                    {
 
18181
                        if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
 
18182
                            setLanguage($LibVersion, "C++");
 
18183
                        }
16250
18184
                    }
16251
18185
                    if($CheckObjectsOnly
16252
18186
                    and $LibVersion==1) {
16253
 
                        $CheckedSymbols{"Binary"}{$realname} = 1;
 
18187
                        $CheckedSymbols{"Binary"}{$Symbol} = 1;
16254
18188
                    }
16255
18189
                }
16256
18190
            }
16257
18191
        }
16258
18192
        close(LIB);
16259
 
        if($LIB_TYPE eq "dynamic")
16260
 
        { # dependencies
16261
 
            open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16262
 
            while(<LIB>)
16263
 
            {
16264
 
                if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16265
 
                and $1 ne $Lib_Path) {
16266
 
                    $NeededLib{$1} = 1;
16267
 
                }
 
18193
        
 
18194
        if($Deps)
 
18195
        {
 
18196
            if($LIB_TYPE eq "dynamic")
 
18197
            { # dependencies
 
18198
                
 
18199
                my $OtoolCmd = get_CmdPath("otool");
 
18200
                if(not $OtoolCmd) {
 
18201
                    exitStatus("Not_Found", "can't find \"otool\"");
 
18202
                }
 
18203
                
 
18204
                open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
 
18205
                while(<LIB>)
 
18206
                {
 
18207
                    if(/\s*([\/\\].+\.$LIB_EXT)\s*/
 
18208
                    and $1 ne $Lib_Path) {
 
18209
                        $NeededLib{$1} = 1;
 
18210
                    }
 
18211
                }
 
18212
                close(LIB);
16268
18213
            }
16269
 
            close(LIB);
16270
18214
        }
16271
18215
    }
16272
18216
    elsif($OStarget eq "windows")
16276
18220
            exitStatus("Not_Found", "can't find \"dumpbin\"");
16277
18221
        }
16278
18222
        $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
16279
 
        if($Debug)
 
18223
        if($DebugPath)
16280
18224
        { # debug mode
16281
18225
          # write to file
16282
 
            system($DumpBinCmd." >".$DebugPath);
 
18226
            system($DumpBinCmd." >\"$DebugPath\"");
16283
18227
            open(LIB, $DebugPath);
16284
18228
        }
16285
18229
        else
16297
18241
                my $realname = $1;
16298
18242
                if($IsNeededLib)
16299
18243
                {
16300
 
                    if(not $GroupNames->{$Lib_SName})
 
18244
                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
16301
18245
                    {
16302
18246
                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16303
18247
                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16307
18251
                {
16308
18252
                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16309
18253
                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16310
 
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16311
 
                    and $realname=~/\A(_Z|\?)/) {
16312
 
                        setLanguage($LibVersion, "C++");
 
18254
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
 
18255
                    {
 
18256
                        if(index($realname, "_Z")==0 or index($realname, "?")==0) {
 
18257
                            setLanguage($LibVersion, "C++");
 
18258
                        }
16313
18259
                    }
16314
18260
                    if($CheckObjectsOnly
16315
18261
                    and $LibVersion==1) {
16319
18265
            }
16320
18266
        }
16321
18267
        close(LIB);
16322
 
        if($LIB_TYPE eq "dynamic")
16323
 
        { # dependencies
16324
 
            open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16325
 
            while(<LIB>)
16326
 
            {
16327
 
                if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16328
 
                and $1 ne $Lib_Path) {
16329
 
                    $NeededLib{path_format($1, $OSgroup)} = 1;
 
18268
        if($Deps)
 
18269
        {
 
18270
            if($LIB_TYPE eq "dynamic")
 
18271
            { # dependencies
 
18272
                open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
 
18273
                while(<LIB>)
 
18274
                {
 
18275
                    if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
 
18276
                    and $1 ne $Lib_Path) {
 
18277
                        $NeededLib{path_format($1, $OSgroup)} = 1;
 
18278
                    }
16330
18279
                }
 
18280
                close(LIB);
16331
18281
            }
16332
 
            close(LIB);
16333
18282
        }
16334
18283
    }
16335
18284
    else
16339
18288
        if(not $ReadelfCmd) {
16340
18289
            exitStatus("Not_Found", "can't find \"readelf\"");
16341
18290
        }
16342
 
        $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
16343
 
        if($Debug)
 
18291
        $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
 
18292
        if($DebugPath)
16344
18293
        { # debug mode
16345
18294
          # write to file
16346
 
            system($ReadelfCmd." >".$DebugPath);
 
18295
            system($ReadelfCmd." >\"$DebugPath\"");
16347
18296
            open(LIB, $DebugPath);
16348
18297
        }
16349
18298
        else
16350
18299
        { # write to pipe
16351
18300
            open(LIB, $ReadelfCmd." |");
16352
18301
        }
16353
 
        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
 
18302
        my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
16354
18303
        while(<LIB>)
16355
18304
        {
16356
18305
            if($LIB_TYPE eq "dynamic")
16357
18306
            { # dynamic library specifics
16358
 
                if($symtab==1)
 
18307
                if(defined $symtab)
16359
18308
                {
16360
 
                    if(/'\.dynsym'/)
 
18309
                    if(index($_, "'.dynsym'")!=-1)
16361
18310
                    { # dynamic table
16362
 
                        $symtab=0;
16363
 
                        next;
16364
 
                    }
16365
 
                    else
16366
 
                    { # do nothing with symtab
16367
 
                        next;
16368
 
                    }
 
18311
                        $symtab = undef;
 
18312
                    }
 
18313
                    # do nothing with symtab
 
18314
                    next;
16369
18315
                }
16370
 
                elsif(/'\.symtab'/)
 
18316
                elsif(index($_, "'.symtab'")!=-1)
16371
18317
                { # symbol table
16372
 
                    $symtab=1;
 
18318
                    $symtab = 1;
16373
18319
                    next;
16374
18320
                }
16375
18321
            }
16376
 
            if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
 
18322
            if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
16377
18323
            { # read ELF entry
16378
 
                if( $Ndx eq "UND" )
 
18324
                if($Ndx eq "UND")
16379
18325
                { # ignore interfaces that are imported from somewhere else
16380
 
                    next;
16381
 
                }
16382
 
                if($bind eq "WEAK"
16383
 
                and $Weak eq "-Weak")
16384
 
                { # skip WEAK symbols
16385
 
                    next;
16386
 
                }
16387
 
                my ($realname, $version_spec, $version) = separate_symbol($fullname);
16388
 
                if($type eq "OBJECT")
 
18326
                    if($CheckUndefined)
 
18327
                    {
 
18328
                        if(not $IsNeededLib) {
 
18329
                            $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0;
 
18330
                        }
 
18331
                    }
 
18332
                    next;
 
18333
                }
 
18334
                if($Bind eq "WEAK")
 
18335
                {
 
18336
                    $WeakSymbols{$LibVersion}{$Symbol} = 1;
 
18337
                    if($Weak eq "-Weak")
 
18338
                    { # skip WEAK symbols
 
18339
                        next;
 
18340
                    }
 
18341
                }
 
18342
                my $Short = $Symbol;
 
18343
                $Short=~s/\@.+//g;
 
18344
                if($Type eq "OBJECT")
16389
18345
                { # global data
16390
 
                    $GlobalDataObject{$LibVersion}{$fullname} = 1;
16391
 
                    $GlobalDataObject{$LibVersion}{$realname} = 1;
 
18346
                    $GlobalDataObject{$LibVersion}{$Symbol} = $Size;
 
18347
                    $GlobalDataObject{$LibVersion}{$Short} = $Size;
16392
18348
                }
16393
18349
                if($IsNeededLib)
16394
18350
                {
16395
 
                    if(not $GroupNames->{$Lib_SName})
 
18351
                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
16396
18352
                    {
16397
 
                        $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16398
 
                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
 
18353
                        $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
 
18354
                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
16399
18355
                    }
16400
18356
                }
16401
18357
                else
16402
18358
                {
16403
 
                    $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16404
 
                    $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16405
 
                    if($LIB_EXT eq "so")
16406
 
                    { # value
16407
 
                        $Interface_Value{$LibVersion}{$fullname} = $idx;
16408
 
                        $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
 
18359
                    $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
 
18360
                    $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
 
18361
                    if($Vers)
 
18362
                    {
 
18363
                        if($LIB_EXT eq "so")
 
18364
                        { # value
 
18365
                            $Interface_Value{$LibVersion}{$Symbol} = $Value;
 
18366
                            $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
 
18367
                        }
16409
18368
                    }
16410
 
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16411
 
                    and $realname=~/\A(_Z|\?)/) {
16412
 
                        setLanguage($LibVersion, "C++");
 
18369
                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
 
18370
                    {
 
18371
                        if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
 
18372
                            setLanguage($LibVersion, "C++");
 
18373
                        }
16413
18374
                    }
16414
18375
                    if($CheckObjectsOnly
16415
18376
                    and $LibVersion==1) {
16416
 
                        $CheckedSymbols{"Binary"}{$fullname} = 1;
 
18377
                        $CheckedSymbols{"Binary"}{$Symbol} = 1;
16417
18378
                    }
16418
18379
                }
16419
18380
            }
16420
18381
            elsif($LIB_TYPE eq "dynamic")
16421
18382
            { # dynamic library specifics
16422
 
                if(/NEEDED.+\[([^\[\]]+)\]/)
16423
 
                { # dependencies:
16424
 
                  # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16425
 
                    $NeededLib{$1} = 1;
 
18383
                if($Deps)
 
18384
                {
 
18385
                    if(/NEEDED.+\[([^\[\]]+)\]/)
 
18386
                    { # dependencies:
 
18387
                      # 0x00000001 (NEEDED) Shared library: [libc.so.6]
 
18388
                        $NeededLib{$1} = 1;
 
18389
                    }
16426
18390
                }
16427
18391
            }
16428
18392
        }
16429
18393
        close(LIB);
16430
18394
    }
16431
 
    if(not $IsNeededLib and $LIB_EXT eq "so")
16432
 
    { # get symbol versions
16433
 
        foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
 
18395
    if($Vers)
 
18396
    {
 
18397
        if(not $IsNeededLib and $LIB_EXT eq "so")
 
18398
        { # get symbol versions
 
18399
            my %Found = ();
 
18400
            
 
18401
            # by value
 
18402
            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
 
18403
            {
 
18404
                next if(index($Symbol,"\@")==-1);
 
18405
                if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
 
18406
                {
 
18407
                    foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
 
18408
                    {
 
18409
                        if($Symbol_SameValue ne $Symbol
 
18410
                        and index($Symbol_SameValue,"\@")==-1)
 
18411
                        {
 
18412
                            $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
 
18413
                            $Found{$Symbol} = 1;
 
18414
                            last;
 
18415
                        }
 
18416
                    }
 
18417
                }
 
18418
            }
 
18419
            
 
18420
            # default
 
18421
            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
 
18422
            {
 
18423
                next if(defined $Found{$Symbol});
 
18424
                next if(index($Symbol,"\@\@")==-1);
 
18425
                
 
18426
                if($Symbol=~/\A([^\@]*)\@\@/
 
18427
                and not $SymVer{$LibVersion}{$1})
 
18428
                {
 
18429
                    $SymVer{$LibVersion}{$1} = $Symbol;
 
18430
                    $Found{$Symbol} = 1;
 
18431
                }
 
18432
            }
 
18433
            
 
18434
            # non-default
 
18435
            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
 
18436
            {
 
18437
                next if(defined $Found{$Symbol});
 
18438
                next if(index($Symbol,"\@")==-1);
 
18439
                
 
18440
                if($Symbol=~/\A([^\@]*)\@([^\@]*)/
 
18441
                and not $SymVer{$LibVersion}{$1})
 
18442
                {
 
18443
                    $SymVer{$LibVersion}{$1} = $Symbol;
 
18444
                    $Found{$Symbol} = 1;
 
18445
                }
 
18446
            }
 
18447
        }
 
18448
    }
 
18449
    if($Deps)
 
18450
    {
 
18451
        foreach my $DyLib (sort keys(%NeededLib))
16434
18452
        {
16435
 
            next if(index($Symbol,"\@")==-1);
16436
 
            my $Interface_SymName = "";
16437
 
            foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
16438
 
            {
16439
 
                if($Symbol_SameValue ne $Symbol
16440
 
                and index($Symbol_SameValue,"\@")==-1)
16441
 
                {
16442
 
                    $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16443
 
                    $Interface_SymName = $Symbol_SameValue;
16444
 
                    last;
16445
 
                }
16446
 
            }
16447
 
            if(not $Interface_SymName)
16448
 
            {
16449
 
                if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16450
 
                and not $SymVer{$LibVersion}{$1}) {
16451
 
                    $SymVer{$LibVersion}{$1} = $Symbol;
16452
 
                }
16453
 
            }
16454
 
        }
16455
 
    }
16456
 
    foreach my $DyLib (sort keys(%NeededLib))
16457
 
    {
16458
 
        my $DepPath = find_lib_path($LibVersion, $DyLib);
16459
 
        if($DepPath and -f $DepPath) {
16460
 
            readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
 
18453
            $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1;
 
18454
            
 
18455
            if(my $DepPath = get_LibPath($LibVersion, $DyLib))
 
18456
            {
 
18457
                if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) {
 
18458
                    readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
 
18459
                }
 
18460
            }
16461
18461
        }
16462
18462
    }
16463
18463
    pop(@RecurLib);
16464
18464
    return $Library_Symbol{$LibVersion};
16465
18465
}
16466
18466
 
16467
 
sub get_path_prefixes($)
 
18467
sub get_prefixes($)
16468
18468
{
16469
 
    my $Path = $_[0];
16470
 
    my ($Dir, $Name) = separate_path($Path);
16471
18469
    my %Prefixes = ();
16472
 
    foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16473
 
    {
16474
 
        $Prefixes{$Name} = 1;
16475
 
        $Name = joinPath($Prefix, $Name);
16476
 
        last if(keys(%Prefixes)>5 or $Prefix eq "include");
16477
 
    }
 
18470
    get_prefixes_I([$_[0]], \%Prefixes);
16478
18471
    return keys(%Prefixes);
16479
18472
}
16480
18473
 
 
18474
sub get_prefixes_I($$)
 
18475
{
 
18476
    foreach my $P (@{$_[0]})
 
18477
    {
 
18478
        my @Parts = reverse(split(/[\/\\]+/, $P));
 
18479
        my $Name = $Parts[0];
 
18480
        foreach (1 .. $#Parts)
 
18481
        {
 
18482
            $_[1]->{$Name}{$P} = 1;
 
18483
            last if($_>4 or $Parts[$_] eq "include");
 
18484
            $Name = $Parts[$_].$SLASH.$Name;
 
18485
        }
 
18486
    }
 
18487
}
 
18488
 
16481
18489
sub detectSystemHeaders()
16482
18490
{
16483
18491
    my @SysHeaders = ();
16484
 
    foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
 
18492
    foreach my $DevelPath (@{$SystemPaths{"include"}})
16485
18493
    {
16486
18494
        next if(not -d $DevelPath);
16487
18495
        # search for all header files in the /usr/include
16488
18496
        # with or without extension (ncurses.h, QtCore, ...)
16489
 
        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16490
 
        foreach my $Link (cmd_find($DevelPath,"l","",""))
 
18497
        push(@SysHeaders, cmd_find($DevelPath,"f"));
 
18498
        foreach my $Link (cmd_find($DevelPath,"l"))
16491
18499
        { # add symbolic links
16492
18500
            if(-f $Link) {
16493
18501
                push(@SysHeaders, $Link);
16494
18502
            }
16495
18503
        }
16496
18504
    }
16497
 
    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16498
 
    {
 
18505
    foreach my $DevelPath (@{$SystemPaths{"lib"}})
 
18506
    { # search for config headers in the /usr/lib
16499
18507
        next if(not -d $DevelPath);
16500
 
        # search for config headers in the /usr/lib
16501
 
        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16502
 
        foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16503
 
        { # search for all include directories
16504
 
          # this is for headers that are installed to /usr/lib
16505
 
          # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16506
 
            if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
 
18508
        foreach (cmd_find($DevelPath,"f",'\.h(pp|xx)?\Z|\/include\/',"",1))
 
18509
        {
 
18510
            if(/\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
 
18511
            { # skip useless headers
16507
18512
                next;
16508
18513
            }
16509
 
            @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16510
 
        }
16511
 
    }
16512
 
    foreach my $Path (@SysHeaders)
16513
 
    {
16514
 
        foreach my $Part (get_path_prefixes($Path)) {
16515
 
            $SystemHeaders{$Part}{$Path}=1;
16516
 
        }
16517
 
    }
 
18514
            push(@SysHeaders, $_);
 
18515
        }
 
18516
    }
 
18517
    get_prefixes_I(\@SysHeaders, \%SystemHeaders);
16518
18518
}
16519
18519
 
16520
18520
sub detectSystemObjects()
16521
18521
{
16522
 
    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
 
18522
    foreach my $DevelPath (@{$SystemPaths{"lib"}})
16523
18523
    {
16524
18524
        next if(not -d $DevelPath);
16525
18525
        foreach my $Path (find_libs($DevelPath,"",""))
16532
18532
sub getSOPaths($)
16533
18533
{
16534
18534
    my $LibVersion = $_[0];
16535
 
    my @SoPaths = ();
 
18535
    my @Paths = ();
16536
18536
    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16537
18537
    {
16538
18538
        if(not -e $Dest) {
16539
18539
            exitStatus("Access_Error", "can't access \'$Dest\'");
16540
18540
        }
 
18541
        $Dest = get_abs_path($Dest);
16541
18542
        my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16542
18543
        foreach (@SoPaths_Dest) {
16543
 
            push(@SoPaths, $_);
 
18544
            push(@Paths, $_);
16544
18545
        }
16545
18546
    }
16546
 
    return sort @SoPaths;
 
18547
    return sort @Paths;
16547
18548
}
16548
18549
 
16549
 
sub skip_lib($$)
 
18550
sub skipLib($$)
16550
18551
{
16551
18552
    my ($Path, $LibVersion) = @_;
16552
18553
    return 1 if(not $Path or not $LibVersion);
16576
18577
    return 0;
16577
18578
}
16578
18579
 
 
18580
sub specificHeader($$)
 
18581
{
 
18582
    my ($Header, $Spec) = @_;
 
18583
    my $Name = get_filename($Header);
 
18584
    
 
18585
    if($Spec eq "windows")
 
18586
    {# MS Windows
 
18587
        return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i);
 
18588
        return 1 if($Name=~/([._-]w|win)(32|64)/i);
 
18589
        return 1 if($Name=~/\A(Win|Windows)[A-Z]/);
 
18590
        return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i);
 
18591
        my @Dirs = (
 
18592
            "win32",
 
18593
            "win64",
 
18594
            "win",
 
18595
            "windows",
 
18596
            "msvcrt"
 
18597
        ); # /gsf-win32/
 
18598
        if(my $DIRs = join("|", @Dirs)) {
 
18599
            return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
 
18600
        }
 
18601
    }
 
18602
    elsif($Spec eq "macos")
 
18603
    { # Mac OS
 
18604
        return 1 if($Name=~/(\A|[_-])mac[._-]/i);
 
18605
    }
 
18606
    
 
18607
    return 0;
 
18608
}
 
18609
 
 
18610
sub skipAlienHeader($)
 
18611
{
 
18612
    my $Path = $_[0];
 
18613
    my $Name = get_filename($Path);
 
18614
    my $Dir = get_dirname($Path);
 
18615
    
 
18616
    if($Tolerance=~/2/)
 
18617
    { # 2 - skip internal headers
 
18618
        my @Terms = (
 
18619
            "p",
 
18620
            "priv",
 
18621
            "int",
 
18622
            "impl",
 
18623
            "implementation",
 
18624
            "internal",
 
18625
            "private",
 
18626
            "old",
 
18627
            "compat",
 
18628
            "debug",
 
18629
            "test",
 
18630
            "gen"
 
18631
        );
 
18632
        
 
18633
        my @Dirs = (
 
18634
            "private",
 
18635
            "priv",
 
18636
            "port",
 
18637
            "impl",
 
18638
            "internal",
 
18639
            "detail",
 
18640
            "details",
 
18641
            "old",
 
18642
            "compat",
 
18643
            "debug",
 
18644
            "config",
 
18645
            "compiler",
 
18646
            "platform",
 
18647
            "test"
 
18648
        );
 
18649
        
 
18650
        if(my $TERMs = join("|", @Terms)) {
 
18651
            return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i);
 
18652
        }
 
18653
        if(my $DIRs = join("|", @Dirs)) {
 
18654
            return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
 
18655
        }
 
18656
        
 
18657
        return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/);
 
18658
    }
 
18659
    
 
18660
    if($Tolerance=~/1/)
 
18661
    { # 1 - skip non-Linux headers
 
18662
        if($OSgroup ne "windows")
 
18663
        {
 
18664
            if(specificHeader($Path, "windows")) {
 
18665
                return 1;
 
18666
            }
 
18667
        }
 
18668
        if($OSgroup ne "macos")
 
18669
        {
 
18670
            if(specificHeader($Path, "macos")) {
 
18671
                return 1;
 
18672
            }
 
18673
        }
 
18674
    }
 
18675
    
 
18676
    # valid
 
18677
    return 0;
 
18678
}
 
18679
 
16579
18680
sub skipHeader($$)
16580
18681
{
16581
18682
    my ($Path, $LibVersion) = @_;
16582
18683
    return 1 if(not $Path or not $LibVersion);
16583
 
    if(not keys(%{$SkipHeaders{$LibVersion}})) {
16584
 
        return 0;
16585
 
    }
16586
18684
    if(defined $Cache{"skipHeader"}{$Path}) {
16587
18685
        return $Cache{"skipHeader"}{$Path};
16588
18686
    }
 
18687
    if(defined $Tolerance and $Tolerance=~/1|2/)
 
18688
    { # --tolerant
 
18689
        if(skipAlienHeader($Path)) {
 
18690
            return ($Cache{"skipHeader"}{$Path} = 1);
 
18691
        }
 
18692
    }
 
18693
    if(not keys(%{$SkipHeaders{$LibVersion}})) {
 
18694
        return 0;
 
18695
    }
16589
18696
    return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16590
18697
}
16591
18698
 
16600
18707
    }
16601
18708
    foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
16602
18709
    {
16603
 
        if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16604
 
            return $SkipHeaders{$LibVersion}{"Path"}{$D};
 
18710
        if(index($Path, $D)!=-1)
 
18711
        {
 
18712
            if($Path=~/\Q$D\E([\/\\]|\Z)/) {
 
18713
                return $SkipHeaders{$LibVersion}{"Path"}{$D};
 
18714
            }
16605
18715
        }
16606
18716
    }
16607
18717
    foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
16616
18726
            }
16617
18727
        }
16618
18728
    }
 
18729
    
16619
18730
    return 0;
16620
18731
}
16621
18732
 
16622
 
sub register_objects($$)
 
18733
sub registerObject_Dir($$)
16623
18734
{
16624
18735
    my ($Dir, $LibVersion) = @_;
16625
 
    if($SystemPaths{"lib"}{$Dir})
 
18736
    if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}})
16626
18737
    { # system directory
16627
18738
        return;
16628
18739
    }
16629
 
    if($RegisteredObjDirs{$LibVersion}{$Dir})
 
18740
    if($RegisteredObject_Dirs{$LibVersion}{$Dir})
16630
18741
    { # already registered
16631
18742
        return;
16632
18743
    }
16633
18744
    foreach my $Path (find_libs($Dir,"",1))
16634
18745
    {
16635
18746
        next if(ignore_path($Path));
16636
 
        next if(skip_lib($Path, $LibVersion));
16637
 
        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16638
 
    }
16639
 
    $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
 
18747
        next if(skipLib($Path, $LibVersion));
 
18748
        registerObject($Path, $LibVersion);
 
18749
    }
 
18750
    $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
 
18751
}
 
18752
 
 
18753
sub registerObject($$)
 
18754
{
 
18755
    my ($Path, $LibVersion) = @_;
 
18756
    my $Name = get_filename($Path);
 
18757
    $RegisteredObjects{$LibVersion}{$Name} = $Path;
 
18758
    if($OSgroup=~/linux|bsd/i)
 
18759
    {
 
18760
        if(my $SONAME = getSONAME($Path)) {
 
18761
            $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
 
18762
        }
 
18763
    }
 
18764
    if(my $Short = parse_libname($Name, "name+ext", $OStarget)) {
 
18765
        $RegisteredObjects_Short{$LibVersion}{$Short} = $Path;
 
18766
    }
 
18767
}
 
18768
 
 
18769
sub getSONAME($)
 
18770
{
 
18771
    my $Path = $_[0];
 
18772
    return if(not $Path);
 
18773
    if(defined $Cache{"getSONAME"}{$Path}) {
 
18774
        return $Cache{"getSONAME"}{$Path};
 
18775
    }
 
18776
    my $ObjdumpCmd = get_CmdPath("objdump");
 
18777
    if(not $ObjdumpCmd) {
 
18778
        exitStatus("Not_Found", "can't find \"objdump\"");
 
18779
    }
 
18780
    my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
 
18781
    if($OSgroup eq "windows") {
 
18782
        $SonameCmd .= " | find \"SONAME\"";
 
18783
    }
 
18784
    else {
 
18785
        $SonameCmd .= " | grep SONAME";
 
18786
    }
 
18787
    if(my $SonameInfo = `$SonameCmd`) {
 
18788
        if($SonameInfo=~/SONAME\s+([^\s]+)/) {
 
18789
            return ($Cache{"getSONAME"}{$Path} = $1);
 
18790
        }
 
18791
    }
 
18792
    return ($Cache{"getSONAME"}{$Path}="");
16640
18793
}
16641
18794
 
16642
18795
sub getSOPaths_Dest($$)
16643
18796
{
16644
18797
    my ($Dest, $LibVersion) = @_;
16645
 
    if(skip_lib($Dest, $LibVersion)) {
 
18798
    if(skipLib($Dest, $LibVersion)) {
16646
18799
        return ();
16647
18800
    }
16648
18801
    if(-f $Dest)
16650
18803
        if(not parse_libname($Dest, "name", $OStarget)) {
16651
18804
            exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16652
18805
        }
16653
 
        $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16654
 
        register_objects(get_dirname($Dest), $LibVersion);
 
18806
        registerObject($Dest, $LibVersion);
 
18807
        registerObject_Dir(get_dirname($Dest), $LibVersion);
16655
18808
        return ($Dest);
16656
18809
    }
16657
18810
    elsif(-d $Dest)
16658
18811
    {
16659
18812
        $Dest=~s/[\/\\]+\Z//g;
16660
18813
        my %Libs = ();
16661
 
        if($SystemPaths{"lib"}{$Dest})
 
18814
        if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}})
16662
18815
        { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16663
18816
          # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16664
 
            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
 
18817
            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2))
16665
18818
            { # all files and symlinks that match the name of a library
16666
18819
                if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16667
18820
                {
16668
 
                    $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16669
 
                    $Libs{resolve_symlink($Path)}=1;
 
18821
                    registerObject($Path, $LibVersion);
 
18822
                    $Libs{realpath($Path)}=1;
16670
18823
                }
16671
18824
            }
16672
18825
        }
16675
18828
            foreach my $Path (find_libs($Dest,"",""))
16676
18829
            {
16677
18830
                next if(ignore_path($Path));
16678
 
                next if(skip_lib($Path, $LibVersion));
16679
 
                $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16680
 
                $Libs{resolve_symlink($Path)}=1;
 
18831
                next if(skipLib($Path, $LibVersion));
 
18832
                registerObject($Path, $LibVersion);
 
18833
                $Libs{realpath($Path)}=1;
16681
18834
            }
16682
18835
            if($OSgroup eq "macos")
16683
18836
            { # shared libraries on MacOS X may have no extension
16684
 
                foreach my $Path (cmd_find($Dest,"f","",""))
 
18837
                foreach my $Path (cmd_find($Dest,"f"))
16685
18838
                {
16686
18839
                    next if(ignore_path($Path));
16687
 
                    next if(skip_lib($Path, $LibVersion));
 
18840
                    next if(skipLib($Path, $LibVersion));
16688
18841
                    if(get_filename($Path)!~/\./
16689
18842
                    and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16690
18843
                    {
16691
 
                        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16692
 
                        $Libs{resolve_symlink($Path)}=1;
 
18844
                        registerObject($Path, $LibVersion);
 
18845
                        $Libs{realpath($Path)}=1;
16693
18846
                    }
16694
18847
                }
16695
18848
            }
16707
18860
    return (grep {$_ eq $Value} @{$Stack});
16708
18861
}
16709
18862
 
16710
 
sub generateTemplate()
16711
 
{
16712
 
    writeFile("VERSION.xml", $DescriptorTemplate."\n");
16713
 
    printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16714
 
}
16715
 
 
16716
18863
sub detectWordSize()
16717
18864
{
16718
18865
    return "" if(not $GCC_PATH);
16720
18867
        return $Cache{"detectWordSize"};
16721
18868
    }
16722
18869
    writeFile("$TMP_DIR/empty.h", "");
16723
 
    my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
 
18870
    my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
16724
18871
    unlink("$TMP_DIR/empty.h");
16725
18872
    my $WSize = 0;
16726
18873
    if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
16737
18884
            $WSize = "4";
16738
18885
        }
16739
18886
    }
16740
 
    if(not int($WSize)) {
 
18887
    if(not $WSize) {
16741
18888
        exitStatus("Error", "can't check WORD size");
16742
18889
    }
16743
18890
    return ($Cache{"detectWordSize"} = $WSize);
16744
18891
}
16745
18892
 
 
18893
sub getWordSize($) {
 
18894
    return $WORD_SIZE{$_[0]};
 
18895
}
 
18896
 
16746
18897
sub majorVersion($)
16747
18898
{
16748
18899
    my $V = $_[0];
16757
18908
    return 0 if($V1 eq $V2);
16758
18909
    my @V1Parts = split(/\./, $V1);
16759
18910
    my @V2Parts = split(/\./, $V2);
16760
 
    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
 
18911
    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++)
 
18912
    {
16761
18913
        return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16762
18914
        return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16763
18915
    }
16771
18923
    my ($LibVersion, $Path) = @_;
16772
18924
    return if(not $LibVersion or not -e $Path);
16773
18925
    my $FilePath = "";
16774
 
    if($Path=~/\.abi\Z/)
 
18926
    if(isDump_U($Path))
16775
18927
    { # input *.abi
16776
18928
        $FilePath = $Path;
16777
18929
    }
16778
18930
    else
16779
18931
    { # input *.abi.tar.gz
16780
18932
        $FilePath = unpackDump($Path);
16781
 
    }
16782
 
    if($FilePath!~/\.abi\Z/) {
16783
 
        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16784
 
    }
16785
 
    
16786
 
    open(DUMP, $FilePath);
16787
 
    local $/ = undef;
16788
 
    my $Content = <DUMP>;
16789
 
    close(DUMP);
16790
 
    
16791
 
    if($Path!~/\.abi\Z/)
16792
 
    { # remove temp file
16793
 
        unlink($FilePath);
16794
 
    }
16795
 
    if($Content!~/};\s*\Z/) {
16796
 
        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16797
 
    }
16798
 
    my $LibraryABI = eval($Content);
16799
 
    if(not $LibraryABI) {
16800
 
        exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
 
18933
        if(not isDump_U($FilePath)) {
 
18934
            exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
 
18935
        }
 
18936
    }
 
18937
    
 
18938
    my $ABI = {};
 
18939
    
 
18940
    my $Line = readLineNum($FilePath, 0);
 
18941
    if($Line=~/xml/)
 
18942
    { # XML format
 
18943
        loadModule("XmlDump");
 
18944
        $ABI = readXmlDump($FilePath);
 
18945
    }
 
18946
    else
 
18947
    { # Perl Data::Dumper format (default)
 
18948
        open(DUMP, $FilePath);
 
18949
        local $/ = undef;
 
18950
        my $Content = <DUMP>;
 
18951
        close(DUMP);
 
18952
        
 
18953
        if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
 
18954
        { # remove temp file
 
18955
            unlink($FilePath);
 
18956
        }
 
18957
        if($Content!~/};\s*\Z/) {
 
18958
            exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
 
18959
        }
 
18960
        $ABI = eval($Content);
 
18961
        if(not $ABI) {
 
18962
            exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
 
18963
        }
16801
18964
    }
16802
18965
    # new dumps (>=1.22) have a personal versioning
16803
 
    my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16804
 
    my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16805
 
    if(not $DumpVersion)
 
18966
    my $DVersion = $ABI->{"ABI_DUMP_VERSION"};
 
18967
    my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
 
18968
    if(not $DVersion)
16806
18969
    { # old dumps (<=1.21.6) have been marked by the tool version
16807
 
        $DumpVersion = $ToolVersion;
16808
 
    }
16809
 
    $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16810
 
    if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16811
 
    { # should be compatible with dumps of the same major version
16812
 
        if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16813
 
        { # Don't know how to parse future dump formats
16814
 
            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16815
 
        }
16816
 
        elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16817
 
        { # Don't know how to parse future dump formats
16818
 
            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
16819
 
        }
 
18970
        $DVersion = $ToolVersion;
 
18971
    }
 
18972
    $UsedDump{$LibVersion}{"V"} = $DVersion;
 
18973
    
 
18974
    if($ABI->{"ABI_DUMP_VERSION"})
 
18975
    {
 
18976
        if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0)
 
18977
        { # Don't know how to parse future dump formats
 
18978
            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
 
18979
        }
 
18980
    }
 
18981
    else
 
18982
    { # support for old ABI dumps
 
18983
        if(cmpVersions($DVersion, $TOOL_VERSION)>0)
 
18984
        { # Don't know how to parse future dump formats
 
18985
            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
 
18986
        }
 
18987
    }
 
18988
    if(majorVersion($DVersion)<2)
 
18989
    { # support for old ABI dumps
16820
18990
        if($UseOldDumps)
16821
18991
        {
16822
 
            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
16823
 
                exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
 
18992
            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) {
 
18993
                exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
16824
18994
            }
16825
18995
        }
16826
18996
        else
16827
18997
        {
16828
 
            my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
16829
 
            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
16830
 
                $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
 
18998
            my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)";
 
18999
            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
 
19000
                $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0)";
16831
19001
            }
16832
19002
            exitStatus("Dump_Version", $Msg);
16833
19003
        }
16834
19004
    }
16835
 
    if($LibraryABI->{"SrcBin"})
 
19005
    
 
19006
    if(defined $ABI->{"ABI_DUMPER_VERSION"})
 
19007
    { # DWARF ABI Dump
 
19008
        $UseConv_Real{$LibVersion}{"P"} = 1;
 
19009
        $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet
 
19010
        
 
19011
        $UsedDump{$LibVersion}{"DWARF"} = 1;
 
19012
        
 
19013
        $TargetComponent = "module";
 
19014
    }
 
19015
    
 
19016
    if(not checkDump($LibVersion, "2.11"))
 
19017
    { # old ABI dumps
 
19018
        $UsedDump{$LibVersion}{"BinOnly"} = 1;
 
19019
    }
 
19020
    elsif($ABI->{"BinOnly"})
 
19021
    { # ABI dump created with --binary option
 
19022
        $UsedDump{$LibVersion}{"BinOnly"} = 1;
 
19023
    }
 
19024
    else
16836
19025
    { # default
16837
19026
        $UsedDump{$LibVersion}{"SrcBin"} = 1;
16838
19027
    }
16839
 
    elsif($LibraryABI->{"BinOnly"})
16840
 
    { # ABI dump created with --binary option
16841
 
        $UsedDump{$LibVersion}{"BinOnly"} = 1;
16842
 
    }
16843
 
    if(defined $LibraryABI->{"Mode"}
16844
 
    and $LibraryABI->{"Mode"} eq "Extended")
 
19028
    
 
19029
    if(defined $ABI->{"Mode"}
 
19030
    and $ABI->{"Mode"} eq "Extended")
16845
19031
    { # --ext option
16846
19032
        $ExtendedCheck = 1;
16847
19033
    }
16848
 
    if(my $Lang = $LibraryABI->{"Language"})
 
19034
    if($ABI->{"Extra"}) {
 
19035
        $ExtraDump = 1;
 
19036
    }
 
19037
    
 
19038
    if(my $Lang = $ABI->{"Language"})
16849
19039
    {
16850
19040
        $UsedDump{$LibVersion}{"L"} = $Lang;
16851
19041
        setLanguage($LibVersion, $Lang);
16852
19042
    }
16853
19043
    if(checkDump($LibVersion, "2.15")) {
16854
 
        $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
 
19044
        $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
16855
19045
    }
16856
19046
    else
16857
19047
    { # support for old ABI dumps
16858
 
        my $TInfo = $LibraryABI->{"TypeInfo"};
 
19048
        my $TInfo = $ABI->{"TypeInfo"};
16859
19049
        if(not $TInfo)
16860
19050
        { # support for older ABI dumps
16861
 
            $TInfo = $LibraryABI->{"TypeDescr"};
 
19051
            $TInfo = $ABI->{"TypeDescr"};
16862
19052
        }
16863
19053
        my %Tid_TDid = ();
16864
19054
        foreach my $TDid (keys(%{$TInfo}))
16906
19096
                my $Bid = $Info{"BaseType"}{"Tid"};
16907
19097
                my $BDid = $Info{"BaseType"}{"TDid"};
16908
19098
                $BDid="" if(not defined $BDid);
 
19099
                delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
16909
19100
                if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
16910
 
                    $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
 
19101
                    $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID;
16911
19102
                }
16912
 
                delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
16913
19103
            }
16914
19104
            delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
16915
19105
        }
16916
19106
    }
16917
 
    read_Machine_DumpInfo($LibraryABI, $LibVersion);
16918
 
    $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
 
19107
    read_Machine_DumpInfo($ABI, $LibVersion);
 
19108
    $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
16919
19109
    if(not $SymbolInfo{$LibVersion})
16920
19110
    { # support for old dumps
16921
 
        $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
 
19111
        $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
16922
19112
    }
16923
19113
    if(not keys(%{$SymbolInfo{$LibVersion}}))
16924
19114
    { # validation of old-version dumps
16926
19116
            exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
16927
19117
        }
16928
19118
    }
16929
 
    $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
16930
 
    if(not $Library_Symbol{$LibVersion})
16931
 
    { # support for old dumps
16932
 
        $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
16933
 
    }
16934
19119
    if(checkDump($LibVersion, "2.15")) {
16935
 
        $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
 
19120
        $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
16936
19121
    }
16937
19122
    else
16938
19123
    { # support for old ABI dumps
16939
 
        my $DepSymbols = $LibraryABI->{"DepSymbols"};
 
19124
        my $DepSymbols = $ABI->{"DepSymbols"};
16940
19125
        if(not $DepSymbols) {
16941
 
            $DepSymbols = $LibraryABI->{"DepInterfaces"};
 
19126
            $DepSymbols = $ABI->{"DepInterfaces"};
16942
19127
        }
16943
19128
        if(not $DepSymbols)
16944
19129
        { # Cannot reconstruct DepSymbols. This may result in false
16950
19135
            $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
16951
19136
        }
16952
19137
    }
16953
 
    $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
16954
 
    $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
16955
 
    $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
 
19138
    $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
 
19139
    $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
 
19140
    $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
16956
19141
    if(not $SkipTypes{$LibVersion})
16957
19142
    { # support for old dumps
16958
 
        $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
16959
 
    }
16960
 
    $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
16961
 
    if(not $SkipSymbols{$LibVersion})
16962
 
    { # support for old dumps
16963
 
        $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
16964
 
    }
16965
 
    if(not $SkipSymbols{$LibVersion})
16966
 
    { # support for old dumps
16967
 
        $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
16968
 
    }
16969
 
    $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
16970
 
    $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
16971
 
    foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
 
19143
        $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
 
19144
    }
 
19145
    $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
 
19146
    if(not $SkipSymbols{$LibVersion})
 
19147
    { # support for old dumps
 
19148
        $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
 
19149
    }
 
19150
    if(not $SkipSymbols{$LibVersion})
 
19151
    { # support for old dumps
 
19152
        $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
 
19153
    }
 
19154
    $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
 
19155
    $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
 
19156
    foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
16972
19157
    {
16973
 
        $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
 
19158
        $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
16974
19159
        my ($CPath, $Type) = classifyPath($Path);
16975
 
        $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
 
19160
        $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
16976
19161
    }
16977
 
    read_Headers_DumpInfo($LibraryABI, $LibVersion);
16978
 
    read_Libs_DumpInfo($LibraryABI, $LibVersion);
16979
 
    if(not checkDump($LibVersion, "2.10.1"))
 
19162
    read_Source_DumpInfo($ABI, $LibVersion);
 
19163
    read_Libs_DumpInfo($ABI, $LibVersion);
 
19164
    if(not checkDump($LibVersion, "2.10.1")
 
19165
    or not $TargetHeaders{$LibVersion})
16980
19166
    { # support for old ABI dumps: added target headers
16981
19167
        foreach (keys(%{$Registered_Headers{$LibVersion}})) {
16982
19168
            $TargetHeaders{$LibVersion}{get_filename($_)}=1;
16983
19169
        }
16984
 
    }
16985
 
    $Constants{$LibVersion} = $LibraryABI->{"Constants"};
16986
 
    $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
 
19170
        foreach (keys(%{$Registered_Sources{$LibVersion}})) {
 
19171
            $TargetHeaders{$LibVersion}{get_filename($_)}=1;
 
19172
        }
 
19173
    }
 
19174
    $Constants{$LibVersion} = $ABI->{"Constants"};
 
19175
    if(defined $ABI->{"GccConstants"})
 
19176
    { # 3.0
 
19177
        foreach my $Name (keys(%{$ABI->{"GccConstants"}})) {
 
19178
            $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name};
 
19179
        }
 
19180
    }
 
19181
    
 
19182
    $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
16987
19183
    if(not $NestedNameSpaces{$LibVersion})
16988
19184
    { # support for old dumps
16989
19185
      # Cannot reconstruct NameSpaces. This may affect design
16994
19190
    # needed to adopt HTML report
16995
19191
    if(not $DumpSystem)
16996
19192
    { # to use in createSymbolsList(...)
16997
 
        $OStarget = $LibraryABI->{"Target"};
 
19193
        $OStarget = $ABI->{"Target"};
16998
19194
    }
16999
19195
    # recreate environment
17000
19196
    foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17004
19200
            $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17005
19201
            if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
17006
19202
            { # data marked as -size in the dump
17007
 
                $GlobalDataObject{$LibVersion}{$Symbol}=1;
 
19203
                $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol};
17008
19204
            }
17009
 
            if($COMMON_LANGUAGE{$LibVersion} ne "C++"
17010
 
            and $Symbol=~/\A(_Z|\?)/) {
17011
 
                setLanguage($LibVersion, "C++");
 
19205
            if($COMMON_LANGUAGE{$LibVersion} ne "C++")
 
19206
            {
 
19207
                if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
 
19208
                    setLanguage($LibVersion, "C++");
 
19209
                }
17012
19210
            }
17013
19211
        }
17014
19212
    }
17022
19220
    my @VFunc = ();
17023
19221
    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17024
19222
    {
17025
 
        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17026
 
        if($MnglName)
 
19223
        if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17027
19224
        {
17028
19225
            if(not $Symbol_Library{$LibVersion}{$MnglName}
17029
19226
            and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17035
19232
    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
17036
19233
    translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17037
19234
    
 
19235
    if(not checkDump($LibVersion, "3.0"))
 
19236
    { # support for old ABI dumps
 
19237
        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
 
19238
        {
 
19239
            if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"})
 
19240
            {
 
19241
                if(ref($BaseType) eq "HASH") {
 
19242
                    $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"};
 
19243
                }
 
19244
            }
 
19245
        }
 
19246
    }
 
19247
    
 
19248
    if(not checkDump($LibVersion, "2.20"))
 
19249
    { # support for old ABI dumps
 
19250
        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
 
19251
        {
 
19252
            my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"};
 
19253
            
 
19254
            if($TType=~/Struct|Union|Enum|Typedef/)
 
19255
            { # repair complex types first
 
19256
                next;
 
19257
            }
 
19258
            
 
19259
            if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"})
 
19260
            {
 
19261
                my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"});
 
19262
                if($BType=~/Struct|Union|Enum/i)
 
19263
                {
 
19264
                    my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"};
 
19265
                    $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g;
 
19266
                }
 
19267
            }
 
19268
        }
 
19269
        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
 
19270
        {
 
19271
            my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"};
 
19272
            my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
 
19273
            if($TType=~/Struct|Union|Enum/) {
 
19274
                $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName;
 
19275
            }
 
19276
        }
 
19277
    }
 
19278
    
17038
19279
    foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
17039
 
    {
 
19280
    { # order is important
17040
19281
        if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17041
19282
        { # support for old ABI dumps < 2.0 (ACC 1.22)
17042
19283
            foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17051
19292
            }
17052
19293
            delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17053
19294
        }
 
19295
        if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
 
19296
        { # support for old ABI dumps
 
19297
            $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
 
19298
        }
 
19299
        elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"})
 
19300
        { # DWARF ABI Dumps
 
19301
            $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source;
 
19302
        }
 
19303
        if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
 
19304
            $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
 
19305
        }
17054
19306
        my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17055
19307
        if(defined $TInfo{"Base"})
17056
19308
        {
17058
19310
                $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
17059
19311
            }
17060
19312
        }
17061
 
        if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17062
 
        {
17063
 
            if(my $BTid = $TInfo{"BaseType"}{"Tid"})
 
19313
        if($TInfo{"Type"} eq "MethodPtr")
 
19314
        {
 
19315
            if(defined $TInfo{"Param"})
 
19316
            { # support for old ABI dumps <= 1.17
 
19317
                if(not defined $TInfo{"Param"}{"0"})
 
19318
                {
 
19319
                    my $Max = keys(%{$TInfo{"Param"}});
 
19320
                    foreach my $Pos (1 .. $Max) {
 
19321
                        $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
 
19322
                    }
 
19323
                    delete($TInfo{"Param"}{$Max});
 
19324
                    %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
 
19325
                }
 
19326
            }
 
19327
        }
 
19328
        if($TInfo{"BaseType"} eq $TypeId)
 
19329
        { # fix ABI dump
 
19330
            delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"});
 
19331
        }
 
19332
        if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"})
 
19333
        {
 
19334
            if(my $BTid = $TInfo{"BaseType"})
17064
19335
            {
17065
19336
                my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17066
19337
                if(not $BName)
17069
19340
                }
17070
19341
                if($TInfo{"Name"} eq $BName)
17071
19342
                { # typedef to "class Class"
17072
 
                    # should not be registered in TName_Tid
 
19343
                  # should not be registered in TName_Tid
17073
19344
                    next;
17074
19345
                }
17075
19346
                if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17079
19350
        }
17080
19351
        if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17081
19352
        { # classes: class (id1), typedef (artificial, id2 > id1)
17082
 
            $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
 
19353
            $TName_Tid{$LibVersion}{formatName($TInfo{"Name"}, "T")} = $TypeId;
17083
19354
        }
17084
19355
    }
17085
19356
    
17104
19375
        }
17105
19376
    }
17106
19377
    
 
19378
    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
 
19379
    {
 
19380
        if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
 
19381
        and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"}
 
19382
        and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
 
19383
        { # support for old ABI dumps (< 3.1)
 
19384
            if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
 
19385
            or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this")
 
19386
            { # add "this" first parameter
 
19387
                my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion);
 
19388
                my %PInfo = ("name"=>"this", "type"=>"$ThisTid");
 
19389
                
 
19390
                if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
 
19391
                {
 
19392
                    my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
 
19393
                    foreach my $Pos (reverse(0 .. $#Pos)) {
 
19394
                        %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}};
 
19395
                    }
 
19396
                }
 
19397
                $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo;
 
19398
            }
 
19399
        }
 
19400
        
 
19401
        if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
 
19402
        { # ABI dumps have no mangled names for C-functions
 
19403
            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
 
19404
        }
 
19405
        if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
 
19406
        { # support for old ABI dumps
 
19407
            $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
 
19408
        }
 
19409
        elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"})
 
19410
        { # DWARF ABI Dumps
 
19411
            $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source;
 
19412
        }
 
19413
    }
 
19414
    
17107
19415
    $Descriptor{$LibVersion}{"Dump"} = 1;
17108
19416
}
17109
19417
 
17110
19418
sub read_Machine_DumpInfo($$)
17111
19419
{
17112
 
    my ($LibraryABI, $LibVersion) = @_;
17113
 
    if($LibraryABI->{"Arch"}) {
17114
 
        $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
 
19420
    my ($ABI, $LibVersion) = @_;
 
19421
    if($ABI->{"Arch"}) {
 
19422
        $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
17115
19423
    }
17116
 
    if($LibraryABI->{"WordSize"}) {
17117
 
        $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
 
19424
    if($ABI->{"WordSize"}) {
 
19425
        $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
17118
19426
    }
17119
19427
    else
17120
19428
    { # support for old dumps
17121
 
        $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
 
19429
        $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
17122
19430
    }
17123
19431
    if(not $WORD_SIZE{$LibVersion})
17124
19432
    { # support for old dumps (<1.23)
17146
19454
            }
17147
19455
        }
17148
19456
    }
17149
 
    if($LibraryABI->{"GccVersion"}) {
17150
 
        $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
 
19457
    if($ABI->{"GccVersion"}) {
 
19458
        $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
17151
19459
    }
17152
19460
}
17153
19461
 
17154
19462
sub read_Libs_DumpInfo($$)
17155
19463
{
17156
 
    my ($LibraryABI, $LibVersion) = @_;
 
19464
    my ($ABI, $LibVersion) = @_;
 
19465
    $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
 
19466
    if(not $Library_Symbol{$LibVersion})
 
19467
    { # support for old dumps
 
19468
        $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
 
19469
    }
17157
19470
    if(keys(%{$Library_Symbol{$LibVersion}})
17158
19471
    and not $DumpAPI) {
17159
19472
        $Descriptor{$LibVersion}{"Libs"} = "OK";
17160
19473
    }
17161
19474
}
17162
19475
 
17163
 
sub read_Headers_DumpInfo($$)
 
19476
sub read_Source_DumpInfo($$)
17164
19477
{
17165
 
    my ($LibraryABI, $LibVersion) = @_;
17166
 
    if(keys(%{$LibraryABI->{"Headers"}})
 
19478
    my ($ABI, $LibVersion) = @_;
 
19479
    
 
19480
    if(keys(%{$ABI->{"Headers"}})
17167
19481
    and not $DumpAPI) {
17168
19482
        $Descriptor{$LibVersion}{"Headers"} = "OK";
17169
19483
    }
17170
 
    foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
 
19484
    foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
17171
19485
    { # headers info is stored in the old dumps in the different way
17172
19486
        if($UseOldDumps
17173
 
        and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
 
19487
        and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
17174
19488
        { # support for old dumps: headers info corrected in 1.22
17175
19489
            $Identity = $Name;
17176
19490
        }
17177
19491
        $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
 
19492
        $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
 
19493
    }
 
19494
    
 
19495
    if(keys(%{$ABI->{"Sources"}})
 
19496
    and not $DumpAPI) {
 
19497
        $Descriptor{$LibVersion}{"Sources"} = "OK";
 
19498
    }
 
19499
    foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}}))
 
19500
    { # headers info is stored in the old dumps in the different way
 
19501
        $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name;
 
19502
        $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name};
17178
19503
    }
17179
19504
}
17180
19505
 
17182
19507
{
17183
19508
    my ($Path, $Type, $MaxDepth) = @_;
17184
19509
    # FIXME: correct the search pattern
17185
 
    return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
 
19510
    return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1);
17186
19511
}
17187
19512
 
17188
19513
sub createDescriptor($$)
17209
19534
    }
17210
19535
    else
17211
19536
    { # files
17212
 
        if($Path=~/\.xml\Z/i)
 
19537
        if($Path=~/\.(xml|desc)\Z/i)
17213
19538
        { # standard XML-descriptor
17214
19539
            return readFile($Path);
17215
19540
        }
17255
19580
    my %LPaths = ();
17256
19581
    if($OSgroup eq "bsd")
17257
19582
    {
17258
 
        if(my $LdConfig = get_CmdPath("ldconfig")) {
17259
 
            foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
17260
 
                if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17261
 
                    $LPaths{"lib".$1} = $2;
 
19583
        if(my $LdConfig = get_CmdPath("ldconfig"))
 
19584
        {
 
19585
            foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
 
19586
            {
 
19587
                if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/)
 
19588
                {
 
19589
                    my $Name = "lib".$1;
 
19590
                    if(not defined $LPaths{$Name}) {
 
19591
                        $LPaths{$Name} = $2;
 
19592
                    }
17262
19593
                }
17263
19594
            }
17264
19595
        }
17276
19607
                    $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17277
19608
                }
17278
19609
            }
17279
 
            foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
 
19610
            foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
 
19611
            {
17280
19612
                if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17281
19613
                {
17282
19614
                    my ($Name, $Path) = ($1, $2);
17283
19615
                    $Path=~s/[\/]{2,}/\//;
17284
 
                    $LPaths{$Name} = $Path;
 
19616
                    if(not defined $LPaths{$Name})
 
19617
                    { # get first element from the list of available paths
 
19618
                      
 
19619
                      # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
 
19620
                      # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6
 
19621
                      # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6
 
19622
                      
 
19623
                        $LPaths{$Name} = $Path;
 
19624
                    }
17285
19625
                }
17286
19626
            }
17287
19627
        }
17288
 
        elsif($OSgroup=~/linux/i) {
 
19628
        elsif($OSgroup eq "linux") {
17289
19629
            printMsg("WARNING", "can't find ldconfig");
17290
19630
        }
17291
19631
    }
17299
19639
        $EnvPaths.=":".$ENV{"BETOOLS"};
17300
19640
    }
17301
19641
    my $Sep = ($OSgroup eq "windows")?";":":|;";
17302
 
    foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
 
19642
    foreach my $Path (split(/$Sep/, $EnvPaths))
17303
19643
    {
17304
19644
        $Path = path_format($Path, $OSgroup);
17305
 
        $Path=~s/[\/\\]+\Z//g;
17306
19645
        next if(not $Path);
17307
19646
        if($SystemRoot
17308
19647
        and $Path=~/\A\Q$SystemRoot\E\//)
17309
19648
        { # do NOT use binaries from target system
17310
19649
            next;
17311
19650
        }
17312
 
        $DefaultBinPaths{$Path} = 1;
 
19651
        push_U(\@DefaultBinPaths, $Path);
17313
19652
    }
17314
19653
}
17315
19654
 
17316
19655
sub detect_inc_default_paths()
17317
19656
{
17318
19657
    return () if(not $GCC_PATH);
17319
 
    my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
 
19658
    my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]);
17320
19659
    writeFile("$TMP_DIR/empty.h", "");
17321
 
    foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
 
19660
    foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
17322
19661
    { # detecting GCC default include paths
 
19662
        next if(index($Line, "/cc1plus ")!=-1);
 
19663
        
17323
19664
        if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17324
19665
        {
17325
 
            my $Path = simplify_path($1);
17326
 
            $Path=~s/[\/\\]+\Z//g;
 
19666
            my $Path = realpath($1);
17327
19667
            $Path = path_format($Path, $OSgroup);
17328
 
            if($Path=~/c\+\+|\/g\+\+\//)
 
19668
            if(index($Path, "c++")!=-1
 
19669
            or index($Path, "/g++/")!=-1)
17329
19670
            {
17330
 
                $DPaths{"Cpp"}{$Path}=1;
 
19671
                push_U($DPaths{"Cpp"}, $Path);
17331
19672
                if(not defined $MAIN_CPP_DIR
17332
19673
                or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17333
19674
                    $MAIN_CPP_DIR = $Path;
17334
19675
                }
17335
19676
            }
17336
 
            elsif($Path=~/gcc/) {
17337
 
                $DPaths{"Gcc"}{$Path}=1;
 
19677
            elsif(index($Path, "gcc")!=-1) {
 
19678
                push_U($DPaths{"Gcc"}, $Path);
17338
19679
            }
17339
19680
            else
17340
19681
            {
17341
 
                next if($Path=~/local[\/\\]+include/);
 
19682
                if($Path=~/local[\/\\]+include/)
 
19683
                { # local paths
 
19684
                    next;
 
19685
                }
17342
19686
                if($SystemRoot
17343
19687
                and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17344
19688
                { # The GCC include path for user headers is not a part of the system root
17346
19690
                  # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17347
19691
                    next;
17348
19692
                }
17349
 
                $DPaths{"Inc"}{$Path}=1;
 
19693
                push_U($DPaths{"Inc"}, $Path);
17350
19694
            }
17351
19695
        }
17352
19696
    }
17370
19714
    if($Search!~/gcc/) {
17371
19715
        $GSearch = 0;
17372
19716
    }
17373
 
    if(keys(%{$SystemPaths{"include"}}))
 
19717
    if(@{$SystemPaths{"include"}})
17374
19718
    { # <search_headers> section of the XML descriptor
17375
19719
      # do NOT search for systems headers
17376
19720
        $HSearch = 0;
17377
19721
    }
17378
 
    if(keys(%{$SystemPaths{"lib"}}))
 
19722
    if(@{$SystemPaths{"lib"}})
17379
19723
    { # <search_headers> section of the XML descriptor
17380
19724
      # do NOT search for systems headers
17381
19725
        $LSearch = 0;
17385
19729
        next if($Type eq "include" and not $HSearch);
17386
19730
        next if($Type eq "lib" and not $LSearch);
17387
19731
        next if($Type eq "bin" and not $BSearch);
17388
 
        foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17389
 
        {
17390
 
            next if(not -d $Path);
17391
 
            $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17392
 
        }
 
19732
        push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}});
17393
19733
    }
17394
19734
    if($OSgroup ne "windows")
17395
19735
    { # unix-like
17404
19744
              # 2. use host commands: ldconfig, readelf, etc.
17405
19745
                ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17406
19746
            }
17407
 
            foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17408
 
                $SystemPaths{$Type}{$Path} = 1;
17409
 
            }
 
19747
            push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1));
17410
19748
            if(-d $RootDir."/".$Type)
17411
19749
            { # if "/lib" is symbolic link
17412
19750
                if($RootDir eq "/") {
17413
 
                    $SystemPaths{$Type}{"/".$Type} = 1;
 
19751
                    push_U($SystemPaths{$Type}, "/".$Type);
17414
19752
                }
17415
19753
                else {
17416
 
                    $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
 
19754
                    push_U($SystemPaths{$Type}, $RootDir."/".$Type);
17417
19755
                }
17418
19756
            }
17419
 
            if(-d $UsrDir) {
17420
 
                foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17421
 
                    $SystemPaths{$Type}{$Path} = 1;
17422
 
                }
 
19757
            if(-d $UsrDir)
 
19758
            {
 
19759
                push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1));
17423
19760
                if(-d $UsrDir."/".$Type)
17424
19761
                { # if "/usr/lib" is symbolic link
17425
 
                    $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
 
19762
                    push_U($SystemPaths{$Type}, $UsrDir."/".$Type);
17426
19763
                }
17427
19764
            }
17428
19765
        }
17430
19767
    if($BSearch)
17431
19768
    {
17432
19769
        detect_bin_default_paths();
17433
 
        foreach my $Path (keys(%DefaultBinPaths)) {
17434
 
            $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17435
 
        }
 
19770
        push_U($SystemPaths{"bin"}, @DefaultBinPaths);
17436
19771
    }
17437
19772
    # check environment variables
17438
19773
    if($OSgroup eq "beos")
17439
19774
    {
17440
 
        foreach (keys(%{$SystemPaths{"bin"}}))
 
19775
        foreach (my @Paths = @{$SystemPaths{"bin"}})
17441
19776
        {
17442
19777
            if($_ eq ".") {
17443
19778
                next;
17444
19779
            }
17445
 
            foreach my $Path (cmd_find($_, "d", "bin", ""))
17446
 
            { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17447
 
                $SystemPaths{"bin"}{$Path} = 1;
 
19780
            # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
 
19781
            if(my @Dirs = sort cmd_find($_, "d", "bin")) {
 
19782
                push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs);
17448
19783
            }
17449
19784
        }
17450
19785
        if($HSearch)
17451
19786
        {
17452
 
            foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17453
 
            {
17454
 
                if(is_abs($Path)) {
17455
 
                    $DefaultIncPaths{$Path} = 1;
17456
 
                }
17457
 
            }
 
19787
            push_U(\@DefaultIncPaths, grep { is_abs($_) } (
 
19788
                split(/:|;/, $ENV{"BEINCLUDES"})
 
19789
                ));
17458
19790
        }
17459
19791
        if($LSearch)
17460
19792
        {
17461
 
            foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17462
 
            {
17463
 
                if(is_abs($Path)) {
17464
 
                    $DefaultLibPaths{$Path} = 1;
17465
 
                }
17466
 
            }
 
19793
            push_U(\@DefaultLibPaths, grep { is_abs($_) } (
 
19794
                split(/:|;/, $ENV{"BELIBRARIES"}),
 
19795
                split(/:|;/, $ENV{"LIBRARY_PATH"})
 
19796
                ));
17467
19797
        }
17468
19798
    }
17469
19799
    if($LSearch)
17470
19800
    { # using linker to get system paths
17471
19801
        if(my $LPaths = detect_lib_default_paths())
17472
19802
        { # unix-like
 
19803
            my %Dirs = ();
17473
19804
            foreach my $Name (keys(%{$LPaths}))
17474
19805
            {
17475
19806
                if($SystemRoot
17479
19810
                    next;
17480
19811
                }
17481
19812
                $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17482
 
                $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
 
19813
                if(my $Dir = get_dirname($LPaths->{$Name})) {
 
19814
                    $Dirs{$Dir} = 1;
 
19815
                }
17483
19816
            }
17484
 
        }
17485
 
        foreach my $Path (keys(%DefaultLibPaths)) {
17486
 
            $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17487
 
        }
 
19817
            push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs));
 
19818
        }
 
19819
        push_U($SystemPaths{"lib"}, @DefaultLibPaths);
17488
19820
    }
17489
19821
    if($BSearch)
17490
19822
    {
17508
19840
    }
17509
19841
    if($GSearch)
17510
19842
    { # GCC path and default include dirs
17511
 
        if(not $CrossGcc) {
 
19843
        if(not $CrossGcc)
 
19844
        { # try default gcc
17512
19845
            $GCC_PATH = get_CmdPath("gcc");
17513
19846
        }
 
19847
        if(not $GCC_PATH)
 
19848
        { # try to find gcc-X.Y
 
19849
            foreach my $Path (@{$SystemPaths{"bin"}})
 
19850
            {
 
19851
                if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1))
 
19852
                { # select the latest version
 
19853
                    @GCCs = sort {$b cmp $a} @GCCs;
 
19854
                    if(check_gcc($GCCs[0], "3"))
 
19855
                    {
 
19856
                        $GCC_PATH = $GCCs[0];
 
19857
                        last;
 
19858
                    }
 
19859
                }
 
19860
            }
 
19861
        }
17514
19862
        if(not $GCC_PATH) {
17515
19863
            exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17516
19864
        }
17530
19878
                exitStatus("Error", "something is going wrong with the GCC compiler");
17531
19879
            }
17532
19880
        }
17533
 
        if(not $NoStdInc)
17534
 
        { # do NOT search in GCC standard paths
17535
 
            my %DPaths = detect_inc_default_paths();
17536
 
            %DefaultCppPaths = %{$DPaths{"Cpp"}};
17537
 
            %DefaultGccPaths = %{$DPaths{"Gcc"}};
17538
 
            %DefaultIncPaths = %{$DPaths{"Inc"}};
17539
 
            foreach my $Path (keys(%DefaultIncPaths)) {
17540
 
                $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
 
19881
        if($HSearch)
 
19882
        {
 
19883
            if(not $NoStdInc)
 
19884
            { # do NOT search in GCC standard paths
 
19885
                my %DPaths = detect_inc_default_paths();
 
19886
                @DefaultCppPaths = @{$DPaths{"Cpp"}};
 
19887
                @DefaultGccPaths = @{$DPaths{"Gcc"}};
 
19888
                @DefaultIncPaths = @{$DPaths{"Inc"}};
 
19889
                push_U($SystemPaths{"include"}, @DefaultIncPaths);
17541
19890
            }
17542
19891
        }
17543
19892
    }
17544
19893
    if($HSearch)
17545
 
    { # user include paths
 
19894
    { # users include paths
17546
19895
        my $IncPath = "/usr/include";
17547
19896
        if($SystemRoot) {
17548
19897
            $IncPath = $SystemRoot.$IncPath;
17549
19898
        }
17550
19899
        if(-d $IncPath) {
17551
 
            $UserIncPath{$IncPath}=1;
 
19900
            push_U(\@UsersIncPath, $IncPath);
17552
19901
        }
17553
19902
    }
 
19903
    
 
19904
    if($ExtraInfo)
 
19905
    {
 
19906
        writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths));
 
19907
        writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths)));
 
19908
    }
17554
19909
}
17555
19910
 
17556
19911
sub getLIB_EXT($)
17578
19933
    if($Cache{"get_dumpversion"}{$Cmd}) {
17579
19934
        return $Cache{"get_dumpversion"}{$Cmd};
17580
19935
    }
17581
 
    my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
 
19936
    my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
17582
19937
    chomp($V);
17583
19938
    return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17584
19939
}
17590
19945
    if($Cache{"get_dumpmachine"}{$Cmd}) {
17591
19946
        return $Cache{"get_dumpmachine"}{$Cmd};
17592
19947
    }
17593
 
    my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
 
19948
    my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
17594
19949
    chomp($Machine);
17595
19950
    return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17596
19951
}
17597
19952
 
17598
 
sub check_command($)
 
19953
sub checkCmd($)
17599
19954
{
17600
19955
    my $Cmd = $_[0];
17601
19956
    return "" if(not $Cmd);
17605
19960
    );
17606
19961
    foreach my $Opt (@Options)
17607
19962
    {
17608
 
        my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
 
19963
        my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
17609
19964
        if($Info) {
17610
19965
            return 1;
17611
19966
        }
17633
19988
sub get_depth($)
17634
19989
{
17635
19990
    if(defined $Cache{"get_depth"}{$_[0]}) {
17636
 
        return $Cache{"get_depth"}{$_[0]}
 
19991
        return $Cache{"get_depth"}{$_[0]};
17637
19992
    }
17638
19993
    return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17639
19994
}
17640
19995
 
17641
 
sub find_gcc_cxx_headers($)
 
19996
sub registerGccHeaders()
17642
19997
{
17643
 
    my $LibVersion = $_[0];
17644
 
    return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17645
 
    # detecting system header paths
17646
 
    foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
 
19998
    return if($Cache{"registerGccHeaders"}); # this function should be called once
 
19999
    
 
20000
    foreach my $Path (@DefaultGccPaths)
17647
20001
    {
17648
 
        foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
 
20002
        my @Headers = cmd_find($Path,"f");
 
20003
        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
 
20004
        foreach my $HPath (@Headers)
17649
20005
        {
17650
 
            my $FileName = get_filename($HeaderPath);
17651
 
            next if($DefaultGccHeader{$FileName});
17652
 
            $DefaultGccHeader{$FileName} = $HeaderPath;
 
20006
            my $FileName = get_filename($HPath);
 
20007
            if(not defined $DefaultGccHeader{$FileName})
 
20008
            { # skip duplicated
 
20009
                $DefaultGccHeader{$FileName} = $HPath;
 
20010
            }
17653
20011
        }
17654
20012
    }
17655
 
    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
 
20013
    $Cache{"registerGccHeaders"} = 1;
 
20014
}
 
20015
 
 
20016
sub registerCppHeaders()
 
20017
{
 
20018
    return if($Cache{"registerCppHeaders"}); # this function should be called once
 
20019
    
 
20020
    foreach my $CppDir (@DefaultCppPaths)
17656
20021
    {
17657
 
        foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
 
20022
        my @Headers = cmd_find($CppDir,"f");
 
20023
        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
 
20024
        foreach my $Path (@Headers)
17658
20025
        {
17659
 
            my @AllCppHeaders = cmd_find($CppDir,"f","","");
17660
 
            foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17661
 
            {
17662
 
                my $FileName = get_filename($Path);
17663
 
                next if($DefaultCppHeader{$FileName});
 
20026
            my $FileName = get_filename($Path);
 
20027
            if(not defined $DefaultCppHeader{$FileName})
 
20028
            { # skip duplicated
17664
20029
                $DefaultCppHeader{$FileName} = $Path;
17665
20030
            }
17666
20031
        }
17667
20032
    }
17668
 
    $Cache{"find_gcc_cxx_headers"} = 1;
 
20033
    $Cache{"registerCppHeaders"} = 1;
17669
20034
}
17670
20035
 
17671
20036
sub parse_libname($$$)
17672
20037
{
 
20038
    return "" if(not $_[0]);
 
20039
    if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
 
20040
        return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
 
20041
    }
 
20042
    return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
 
20043
}
 
20044
 
 
20045
sub parse_libname_I($$$)
 
20046
{
17673
20047
    my ($Name, $Type, $Target) = @_;
17674
 
    if(not $Name) {
17675
 
        return "";
17676
 
    }
 
20048
    
17677
20049
    if($Target eq "symbian") {
17678
20050
        return parse_libname_symbian($Name, $Type);
17679
20051
    }
17680
20052
    elsif($Target eq "windows") {
17681
20053
        return parse_libname_windows($Name, $Type);
17682
20054
    }
 
20055
    
 
20056
    # unix
17683
20057
    my $Ext = getLIB_EXT($Target);
17684
 
    if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
 
20058
    if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
17685
20059
    { # libSDL-1.2.so.0.7.1
17686
20060
      # libwbxml2.so.0.0.18
 
20061
      # libopcodes-2.21.53-system.20110810.so
17687
20062
        if($Type eq "name")
17688
20063
        { # libSDL-1.2
17689
20064
          # libwbxml2
17696
20071
        }
17697
20072
        elsif($Type eq "version")
17698
20073
        {
17699
 
            if($7 ne "")
 
20074
            if(defined $7
 
20075
            and $7 ne "")
17700
20076
            { # 0.7.1
17701
20077
                return $7;
17702
20078
            }
17795
20171
    return $Name;
17796
20172
}
17797
20173
 
17798
 
sub getPrefix($)
17799
 
{
17800
 
    my $Str = $_[0];
17801
 
    if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
17802
 
    { # GetError
17803
 
        return "";
17804
 
    }
17805
 
    if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
17806
 
    { # XmuValidArea: Xmu
17807
 
        return $1;
17808
 
    }
17809
 
    elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
17810
 
    { # snfReadFont: snf
17811
 
        return $1;
17812
 
    }
17813
 
    elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
17814
 
    { # XRRTimes: XRR
17815
 
        return $1;
17816
 
    }
17817
 
    elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
17818
 
    { # alarm_event_add: alarm_
17819
 
        return $1;
17820
 
    }
17821
 
    elsif($Str=~/\A(([a-z])\2{1,})/i)
17822
 
    { # ffopen
17823
 
        return $1;
17824
 
    }
17825
 
    else {
17826
 
        return "";
17827
 
    }
17828
 
}
17829
 
 
17830
 
sub problem_title($)
17831
 
{
17832
 
    if($_[0]==1)  {
17833
 
        return "1 problem";
17834
 
    }
17835
 
    else  {
17836
 
        return $_[0]." problems";
17837
 
    }
17838
 
}
17839
 
 
17840
 
sub warning_title($)
17841
 
{
17842
 
    if($_[0]==1)  {
17843
 
        return "1 warning";
17844
 
    }
17845
 
    else  {
17846
 
        return $_[0]." warnings";
17847
 
    }
17848
 
}
17849
 
 
17850
20174
sub createSymbolsList($$$$$)
17851
20175
{
17852
20176
    my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
17889
20213
        {
17890
20214
            my %NS_Symbol = ();
17891
20215
            foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
17892
 
                $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
 
20216
                $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1;
17893
20217
            }
17894
20218
            foreach my $NameSpace (sort keys(%NS_Symbol))
17895
20219
            {
17906
20230
                    {
17907
20231
                        if($Signature) {
17908
20232
                            $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
17909
 
                        }# report_added
 
20233
                        }
17910
20234
                        else {
17911
20235
                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17912
20236
                        }
17941
20265
    my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
17942
20266
    $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
17943
20267
    <body><div>\n$SYMBOLS_LIST</div>
17944
 
    <br/><br/><hr/>\n".getReportFooter($LName)."
 
20268
    <br/><br/><hr/>\n".getReportFooter($LName, 1)."
17945
20269
    <div style='height:999px;'></div></body></html>";
17946
20270
    writeFile($SaveTo, $SYMBOLS_LIST);
17947
20271
}
17948
20272
 
17949
 
sub readModule($$)
 
20273
sub add_target_libs($)
17950
20274
{
17951
 
    my ($Module, $Name) = @_;
17952
 
    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
17953
 
    if(not -f $Path) {
17954
 
        exitStatus("Module_Error", "can't access \'$Path\'");
 
20275
    foreach (@{$_[0]}) {
 
20276
        $TargetLibs{$_} = 1;
17955
20277
    }
17956
 
    return readFile($Path);
17957
20278
}
17958
20279
 
17959
20280
sub is_target_lib($)
17960
20281
{
17961
20282
    my $LName = $_[0];
 
20283
    if(not $LName) {
 
20284
        return 0;
 
20285
    }
17962
20286
    if($TargetLibraryName
17963
20287
    and $LName!~/\Q$TargetLibraryName\E/) {
17964
20288
        return 0;
17992
20316
    my $UsedAltDescr = 0;
17993
20317
    foreach my $Part (split(/\s*,\s*/, $Path))
17994
20318
    { # try to get version string from file path
17995
 
        next if($Part=~/\.xml\Z/i);
17996
 
        next if(isDump($Part));
 
20319
        next if(isDump($Part)); # ABI dump
 
20320
        next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
17997
20321
        my $VerNum = "";
17998
20322
        if(parse_libname($Part, "name", $OStarget))
17999
20323
        {
18000
20324
            $UsedAltDescr = 1;
18001
20325
            $VerNum = parse_libname($Part, "version", $OStarget);
18002
20326
            if(not $VerNum) {
18003
 
                $VerNum = readStringVersion($Part);
 
20327
                $VerNum = readStrVer($Part);
18004
20328
            }
18005
20329
        }
18006
20330
        elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18007
20331
        {
18008
20332
            $UsedAltDescr = 1;
18009
 
            $VerNum = readStringVersion($Part);
 
20333
            $VerNum = readStrVer($Part);
18010
20334
        }
18011
20335
        if($VerNum ne "")
18012
20336
        {
18013
20337
            $TargetVersion{$LibVersion} = $VerNum;
18014
20338
            if($DumpAPI) {
18015
 
                printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
 
20339
                printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)");
18016
20340
            }
18017
20341
            else {
18018
 
                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
 
20342
                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)");
18019
20343
            }
18020
20344
            return $TargetVersion{$LibVersion};
18021
20345
        }
18023
20347
    if($UsedAltDescr)
18024
20348
    {
18025
20349
        if($DumpAPI) {
18026
 
            exitStatus("Error", "version number is not set (use -vnum <num> option)");
 
20350
            exitStatus("Error", "version number is not set (use -vnum option)");
18027
20351
        }
18028
20352
        else {
18029
 
            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
 
20353
            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)");
18030
20354
        }
18031
20355
    }
18032
20356
}
18033
20357
 
18034
 
sub readStringVersion($)
 
20358
sub readStrVer($)
18035
20359
{
18036
20360
    my $Str = $_[0];
18037
20361
    return "" if(not $Str);
18321
20645
    }
18322
20646
}
18323
20647
 
 
20648
sub diffSets($$)
 
20649
{
 
20650
    my ($S1, $S2) = @_;
 
20651
    my @SK1 = keys(%{$S1});
 
20652
    my @SK2 = keys(%{$S2});
 
20653
    if($#SK1!=$#SK2) {
 
20654
        return 1;
 
20655
    }
 
20656
    foreach my $K1 (@SK1)
 
20657
    {
 
20658
        if(not defined $S2->{$K1}) {
 
20659
            return 1;
 
20660
        }
 
20661
    }
 
20662
    return 0;
 
20663
}
 
20664
 
18324
20665
sub create_ABI_Dump()
18325
20666
{
18326
20667
    if(not -e $DumpAPI) {
18327
20668
        exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18328
20669
    }
18329
 
    # check the archive utilities
18330
 
    if($OSgroup eq "windows")
18331
 
    { # using zip
18332
 
        my $ZipCmd = get_CmdPath("zip");
18333
 
        if(not $ZipCmd) {
18334
 
            exitStatus("Not_Found", "can't find \"zip\"");
18335
 
        }
18336
 
    }
18337
 
    else
18338
 
    { # using tar and gzip
18339
 
        my $TarCmd = get_CmdPath("tar");
18340
 
        if(not $TarCmd) {
18341
 
            exitStatus("Not_Found", "can't find \"tar\"");
18342
 
        }
18343
 
        my $GzipCmd = get_CmdPath("gzip");
18344
 
        if(not $GzipCmd) {
18345
 
            exitStatus("Not_Found", "can't find \"gzip\"");
18346
 
        }
18347
 
    }
18348
20670
    my @DParts = split(/\s*,\s*/, $DumpAPI);
18349
20671
    foreach my $Part (@DParts)
18350
20672
    {
18362
20684
            readDescriptor(1, createDescriptor(1, $Part));
18363
20685
        }
18364
20686
    }
 
20687
    
 
20688
    if(not $Descriptor{1}{"Version"})
 
20689
    { # set to default: X
 
20690
        $Descriptor{1}{"Version"} = "X";
 
20691
    }
 
20692
    
18365
20693
    initLogging(1);
18366
20694
    detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18367
 
    if(not $CheckHeadersOnly) {
18368
 
        readLibs(1);
18369
 
    }
18370
 
    if($CheckHeadersOnly) {
18371
 
        setLanguage(1, "C++");
18372
 
    }
18373
 
    if(not $CheckObjectsOnly) {
18374
 
        searchForHeaders(1);
18375
 
    }
18376
 
    $WORD_SIZE{1} = detectWordSize();
18377
 
    if($Descriptor{1}{"Headers"}
18378
 
    and not $Descriptor{1}{"Dump"}) {
18379
 
        readHeaders(1);
 
20695
    
 
20696
    my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
 
20697
    $DumpPath .= ".".$AR_EXT; # gzipped by default
 
20698
    if($OutputDumpPath)
 
20699
    { # user defined path
 
20700
        $DumpPath = $OutputDumpPath;
 
20701
    }
 
20702
    my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
 
20703
    
 
20704
    if(not $Archive and not $StdOut)
 
20705
    { # check archive utilities
 
20706
        if($OSgroup eq "windows")
 
20707
        { # using zip
 
20708
            my $ZipCmd = get_CmdPath("zip");
 
20709
            if(not $ZipCmd) {
 
20710
                exitStatus("Not_Found", "can't find \"zip\"");
 
20711
            }
 
20712
        }
 
20713
        else
 
20714
        { # using tar and gzip
 
20715
            my $TarCmd = get_CmdPath("tar");
 
20716
            if(not $TarCmd) {
 
20717
                exitStatus("Not_Found", "can't find \"tar\"");
 
20718
            }
 
20719
            my $GzipCmd = get_CmdPath("gzip");
 
20720
            if(not $GzipCmd) {
 
20721
                exitStatus("Not_Found", "can't find \"gzip\"");
 
20722
            }
 
20723
        }
 
20724
    }
 
20725
    
 
20726
    if(not $Descriptor{1}{"Dump"})
 
20727
    {
 
20728
        if(not $CheckHeadersOnly) {
 
20729
            readLibs(1);
 
20730
        }
 
20731
        if($CheckHeadersOnly) {
 
20732
            setLanguage(1, "C++");
 
20733
        }
 
20734
        if(not $CheckObjectsOnly) {
 
20735
            searchForHeaders(1);
 
20736
        }
 
20737
        $WORD_SIZE{1} = detectWordSize();
 
20738
    }
 
20739
    if(not $Descriptor{1}{"Dump"})
 
20740
    {
 
20741
        if($Descriptor{1}{"Headers"}) {
 
20742
            readHeaders(1);
 
20743
        }
18380
20744
    }
18381
20745
    cleanDump(1);
18382
20746
    if(not keys(%{$SymbolInfo{1}}))
18392
20756
        }
18393
20757
    }
18394
20758
    my %HeadersInfo = ();
18395
 
    foreach my $HPath (keys(%{$Registered_Headers{1}}))
18396
 
    { # headers info stored without paths in the dump
 
20759
    foreach my $HPath (keys(%{$Registered_Headers{1}})) {
18397
20760
        $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18398
20761
    }
 
20762
    if($ExtraDump)
 
20763
    { # add unmangled names to the ABI dump
 
20764
        my @Names = ();
 
20765
        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
 
20766
        {
 
20767
            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) {
 
20768
                push(@Names, $MnglName);
 
20769
            }
 
20770
        }
 
20771
        translateSymbols(@Names, 1);
 
20772
        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
 
20773
        {
 
20774
            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"})
 
20775
            {
 
20776
                if(my $Unmangled = $tr_name{$MnglName})
 
20777
                {
 
20778
                    if($MnglName ne $Unmangled) {
 
20779
                        $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled;
 
20780
                    }
 
20781
                }
 
20782
            }
 
20783
        }
 
20784
    }
 
20785
    
 
20786
    my %GccConstants = (); # built-in GCC constants
 
20787
    foreach my $Name (keys(%{$Constants{1}}))
 
20788
    {
 
20789
        if(not defined $Constants{1}{$Name}{"Header"})
 
20790
        {
 
20791
            $GccConstants{$Name} = $Constants{1}{$Name}{"Value"};
 
20792
            delete($Constants{1}{$Name});
 
20793
        }
 
20794
    }
 
20795
    
18399
20796
    printMsg("INFO", "creating library ABI dump ...");
18400
 
    my %LibraryABI = (
 
20797
    my %ABI = (
18401
20798
        "TypeInfo" => $TypeInfo{1},
18402
20799
        "SymbolInfo" => $SymbolInfo{1},
18403
20800
        "Symbols" => $Library_Symbol{1},
18410
20807
        "SkipSymbols" => $SkipSymbols{1},
18411
20808
        "SkipNameSpaces" => $SkipNameSpaces{1},
18412
20809
        "SkipHeaders" => $SkipHeadersList{1},
18413
 
        "TargetHeaders" => $TargetHeaders{1},
18414
20810
        "Headers" => \%HeadersInfo,
18415
20811
        "Constants" => $Constants{1},
 
20812
        "GccConstants" => \%GccConstants,
18416
20813
        "NameSpaces" => $NestedNameSpaces{1},
18417
20814
        "Target" => $OStarget,
18418
20815
        "Arch" => getArch(1),
18421
20818
        "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18422
20819
        "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18423
20820
    );
 
20821
    if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
 
20822
        $ABI{"TargetHeaders"} = $TargetHeaders{1};
 
20823
    }
 
20824
    if($UseXML) {
 
20825
        $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
 
20826
    }
18424
20827
    if($ExtendedCheck)
18425
20828
    { # --ext option
18426
 
        $LibraryABI{"Mode"} = "Extended";
 
20829
        $ABI{"Mode"} = "Extended";
18427
20830
    }
18428
20831
    if($BinaryOnly)
18429
20832
    { # --binary
18430
 
        $LibraryABI{"BinOnly"} = 1;
 
20833
        $ABI{"BinOnly"} = 1;
 
20834
    }
 
20835
    if($ExtraDump)
 
20836
    { # --extra-dump
 
20837
        $ABI{"Extra"} = 1;
 
20838
        $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1};
 
20839
        $ABI{"Needed"} = $Library_Needed{1};
 
20840
    }
 
20841
    
 
20842
    my $ABI_DUMP = "";
 
20843
    if($UseXML)
 
20844
    {
 
20845
        loadModule("XmlDump");
 
20846
        $ABI_DUMP = createXmlDump(\%ABI);
18431
20847
    }
18432
20848
    else
18433
20849
    { # default
18434
 
        $LibraryABI{"SrcBin"} = 1;
 
20850
        $ABI_DUMP = Dumper(\%ABI);
18435
20851
    }
18436
 
    
18437
20852
    if($StdOut)
18438
20853
    { # --stdout option
18439
 
        print STDOUT Dumper(\%LibraryABI);
 
20854
        print STDOUT $ABI_DUMP;
18440
20855
        printMsg("INFO", "ABI dump has been generated to stdout");
18441
20856
        return;
18442
20857
    }
18443
20858
    else
18444
20859
    { # write to gzipped file
18445
 
        my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
18446
 
        if($OutputDumpPath)
18447
 
        { # user defined path
18448
 
            $DumpPath = $OutputDumpPath;
18449
 
        }
18450
 
        if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
18451
 
            exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
18452
 
        }
18453
20860
        my ($DDir, $DName) = separate_path($DumpPath);
18454
20861
        my $DPath = $TMP_DIR."/".$DName;
 
20862
        if(not $Archive) {
 
20863
            $DPath = $DumpPath;
 
20864
        }
 
20865
        
18455
20866
        mkpath($DDir);
18456
20867
        
18457
20868
        open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18458
 
        print DUMP Dumper(\%LibraryABI);
 
20869
        print DUMP $ABI_DUMP;
18459
20870
        close(DUMP);
18460
20871
        
18461
20872
        if(not -s $DPath) {
18462
20873
            exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18463
20874
        }
18464
 
        my $Pkg = createArchive($DPath, $DDir);
18465
 
        printMsg("INFO", "library ABI has been dumped to:\n  $Pkg");
 
20875
        if($Archive) {
 
20876
            $DumpPath = createArchive($DPath, $DDir);
 
20877
        }
 
20878
        
 
20879
        if($OutputDumpPath) {
 
20880
            printMsg("INFO", "library ABI has been dumped to:\n  $OutputDumpPath");
 
20881
        }
 
20882
        else {
 
20883
            printMsg("INFO", "library ABI has been dumped to:\n  $DumpPath");
 
20884
        }
18466
20885
        printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18467
20886
    }
18468
20887
}
18481
20900
        my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18482
20901
        if($FilePath1 and $FilePath2)
18483
20902
        {
 
20903
            my $Line = readLineNum($FilePath1, 0);
 
20904
            if($Line=~/xml/)
 
20905
            { # XML format
 
20906
                # is not supported yet
 
20907
                return;
 
20908
            }
 
20909
            
18484
20910
            local $/ = undef;
18485
20911
            
18486
20912
            open(DUMP1, $FilePath1);
18503
20929
                undef $Content1;
18504
20930
                
18505
20931
                if(not $ABIdump) {
18506
 
                    exitStatus("Error", "internal error");
 
20932
                    exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
18507
20933
                }
18508
20934
                if(not $ABIdump->{"TypeInfo"})
18509
20935
                { # support for old dumps
18513
20939
                { # support for old dumps
18514
20940
                    $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18515
20941
                }
18516
 
                read_Headers_DumpInfo($ABIdump, 1);
 
20942
                read_Source_DumpInfo($ABIdump, 1);
18517
20943
                read_Libs_DumpInfo($ABIdump, 1);
18518
20944
                read_Machine_DumpInfo($ABIdump, 1);
18519
20945
                read_Machine_DumpInfo($ABIdump, 2);
18545
20971
        mkpath($LOG_DIR);
18546
20972
    }
18547
20973
    $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18548
 
    resetLogging($LibVersion);
18549
20974
    if($Debug)
18550
20975
    { # debug directory
18551
20976
        $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18552
 
        rmtree($DEBUG_PATH{$LibVersion});
 
20977
        
 
20978
        if(not $ExtraInfo)
 
20979
        { # enable --extra-info
 
20980
            $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info";
 
20981
        }
 
20982
        
 
20983
        # enable --extra-dump
 
20984
        $ExtraDump = 1;
18553
20985
    }
 
20986
    resetLogging($LibVersion);
18554
20987
}
18555
20988
 
18556
20989
sub writeLog($$)
18567
21000
    if($LogMode!~/a|n/)
18568
21001
    { # remove old log
18569
21002
        unlink($LOG_PATH{$LibVersion});
 
21003
        if($Debug) {
 
21004
            rmtree($DEBUG_PATH{$LibVersion});
 
21005
        }
18570
21006
    }
18571
21007
}
18572
21008
 
18580
21016
 
18581
21017
sub isDump($)
18582
21018
{
18583
 
    if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18584
 
    { # returns a name of package
 
21019
    if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz|\.zip|\.xml|)(\.\w+|)\Z/) {
 
21020
        return $1;
 
21021
    }
 
21022
    return 0;
 
21023
}
 
21024
 
 
21025
sub isDump_U($)
 
21026
{
 
21027
    if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.xml|)(\.\w+|)\Z/) {
18585
21028
        return $1;
18586
21029
    }
18587
21030
    return 0;
18638
21081
            readDescriptor(2, createDescriptor(2, $Part));
18639
21082
        }
18640
21083
    }
 
21084
    
 
21085
    if(not $Descriptor{1}{"Version"})
 
21086
    { # set to default: X
 
21087
        $Descriptor{1}{"Version"} = "X";
 
21088
    }
 
21089
    
 
21090
    if(not $Descriptor{2}{"Version"})
 
21091
    { # set to default: Y
 
21092
        $Descriptor{2}{"Version"} = "Y";
 
21093
    }
 
21094
    
18641
21095
    initLogging(1);
18642
21096
    initLogging(2);
18643
21097
    # check consistency
18657
21111
    and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18658
21112
        exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18659
21113
    }
18660
 
    if(not $Descriptor{1}{"Headers"}) {
 
21114
    if(not $Descriptor{1}{"Headers"})
 
21115
    {
18661
21116
        if($CheckHeadersOnly_Opt) {
18662
21117
            exitStatus("Error", "can't find header files info in descriptor d1");
18663
21118
        }
18664
21119
    }
18665
 
    if(not $Descriptor{2}{"Headers"}) {
 
21120
    if(not $Descriptor{2}{"Headers"})
 
21121
    {
18666
21122
        if($CheckHeadersOnly_Opt) {
18667
21123
            exitStatus("Error", "can't find header files info in descriptor d2");
18668
21124
        }
18669
21125
    }
18670
21126
    if(not $Descriptor{1}{"Headers"}
18671
 
    or not $Descriptor{2}{"Headers"}) {
18672
 
        if(not $CheckObjectsOnly_Opt) {
 
21127
    or not $Descriptor{2}{"Headers"})
 
21128
    {
 
21129
        if(not $CheckObjectsOnly_Opt)
 
21130
        {
18673
21131
            printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18674
21132
            $CheckObjectsOnly = 1;
18675
21133
        }
18676
21134
    }
18677
 
    if(not $Descriptor{1}{"Libs"}) {
 
21135
    if(not $Descriptor{1}{"Libs"})
 
21136
    {
18678
21137
        if($CheckObjectsOnly_Opt) {
18679
21138
            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18680
21139
        }
18681
21140
    }
18682
 
    if(not $Descriptor{2}{"Libs"}) {
 
21141
    if(not $Descriptor{2}{"Libs"})
 
21142
    {
18683
21143
        if($CheckObjectsOnly_Opt) {
18684
21144
            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18685
21145
        }
18697
21157
    if($UseDumps)
18698
21158
    { # --use-dumps
18699
21159
      # parallel processing
 
21160
        my $DumpPath1 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT";
 
21161
        my $DumpPath2 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT";
 
21162
        
 
21163
        unlink($DumpPath1);
 
21164
        unlink($DumpPath2);
 
21165
        
18700
21166
        my $pid = fork();
18701
21167
        if($pid)
18702
21168
        { # dump on two CPU cores
18737
21203
            if($SortDump) {
18738
21204
                @PARAMS = (@PARAMS, "-sort");
18739
21205
            }
 
21206
            if($DumpFormat and $DumpFormat ne "perl") {
 
21207
                @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
 
21208
            }
 
21209
            if($CheckHeadersOnly) {
 
21210
                @PARAMS = (@PARAMS, "-headers-only");
 
21211
            }
 
21212
            if($CheckObjectsOnly) {
 
21213
                @PARAMS = (@PARAMS, "-objects-only");
 
21214
            }
18740
21215
            if($Debug)
18741
21216
            {
18742
21217
                @PARAMS = (@PARAMS, "-debug");
18743
21218
                printMsg("INFO", "running perl $0 @PARAMS");
18744
21219
            }
18745
21220
            system("perl", $0, @PARAMS);
18746
 
            if($?) {
 
21221
            if(not -f $DumpPath1) {
18747
21222
                exit(1);
18748
21223
            }
18749
21224
        }
18786
21261
            if($SortDump) {
18787
21262
                @PARAMS = (@PARAMS, "-sort");
18788
21263
            }
 
21264
            if($DumpFormat and $DumpFormat ne "perl") {
 
21265
                @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
 
21266
            }
 
21267
            if($CheckHeadersOnly) {
 
21268
                @PARAMS = (@PARAMS, "-headers-only");
 
21269
            }
 
21270
            if($CheckObjectsOnly) {
 
21271
                @PARAMS = (@PARAMS, "-objects-only");
 
21272
            }
18789
21273
            if($Debug)
18790
21274
            {
18791
21275
                @PARAMS = (@PARAMS, "-debug");
18792
21276
                printMsg("INFO", "running perl $0 @PARAMS");
18793
21277
            }
18794
21278
            system("perl", $0, @PARAMS);
18795
 
            if($?) {
 
21279
            if(not -f $DumpPath2) {
18796
21280
                exit(1);
18797
21281
            }
18798
21282
            else {
18801
21285
        }
18802
21286
        waitpid($pid, 0);
18803
21287
        my @CMP_PARAMS = ("-l", $TargetLibraryName);
18804
 
        @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
18805
 
        @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
 
21288
        @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1);
 
21289
        @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2);
18806
21290
        if($TargetLibraryFName ne $TargetLibraryName) {
18807
21291
            @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
18808
21292
        }
18812
21296
        if($CrossGcc) {
18813
21297
            @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
18814
21298
        }
18815
 
        if($Quiet)
18816
 
        {
 
21299
        @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
 
21300
        if($Quiet) {
18817
21301
            @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
18818
 
            @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
18819
 
        }
18820
 
        elsif($LogMode and $LogMode ne "w")
18821
 
        { # "w" is default
18822
 
            @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
18823
21302
        }
18824
21303
        if($ReportFormat and $ReportFormat ne "html")
18825
21304
        { # HTML is default format
18837
21316
        if($LoggingPath) {
18838
21317
            @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
18839
21318
        }
 
21319
        if($CheckHeadersOnly) {
 
21320
            @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
 
21321
        }
 
21322
        if($CheckObjectsOnly) {
 
21323
            @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
 
21324
        }
 
21325
        if($BinaryOnly) {
 
21326
            @CMP_PARAMS = (@CMP_PARAMS, "-binary");
 
21327
        }
 
21328
        if($SourceOnly) {
 
21329
            @CMP_PARAMS = (@CMP_PARAMS, "-source");
 
21330
        }
18840
21331
        if($Browse) {
18841
21332
            @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
18842
21333
        }
18973
21464
{
18974
21465
    my $Level = $_[0];
18975
21466
    readRules($Level);
 
21467
    loadModule("CallConv");
18976
21468
    if($Level eq "Binary") {
18977
21469
        printMsg("INFO", "comparing ABIs ...");
18978
21470
    }
18992
21484
    }
18993
21485
    if(not $CheckObjectsOnly)
18994
21486
    {
18995
 
        mergeSignatures($Level);
 
21487
        mergeSymbols($Level);
18996
21488
        if(keys(%{$CheckedSymbols{$Level}})) {
18997
21489
            mergeConstants($Level);
18998
21490
        }
19012
21504
    }
19013
21505
}
19014
21506
 
19015
 
sub writeOpts()
 
21507
sub getSysOpts()
19016
21508
{
19017
21509
    my %Opts = (
19018
21510
    "OStarget"=>$OStarget,
19029
21521
    "TargetLibraryName"=>$TargetLibraryName,
19030
21522
    "CrossGcc"=>$CrossGcc,
19031
21523
    "UseStaticLibs"=>$UseStaticLibs,
19032
 
    "NoStdInc"=>$NoStdInc
 
21524
    "NoStdInc"=>$NoStdInc,
 
21525
    
 
21526
    "BinaryOnly" => $BinaryOnly,
 
21527
    "SourceOnly" => $SourceOnly
19033
21528
    );
19034
21529
    return \%Opts;
19035
21530
}
19036
21531
 
19037
 
sub get_CoreError($)
 
21532
sub get_CodeError($)
19038
21533
{
19039
21534
    my %CODE_ERROR = reverse(%ERROR_CODE);
19040
21535
    return $CODE_ERROR{$_[0]};
19065
21560
            $COMMON_LOG_PATH = $LoggingPath;
19066
21561
        }
19067
21562
    }
 
21563
    if($OutputDumpPath)
 
21564
    { # validate
 
21565
        if(not isDump($OutputDumpPath)) {
 
21566
            exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
 
21567
        }
 
21568
    }
19068
21569
    if($BinaryOnly and $SourceOnly)
19069
21570
    { # both --binary and --source
19070
21571
      # is the default mode
19086
21587
    if($UseXML)
19087
21588
    { # --xml option
19088
21589
        $ReportFormat = "xml";
 
21590
        $DumpFormat = "xml";
19089
21591
    }
19090
21592
    if($ReportFormat)
19091
21593
    { # validate
19092
21594
        $ReportFormat = lc($ReportFormat);
19093
21595
        if($ReportFormat!~/\A(xml|html|htm)\Z/) {
19094
 
            exitStatus("Error", "unknown format \'$ReportFormat\'");
 
21596
            exitStatus("Error", "unknown report format \'$ReportFormat\'");
19095
21597
        }
19096
21598
        if($ReportFormat eq "htm")
19097
21599
        { # HTM == HTML
19106
21608
    { # default: HTML
19107
21609
        $ReportFormat = "html";
19108
21610
    }
 
21611
    if($DumpFormat)
 
21612
    { # validate
 
21613
        $DumpFormat = lc($DumpFormat);
 
21614
        if($DumpFormat!~/\A(xml|perl)\Z/) {
 
21615
            exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
 
21616
        }
 
21617
        if($DumpFormat eq "xml")
 
21618
        { # --dump-format=XML equal to --xml
 
21619
            $UseXML = 1;
 
21620
        }
 
21621
    }
 
21622
    else
 
21623
    { # default: Perl Data::Dumper
 
21624
        $DumpFormat = "perl";
 
21625
    }
19109
21626
    if($Quiet and $LogMode!~/a|n/)
19110
21627
    { # --quiet log
19111
21628
        if(-f $COMMON_LOG_PATH) {
19112
21629
            unlink($COMMON_LOG_PATH);
19113
21630
        }
19114
21631
    }
 
21632
    if($ExtraInfo) {
 
21633
        $CheckUndefined = 1;
 
21634
    }
19115
21635
    if($TestTool and $UseDumps)
19116
21636
    { # --test && --use-dumps == --test-dump
19117
21637
        $TestDump = 1;
19118
21638
    }
19119
 
    if($Help) {
 
21639
    if($Tolerant)
 
21640
    { # enable all
 
21641
        $Tolerance = 1234;
 
21642
    }
 
21643
    if($Help)
 
21644
    {
19120
21645
        HELP_MESSAGE();
19121
21646
        exit(0);
19122
21647
    }
19124
21649
        INFO_MESSAGE();
19125
21650
        exit(0);
19126
21651
    }
19127
 
    if($ShowVersion) {
 
21652
    if($ShowVersion)
 
21653
    {
19128
21654
        printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2012 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.");
19129
21655
        exit(0);
19130
21656
    }
19131
 
    if($DumpVersion) {
 
21657
    if($DumpVersion)
 
21658
    {
19132
21659
        printMsg("INFO", $TOOL_VERSION);
19133
21660
        exit(0);
19134
21661
    }
19184
21711
    { # --test, --test-dump
19185
21712
        detect_default_paths("bin|gcc"); # to compile libs
19186
21713
        loadModule("RegTests");
19187
 
        testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19188
 
        $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
 
21714
        testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
 
21715
        $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
19189
21716
        exit(0);
19190
21717
    }
19191
21718
    if($DumpSystem)
19192
21719
    { # --dump-system
19193
21720
        loadModule("SysCheck");
19194
 
        if($DumpSystem=~/\.xml\Z/)
 
21721
        if($DumpSystem=~/\.(xml|desc)\Z/)
19195
21722
        { # system XML descriptor
19196
21723
            if(not -f $DumpSystem) {
19197
21724
                exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19198
21725
            }
19199
21726
            my $Ret = readSystemDescriptor(readFile($DumpSystem));
19200
 
            foreach (@{$Ret->{"Tools"}}) {
19201
 
                $SystemPaths{"bin"}{$_} = 1;
19202
 
                $TargetTools{$_}=1;
 
21727
            foreach (@{$Ret->{"Tools"}})
 
21728
            {
 
21729
                push_U($SystemPaths{"bin"}, $_);
 
21730
                $TargetTools{$_} = 1;
19203
21731
            }
19204
21732
            if($Ret->{"CrossPrefix"}) {
19205
21733
                $CrossPrefix = $Ret->{"CrossPrefix"};
19241
21769
          # and undname.exe
19242
21770
            check_win32_env();
19243
21771
        }
19244
 
        dumpSystem(writeOpts());
 
21772
        dumpSystem(getSysOpts());
19245
21773
        exit(0);
19246
21774
    }
19247
21775
    if($CmpSystems)
19248
21776
    { # --cmp-systems
19249
21777
        detect_default_paths("bin"); # to extract dumps
19250
21778
        loadModule("SysCheck");
19251
 
        cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
 
21779
        cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
19252
21780
        exit(0);
19253
21781
    }
19254
 
    if($GenerateTemplate) {
19255
 
        generateTemplate();
 
21782
    if($GenerateTemplate)
 
21783
    {
 
21784
        writeFile("VERSION.xml", $DescriptorTemplate."\n");
 
21785
        printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
19256
21786
        exit(0);
19257
21787
    }
19258
21788
    if(not $TargetLibraryName) {
19259
 
        exitStatus("Error", "library name is not selected (option -l <name>)");
 
21789
        exitStatus("Error", "library name is not selected (-l option)");
19260
21790
    }
19261
21791
    else
19262
21792
    { # validate library name
19279
21809
            $SymbolsList{$Interface} = 1;
19280
21810
        }
19281
21811
    }
 
21812
    if($SkipSymbolsListPath)
 
21813
    {
 
21814
        if(not -f $SkipSymbolsListPath) {
 
21815
            exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'");
 
21816
        }
 
21817
        foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) {
 
21818
            $SkipSymbolsList{$Interface} = 1;
 
21819
        }
 
21820
    }
19282
21821
    if($SkipHeadersPath)
19283
21822
    {
19284
21823
        if(not -f $SkipHeadersPath) {