abi-compliance-checker.pl revision ac687f969ca8bee69e9eb5e3267097f679cf283b
1f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#!/usr/bin/perl
2f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch###########################################################################
3f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# ABI Compliance Checker (ACC) 1.99.8
4f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# A tool for checking backward compatibility of a C/C++ library API
5f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
6f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright (C) 2009-2010 The Linux Foundation
7f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright (C) 2009-2011 Institute for System Programming, RAS
8f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright (C) 2011-2013 ROSA Laboratory
10f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
11f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Written by Andrey Ponomarenko
12f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
13f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# PLATFORMS
14f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# =========
15f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#  Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# REQUIREMENTS
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# ============
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#  Linux
20f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - G++ (3.0-4.7, recommended 4.5 or newer)
21f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - GNU Binutils (readelf, c++filt, objdump)
22f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Perl 5 (5.8 or newer)
23f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Ctags (5.8 or newer)
24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#  Mac OS X
26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Xcode (g++, c++filt, otool, nm)
27f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Ctags (5.8 or newer)
28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
29f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#  MS Windows
30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - MinGW (3.0-4.7, recommended 4.5 or newer)
31f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - MS Visual C++ (dumpbin, undname, cl)
32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Active Perl 5 (5.8 or newer)
33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Sigcheck v1.71 or newer
34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Info-ZIP 3.0 (zip, unzip)
35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Ctags (5.8 or newer)
36f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Add tool locations to the PATH environment variable
37f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#    - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# COMPATIBILITY
40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# =============
41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#  ABI Dumper >= 0.98
42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
43f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
44f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# This program is free software: you can redistribute it and/or modify
45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# it under the terms of the GNU General Public License or the GNU Lesser
46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# General Public License as published by the Free Software Foundation.
47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# This program is distributed in the hope that it will be useful,
49f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# but WITHOUT ANY WARRANTY; without even the implied warranty of
50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# GNU General Public License for more details.
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# You should have received a copy of the GNU General Public License
54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# and the GNU Lesser General Public License along with this program.
55f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# If not, see <http://www.gnu.org/licenses/>.
56f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch###########################################################################
57f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse Getopt::Long;
58f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochGetopt::Long::Configure ("posix_default", "no_ignore_case");
59f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse File::Path qw(mkpath rmtree);
60f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse File::Temp qw(tempdir);
61f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse File::Copy qw(copy move);
62f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse Cwd qw(abs_path cwd realpath);
63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse Storable qw(dclone);
64f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse Data::Dumper;
65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochuse Config;
66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
67f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $TOOL_VERSION = "1.99.8";
68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $ABI_DUMP_VERSION = "3.2";
69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $OLDEST_SUPPORTED_VERSION = "1.18";
70f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $XML_REPORT_VERSION = "1.1";
71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $XML_ABI_DUMP_VERSION = "1.2";
72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $OSgroup = get_OSgroup();
73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $ORIG_DIR = cwd();
74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $TMP_DIR = tempdir(CLEANUP=>1);
75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Internal modules
77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $MODULES_DIR = get_Modules();
78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochpush(@INC, get_dirname($MODULES_DIR));
79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Rules DB
80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy %RULES_PATH = (
81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Binary" => $MODULES_DIR."/RulesBin.xml",
82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Source" => $MODULES_DIR."/RulesSrc.xml");
83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
84f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
85f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
86f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
87f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
88f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch%TargetVersion, $InfoMsg, $UseOldDumps, $CrossGcc, %OutputLogPath,
89f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
90f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
91f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
92f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
93f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
94f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath,
96f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch$CheckInfo, $Quick, $AffectLimit, $AllAffected);
97f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy $CmdName = get_filename($0);
99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy %OS_LibExt = (
100f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "dynamic" => {
101f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "linux"=>"so",
102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "macos"=>"dylib",
103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "windows"=>"dll",
104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "symbian"=>"dso",
105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "default"=>"so"
106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    },
107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "static" => {
108f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "linux"=>"a",
109f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "windows"=>"lib",
110f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "symbian"=>"lib",
111f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        "default"=>"a"
112f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    }
113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch);
114f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
115f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy %OS_Archive = (
116f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "windows"=>"zip",
117f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "default"=>"tar.gz"
118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch);
119f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
120f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochmy %ERROR_CODE = (
121f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Compatible verdict
122f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Compatible"=>0,
123f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Success"=>0,
124f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Incompatible verdict
125f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Incompatible"=>1,
126f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Undifferentiated error code
127f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Error"=>2,
128f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # System command is not found
129f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Not_Found"=>3,
130f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Cannot access input files
131f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Access_Error"=>4,
132f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Cannot compile header files
133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Cannot_Compile"=>5,
134f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Header compiled with errors
135f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Compile_Error"=>6,
136f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Invalid input ABI dump
137f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Invalid_Dump"=>7,
138f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Incompatible version of ABI dump
139f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Dump_Version"=>8,
140f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Cannot find a module
141f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Module_Error"=>9,
142f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Empty intersection between
143f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # headers and shared objects
144f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Empty_Intersection"=>10,
145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    # Empty set of symbols in headers
146f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    "Empty_Set"=>11
147f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch);
14862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
14962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochmy %HomePage = (
15062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
15162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
15262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
15362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch);
15462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
15562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochmy $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
15662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochA tool for checking backward compatibility of a C/C++ library API
15762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochCopyright (C) 2012 ROSA Laboratory
15862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochLicense: GNU LGPL or GNU GPL
15962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
16062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochUsage: $CmdName [options]
16162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochExample: $CmdName -lib NAME -old OLD.xml -new NEW.xml
16262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
163f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochOLD.xml and NEW.xml are XML-descriptors:
164f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
165f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    <version>
166f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        1.0
167f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    </version>
168f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    <headers>
170f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        /path/to/headers/
171f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    </headers>
172f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
173f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    <libs>
174f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        /path/to/libraries/
175f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    </libs>
176
177More info: $CmdName --help\n";
178
179if($#ARGV==-1)
180{
181    printMsg("INFO", $ShortUsage);
182    exit(0);
183}
184
185foreach (2 .. $#ARGV)
186{ # correct comma separated options
187    if($ARGV[$_-1] eq ",")
188    {
189        $ARGV[$_-2].=",".$ARGV[$_];
190        splice(@ARGV, $_-1, 2);
191    }
192    elsif($ARGV[$_-1]=~/,\Z/)
193    {
194        $ARGV[$_-1].=$ARGV[$_];
195        splice(@ARGV, $_, 1);
196    }
197    elsif($ARGV[$_]=~/\A,/
198    and $ARGV[$_] ne ",")
199    {
200        $ARGV[$_-1].=$ARGV[$_];
201        splice(@ARGV, $_, 1);
202    }
203}
204
205GetOptions("h|help!" => \$Help,
206  "i|info!" => \$InfoMsg,
207  "v|version!" => \$ShowVersion,
208  "dumpversion!" => \$DumpVersion,
209# general options
210  "l|lib|library=s" => \$TargetLibraryName,
211  "d1|old|o=s" => \$Descriptor{1}{"Path"},
212  "d2|new|n=s" => \$Descriptor{2}{"Path"},
213  "dump|dump-abi|dump_abi=s" => \$DumpAPI,
214  "old-dumps!" => \$UseOldDumps,
215# extra options
216  "d|descriptor-template!" => \$GenerateTemplate,
217  "app|application=s" => \$AppPath,
218  "static-libs!" => \$UseStaticLibs,
219  "cross-gcc|gcc-path=s" => \$CrossGcc,
220  "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
221  "sysroot=s" => \$SystemRoot_Opt,
222  "v1|version1|vnum=s" => \$TargetVersion{1},
223  "v2|version2=s" => \$TargetVersion{2},
224  "s|strict!" => \$StrictCompat,
225  "symbols-list=s" => \$SymbolsListPath,
226  "skip-symbols=s" => \$SkipSymbolsListPath,
227  "headers-list=s" => \$TargetHeadersPath,
228  "skip-headers=s" => \$SkipHeadersPath,
229  "header=s" => \$TargetHeader,
230  "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
231  "objects-only!" => \$CheckObjectsOnly_Opt,
232  "check-impl|check-implementation!" => \$CheckImpl,
233  "show-retval!" => \$ShowRetVal,
234  "use-dumps!" => \$UseDumps,
235  "nostdinc!" => \$NoStdInc,
236  "dump-system=s" => \$DumpSystem,
237  "sysinfo=s" => \$TargetSysInfo,
238  "cmp-systems!" => \$CmpSystems,
239  "libs-list=s" => \$TargetLibsPath,
240  "ext|extended!" => \$ExtendedCheck,
241  "q|quiet!" => \$Quiet,
242  "stdout!" => \$StdOut,
243  "report-format=s" => \$ReportFormat,
244  "dump-format=s" => \$DumpFormat,
245  "xml!" => \$UseXML,
246  "lang=s" => \$UserLang,
247  "binary|bin|abi!" => \$BinaryOnly,
248  "source|src|api!" => \$SourceOnly,
249  "affected-limit=s" => \$AffectLimit,
250# other options
251  "test!" => \$TestTool,
252  "test-dump!" => \$TestDump,
253  "debug!" => \$Debug,
254  "cpp-compatible!" => \$CppCompat,
255  "p|params=s" => \$ParamNamesPath,
256  "relpath1|relpath=s" => \$RelativeDirectory{1},
257  "relpath2=s" => \$RelativeDirectory{2},
258  "dump-path=s" => \$OutputDumpPath,
259  "sort!" => \$SortDump,
260  "report-path=s" => \$OutputReportPath,
261  "bin-report-path=s" => \$BinaryReportPath,
262  "src-report-path=s" => \$SourceReportPath,
263  "log-path=s" => \$LoggingPath,
264  "log1-path=s" => \$OutputLogPath{1},
265  "log2-path=s" => \$OutputLogPath{2},
266  "logging-mode=s" => \$LogMode,
267  "list-affected!" => \$ListAffected,
268  "l-full|lib-full=s" => \$TargetLibraryFName,
269  "component=s" => \$TargetComponent_Opt,
270  "b|browse=s" => \$Browse,
271  "open!" => \$OpenReport,
272  "extra-info=s" => \$ExtraInfo,
273  "extra-dump!" => \$ExtraDump,
274  "force!" => \$Force,
275  "tolerance=s" => \$Tolerance,
276  "tolerant!" => \$Tolerant,
277  "check!" => \$CheckInfo,
278  "quick!" => \$Quick,
279  "all-affected!" => \$AllAffected
280) or ERR_MESSAGE();
281
282sub ERR_MESSAGE()
283{
284    printMsg("INFO", "\n".$ShortUsage);
285    exit($ERROR_CODE{"Error"});
286}
287
288my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
289my $SLIB_TYPE = $LIB_TYPE;
290if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
291{ # show as "shared" library
292    $SLIB_TYPE = "shared";
293}
294my $LIB_EXT = getLIB_EXT($OSgroup);
295my $AR_EXT = getAR_EXT($OSgroup);
296my $BYTE_SIZE = 8;
297my $COMMON_LOG_PATH = "logs/run.log";
298
299my $HelpMessage="
300NAME:
301  ABI Compliance Checker ($CmdName)
302  Check backward compatibility of a C/C++ library API
303
304DESCRIPTION:
305  ABI Compliance Checker (ACC) is a tool for checking backward binary and
306  source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
307  header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
308  analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
309  and/or source-level compatibility: changes in calling stack, v-table changes,
310  removed symbols, renamed fields, etc. Binary incompatibility may result in
311  crashing or incorrect behavior of applications built with an old version of
312  a library if they run on a new one. Source incompatibility may result in
313  recompilation errors with a new library version.
314
315  The tool is intended for developers of software libraries and maintainers
316  of operating systems who are interested in ensuring backward compatibility,
317  i.e. allow old applications to run or to be recompiled with newer library
318  versions.
319
320  Also the tool can be used by ISVs for checking applications portability to
321  new library versions. Found issues can be taken into account when adapting
322  the application to a new library version.
323
324  This tool is free software: you can redistribute it and/or modify it
325  under the terms of the GNU LGPL or GNU GPL.
326
327USAGE:
328  $CmdName [options]
329
330EXAMPLE:
331  $CmdName -lib NAME -old OLD.xml -new NEW.xml
332
333  OLD.xml and NEW.xml are XML-descriptors:
334
335    <version>
336        1.0
337    </version>
338
339    <headers>
340        /path1/to/header(s)/
341        /path2/to/header(s)/
342         ...
343    </headers>
344
345    <libs>
346        /path1/to/library(ies)/
347        /path2/to/library(ies)/
348         ...
349    </libs>
350
351INFORMATION OPTIONS:
352  -h|-help
353      Print this help.
354
355  -i|-info
356      Print complete info.
357
358  -v|-version
359      Print version information.
360
361  -dumpversion
362      Print the tool version ($TOOL_VERSION) and don't do anything else.
363
364GENERAL OPTIONS:
365  -l|-lib|-library NAME
366      Library name (without version).
367
368  -d1|-old|-o PATH
369      Descriptor of 1st (old) library version.
370      It may be one of the following:
371
372         1. XML-descriptor (VERSION.xml file):
373
374              <version>
375                  1.0
376              </version>
377
378              <headers>
379                  /path1/to/header(s)/
380                  /path2/to/header(s)/
381                   ...
382              </headers>
383
384              <libs>
385                  /path1/to/library(ies)/
386                  /path2/to/library(ies)/
387                   ...
388              </libs>
389
390                 ... (XML-descriptor template
391                         can be generated by -d option)
392
393         2. ABI dump generated by -dump option
394         3. Directory with headers and/or $SLIB_TYPE libraries
395         4. Single header file
396         5. Single $SLIB_TYPE library
397         6. Comma separated list of headers and/or libraries
398
399      If you are using an 2-6 descriptor types then you should
400      specify version numbers with -v1 and -v2 options too.
401
402      For more information, please see:
403        http://ispras.linuxbase.org/index.php/Library_Descriptor
404
405  -d2|-new|-n PATH
406      Descriptor of 2nd (new) library version.
407
408  -dump|-dump-abi PATH
409      Create library ABI dump for the input XML descriptor. You can
410      transfer it anywhere and pass instead of the descriptor. Also
411      it can be used for debugging the tool.
412
413      Supported ABI dump versions: 2.0<=V<=$ABI_DUMP_VERSION
414
415  -old-dumps
416      Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0).\n";
417
418sub HELP_MESSAGE() {
419    printMsg("INFO", $HelpMessage."
420MORE INFO:
421     $CmdName --info\n");
422}
423
424sub INFO_MESSAGE()
425{
426    printMsg("INFO", "$HelpMessage
427EXTRA OPTIONS:
428  -d|-descriptor-template
429      Create XML-descriptor template ./VERSION.xml
430
431  -app|-application PATH
432      This option allows to specify the application that should be checked
433      for portability to the new library version.
434
435  -static-libs
436      Check static libraries instead of the shared ones. The <libs> section
437      of the XML-descriptor should point to static libraries location.
438
439  -cross-gcc|-gcc-path PATH
440      Path to the cross GCC compiler to use instead of the usual (host) GCC.
441
442  -cross-prefix|-gcc-prefix PREFIX
443      GCC toolchain prefix.
444
445  -sysroot DIR
446      Specify the alternative root directory. The tool will search for include
447      paths in the DIR/usr/include and DIR/usr/lib directories.
448
449  -v1|-version1 NUM
450      Specify 1st library version outside the descriptor. This option is needed
451      if you have prefered an alternative descriptor type (see -d1 option).
452
453      In general case you should specify it in the XML-descriptor:
454          <version>
455              VERSION
456          </version>
457
458  -v2|-version2 NUM
459      Specify 2nd library version outside the descriptor.
460
461  -s|-strict
462      Treat all compatibility warnings as problems. Add a number of \"Low\"
463      severity problems to the return value of the tool.
464
465  -headers-only
466      Check header files without $SLIB_TYPE libraries. It is easy to run, but may
467      provide a low quality compatibility report with false positives and
468      without detecting of added/removed symbols.
469
470      Alternatively you can write \"none\" word to the <libs> section
471      in the XML-descriptor:
472          <libs>
473              none
474          </libs>
475
476  -objects-only
477      Check $SLIB_TYPE libraries without header files. It is easy to run, but may
478      provide a low quality compatibility report with false positives and
479      without analysis of changes in parameters and data types.
480
481      Alternatively you can write \"none\" word to the <headers> section
482      in the XML-descriptor:
483          <headers>
484              none
485          </headers>
486
487  -check-impl|-check-implementation
488      Compare canonified disassembled binary code of $SLIB_TYPE libraries to
489      detect changes in the implementation. Add \'Problems with Implementation\'
490      section to the report.
491
492  -show-retval
493      Show the symbol's return type in the report.
494
495  -symbols-list PATH
496      This option allows to specify a file with a list of symbols (mangled
497      names in C++) that should be checked, other symbols will not be checked.
498
499  -skip-symbols PATH
500      The list of symbols that should NOT be checked.
501
502  -headers-list PATH
503      The file with a list of headers, that should be checked/dumped.
504
505  -skip-headers PATH
506      The file with the list of header files, that should not be checked.
507
508  -header NAME
509      Check/Dump ABI of this header only.
510
511  -use-dumps
512      Make dumps for two versions of a library and compare dumps. This should
513      increase the performance of the tool and decrease the system memory usage.
514
515  -nostdinc
516      Do not search in GCC standard system directories for header files.
517
518  -dump-system NAME -sysroot DIR
519      Find all the shared libraries and header files in DIR directory,
520      create XML descriptors and make ABI dumps for each library. The result
521      set of ABI dumps can be compared (--cmp-systems) with the other one
522      created for other version of operating system in order to check them for
523      compatibility. Do not forget to specify -cross-gcc option if your target
524      system requires some specific version of GCC compiler (different from
525      the host GCC). The system ABI dump will be generated to:
526          sys_dumps/NAME/ARCH
527
528  -dump-system DESCRIPTOR.xml
529      The same as the previous option but takes an XML descriptor of the target
530      system as input, where you should describe it:
531
532          /* Primary sections */
533
534          <name>
535              /* Name of the system */
536          </name>
537
538          <headers>
539              /* The list of paths to header files and/or
540                 directories with header files, one per line */
541          </headers>
542
543          <libs>
544              /* The list of paths to shared libraries and/or
545                 directories with shared libraries, one per line */
546          </libs>
547
548          /* Optional sections */
549
550          <search_headers>
551              /* List of directories to be searched
552                 for header files to automatically
553                 generate include paths, one per line */
554          </search_headers>
555
556          <search_libs>
557              /* List of directories to be searched
558                 for shared libraries to resolve
559                 dependencies, one per line */
560          </search_libs>
561
562          <tools>
563              /* List of directories with tools used
564                 for analysis (GCC toolchain), one per line */
565          </tools>
566
567          <cross_prefix>
568              /* GCC toolchain prefix.
569                 Examples:
570                     arm-linux-gnueabi
571                     arm-none-symbianelf */
572          </cross_prefix>
573
574          <gcc_options>
575              /* Additional GCC options, one per line */
576          </gcc_options>
577
578  -sysinfo DIR
579      This option may be used with -dump-system to dump ABI of operating
580      systems and configure the dumping process.
581      Default:
582          modules/Targets/{unix, symbian, windows}
583
584  -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
585      Compare two system ABI dumps. Create compatibility reports for each
586      library and the common HTML report including the summary of test
587      results for all checked libraries. Report will be generated to:
588          sys_compat_reports/NAME1_to_NAME2/ARCH
589
590  -libs-list PATH
591      The file with a list of libraries, that should be dumped by
592      the -dump-system option or should be checked by the -cmp-systems option.
593
594  -ext|-extended
595      If your library A is supposed to be used by other library B and you
596      want to control the ABI of B, then you should enable this option. The
597      tool will check for changes in all data types, even if they are not
598      used by any function in the library A. Such data types are not part
599      of the A library ABI, but may be a part of the ABI of the B library.
600
601      The short scheme is:
602        app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
603
604  -q|-quiet
605      Print all messages to the file instead of stdout and stderr.
606      Default path (can be changed by -log-path option):
607          $COMMON_LOG_PATH
608
609  -stdout
610      Print analysis results (compatibility reports and ABI dumps) to stdout
611      instead of creating a file. This would allow piping data to other programs.
612
613  -report-format FMT
614      Change format of compatibility report.
615      Formats:
616        htm - HTML format (default)
617        xml - XML format
618
619  -dump-format FMT
620      Change format of ABI dump.
621      Formats:
622        perl - Data::Dumper format (default)
623        xml - XML format
624
625  -xml
626      Alias for: --report-format=xml or --dump-format=xml
627
628  -lang LANG
629      Set library language (C or C++). You can use this option if the tool
630      cannot auto-detect a language. This option may be useful for checking
631      C-library headers (--lang=C) in --headers-only or --extended modes.
632
633  -binary|-bin|-abi
634      Show \"Binary\" compatibility problems only.
635      Generate report to:
636        compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
637
638  -source|-src|-api
639      Show \"Source\" compatibility problems only.
640      Generate report to:
641        compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
642
643  -affected-limit LIMIT
644      The maximum number of affected symbols listed under the description
645      of the changed type in the report.
646
647OTHER OPTIONS:
648  -test
649      Run internal tests. Create two binary incompatible versions of a sample
650      library and run the tool to check them for compatibility. This option
651      allows to check if the tool works correctly in the current environment.
652
653  -test-dump
654      Test ability to create, read and compare ABI dumps.
655
656  -debug
657      Debugging mode. Print debug info on the screen. Save intermediate
658      analysis stages in the debug directory:
659          debug/LIB_NAME/VERSION/
660
661      Also consider using --dump option for debugging the tool.
662
663  -cpp-compatible
664      If your header files are written in C language and can be compiled
665      by the G++ compiler (i.e. don't use C++ keywords), then you can tell
666      the tool about this and speedup the analysis.
667
668  -p|-params PATH
669      Path to file with the function parameter names. It can be used
670      for improving report view if the library header files have no
671      parameter names. File format:
672
673            func1;param1;param2;param3 ...
674            func2;param1;param2;param3 ...
675             ...
676
677  -relpath PATH
678      Replace {RELPATH} macros to PATH in the XML-descriptor used
679      for dumping the library ABI (see -dump option).
680
681  -relpath1 PATH
682      Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
683
684  -relpath2 PATH
685      Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
686
687  -dump-path PATH
688      Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
689      Default:
690          abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
691
692  -sort
693      Enable sorting of data in ABI dumps.
694
695  -report-path PATH
696      Path to compatibility report.
697      Default:
698          compat_reports/LIB_NAME/V1_to_V2/compat_report.html
699
700  -bin-report-path PATH
701      Path to \"Binary\" compatibility report.
702      Default:
703          compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
704
705  -src-report-path PATH
706      Path to \"Source\" compatibility report.
707      Default:
708          compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
709
710  -log-path PATH
711      Log path for all messages.
712      Default:
713          logs/LIB_NAME/VERSION/log.txt
714
715  -log1-path PATH
716      Log path for 1st version of a library.
717      Default:
718          logs/LIB_NAME/V1/log.txt
719
720  -log2-path PATH
721      Log path for 2nd version of a library.
722      Default:
723          logs/LIB_NAME/V2/log.txt
724
725  -logging-mode MODE
726      Change logging mode.
727      Modes:
728        w - overwrite old logs (default)
729        a - append old logs
730        n - do not write any logs
731
732  -list-affected
733      Generate file with the list of incompatible
734      symbols beside the HTML compatibility report.
735      Use 'c++filt \@file' command from GNU binutils
736      to unmangle C++ symbols in the generated file.
737      Default names:
738          abi_affected.txt
739          src_affected.txt
740
741  -component NAME
742      The component name in the title and summary of the HTML report.
743      Default:
744          library
745
746  -l-full|-lib-full NAME
747      Change library name in the report title to NAME. By default
748      will be displayed a name specified by -l option.
749
750  -b|-browse PROGRAM
751      Open report(s) in the browser (firefox, opera, etc.).
752
753  -open
754      Open report(s) in the default browser.
755
756  -extra-info DIR
757      Dump extra info to DIR.
758
759  -extra-dump
760      Create extended ABI dump containing all symbols
761      from the translation unit.
762
763  -force
764      Try to use this option if the tool doesn't work.
765
766  -tolerance LEVEL
767      Apply a set of heuristics to successfully compile input
768      header files. You can enable several tolerance levels by
769      joining them into one string (e.g. 13, 124, etc.).
770      Levels:
771          1 - skip non-Linux headers (e.g. win32_*.h, etc.)
772          2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.)
773          3 - skip headers that iclude non-Linux headers
774          4 - skip headers included by others
775
776  -tolerant
777      Enable highest tolerance level [1234].
778
779  -check
780      Check completeness of the ABI dump.
781
782  -quick
783      Quick analysis. Disable check of some template instances.
784
785REPORT:
786    Compatibility report will be generated to:
787        compat_reports/LIB_NAME/V1_to_V2/compat_report.html
788
789    Log will be generated to:
790        logs/LIB_NAME/V1/log.txt
791        logs/LIB_NAME/V2/log.txt
792
793EXIT CODES:
794    0 - Compatible. The tool has run without any errors.
795    non-zero - Incompatible or the tool has run with errors.
796
797REPORT BUGS TO:
798    Andrey Ponomarenko <aponomarenko\@rosalab.ru>
799
800MORE INFORMATION:
801    ".$HomePage{"Wiki"}."
802    ".$HomePage{"Dev1"}."\n");
803}
804
805my $DescriptorTemplate = "
806<?xml version=\"1.0\" encoding=\"utf-8\"?>
807<descriptor>
808
809/* Primary sections */
810
811<version>
812    /* Version of the library */
813</version>
814
815<headers>
816    /* The list of paths to header files and/or
817       directories with header files, one per line */
818</headers>
819
820<libs>
821    /* The list of paths to shared libraries (*.$LIB_EXT) and/or
822       directories with shared libraries, one per line */
823</libs>
824
825/* Optional sections */
826
827<include_paths>
828    /* The list of include paths that will be provided
829       to GCC to compile library headers, one per line.
830       NOTE: If you define this section then the tool
831       will not automatically generate include paths */
832</include_paths>
833
834<add_include_paths>
835    /* The list of include paths that will be added
836       to the automatically generated include paths, one per line */
837</add_include_paths>
838
839<skip_include_paths>
840    /* The list of include paths that will be removed from the
841       list of automatically generated include paths, one per line */
842</skip_include_paths>
843
844<gcc_options>
845    /* Additional GCC options, one per line */
846</gcc_options>
847
848<include_preamble>
849    /* The list of header files that will be
850       included before other headers, one per line  */
851</include_preamble>
852
853<defines>
854    /* The list of defines that will be added at the
855       headers compiling stage, one per line:
856          #define A B
857          #define C D */
858</defines>
859
860<add_namespaces>
861    /* The list of namespaces that should be added to the alanysis
862       if the tool cannot find them automatically, one per line */
863</add_namespaces>
864
865<skip_types>
866    /* The list of data types, that
867       should not be checked, one per line */
868</skip_types>
869
870<skip_symbols>
871    /* The list of functions (mangled/symbol names in C++),
872       that should not be checked, one per line */
873</skip_symbols>
874
875<skip_namespaces>
876    /* The list of C++ namespaces, that
877       should not be checked, one per line */
878</skip_namespaces>
879
880<skip_constants>
881    /* The list of constants that should
882       not be checked, one name per line */
883</skip_constants>
884
885<skip_headers>
886    /* The list of header files and/or directories
887       with header files that should not be checked, one per line */
888</skip_headers>
889
890<skip_libs>
891    /* The list of shared libraries and/or directories
892       with shared libraries that should not be checked, one per line */
893</skip_libs>
894
895<skip_including>
896    /* The list of header files, that cannot be included
897       directly (or non-self compiled ones), one per line */
898</skip_including>
899
900<search_headers>
901    /* List of directories to be searched
902       for header files to automatically
903       generate include paths, one per line. */
904</search_headers>
905
906<search_libs>
907    /* List of directories to be searched
908       for shared librariess to resolve
909       dependencies, one per line */
910</search_libs>
911
912<tools>
913    /* List of directories with tools used
914       for analysis (GCC toolchain), one per line */
915</tools>
916
917<cross_prefix>
918    /* GCC toolchain prefix.
919       Examples:
920           arm-linux-gnueabi
921           arm-none-symbianelf */
922</cross_prefix>
923
924</descriptor>";
925
926my %Operator_Indication = (
927    "not" => "~",
928    "assign" => "=",
929    "andassign" => "&=",
930    "orassign" => "|=",
931    "xorassign" => "^=",
932    "or" => "|",
933    "xor" => "^",
934    "addr" => "&",
935    "and" => "&",
936    "lnot" => "!",
937    "eq" => "==",
938    "ne" => "!=",
939    "lt" => "<",
940    "lshift" => "<<",
941    "lshiftassign" => "<<=",
942    "rshiftassign" => ">>=",
943    "call" => "()",
944    "mod" => "%",
945    "modassign" => "%=",
946    "subs" => "[]",
947    "land" => "&&",
948    "lor" => "||",
949    "rshift" => ">>",
950    "ref" => "->",
951    "le" => "<=",
952    "deref" => "*",
953    "mult" => "*",
954    "preinc" => "++",
955    "delete" => " delete",
956    "vecnew" => " new[]",
957    "vecdelete" => " delete[]",
958    "predec" => "--",
959    "postinc" => "++",
960    "postdec" => "--",
961    "plusassign" => "+=",
962    "plus" => "+",
963    "minus" => "-",
964    "minusassign" => "-=",
965    "gt" => ">",
966    "ge" => ">=",
967    "new" => " new",
968    "multassign" => "*=",
969    "divassign" => "/=",
970    "div" => "/",
971    "neg" => "-",
972    "pos" => "+",
973    "memref" => "->*",
974    "compound" => "," );
975
976my %UnknownOperator;
977
978my %NodeType= (
979  "array_type" => "Array",
980  "binfo" => "Other",
981  "boolean_type" => "Intrinsic",
982  "complex_type" => "Intrinsic",
983  "const_decl" => "Other",
984  "enumeral_type" => "Enum",
985  "field_decl" => "Other",
986  "function_decl" => "Other",
987  "function_type" => "FunctionType",
988  "identifier_node" => "Other",
989  "integer_cst" => "Other",
990  "integer_type" => "Intrinsic",
991  "vector_type" => "Vector",
992  "method_type" => "MethodType",
993  "namespace_decl" => "Other",
994  "parm_decl" => "Other",
995  "pointer_type" => "Pointer",
996  "real_cst" => "Other",
997  "real_type" => "Intrinsic",
998  "record_type" => "Struct",
999  "reference_type" => "Ref",
1000  "string_cst" => "Other",
1001  "template_decl" => "Other",
1002  "template_type_parm" => "TemplateParam",
1003  "typename_type" => "TypeName",
1004  "sizeof_expr" => "SizeOf",
1005  "tree_list" => "Other",
1006  "tree_vec" => "Other",
1007  "type_decl" => "Other",
1008  "union_type" => "Union",
1009  "var_decl" => "Other",
1010  "void_type" => "Intrinsic",
1011  "nop_expr" => "Other", #
1012  "addr_expr" => "Other", #
1013  "offset_type" => "Other" );
1014
1015my %CppKeywords_C = map {$_=>1} (
1016    # C++ 2003 keywords
1017    "public",
1018    "protected",
1019    "private",
1020    "default",
1021    "template",
1022    "new",
1023    #"asm",
1024    "dynamic_cast",
1025    "auto",
1026    "try",
1027    "namespace",
1028    "typename",
1029    "using",
1030    "reinterpret_cast",
1031    "friend",
1032    "class",
1033    "virtual",
1034    "const_cast",
1035    "mutable",
1036    "static_cast",
1037    "export",
1038    # C++0x keywords
1039    "noexcept",
1040    "nullptr",
1041    "constexpr",
1042    "static_assert",
1043    "explicit",
1044    # cannot be used as a macro name
1045    # as it is an operator in C++
1046    "and",
1047    #"and_eq",
1048    "not",
1049    #"not_eq",
1050    "or"
1051    #"or_eq",
1052    #"bitand",
1053    #"bitor",
1054    #"xor",
1055    #"xor_eq",
1056    #"compl"
1057);
1058
1059my %CppKeywords_F = map {$_=>1} (
1060    "delete",
1061    "catch",
1062    "alignof",
1063    "thread_local",
1064    "decltype",
1065    "typeid"
1066);
1067
1068my %CppKeywords_O = map {$_=>1} (
1069    "bool",
1070    "register",
1071    "inline",
1072    "operator"
1073);
1074
1075my %CppKeywords_A = map {$_=>1} (
1076    "this",
1077    "throw",
1078    "template"
1079);
1080
1081foreach (keys(%CppKeywords_C),
1082keys(%CppKeywords_F),
1083keys(%CppKeywords_O)) {
1084    $CppKeywords_A{$_}=1;
1085}
1086
1087# Header file extensions as described by gcc
1088my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1089
1090my %IntrinsicMangling = (
1091    "void" => "v",
1092    "bool" => "b",
1093    "wchar_t" => "w",
1094    "char" => "c",
1095    "signed char" => "a",
1096    "unsigned char" => "h",
1097    "short" => "s",
1098    "unsigned short" => "t",
1099    "int" => "i",
1100    "unsigned int" => "j",
1101    "long" => "l",
1102    "unsigned long" => "m",
1103    "long long" => "x",
1104    "__int64" => "x",
1105    "unsigned long long" => "y",
1106    "__int128" => "n",
1107    "unsigned __int128" => "o",
1108    "float" => "f",
1109    "double" => "d",
1110    "long double" => "e",
1111    "__float80" => "e",
1112    "__float128" => "g",
1113    "..." => "z"
1114);
1115
1116my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling);
1117
1118my %StdcxxMangling = (
1119    "3std"=>"St",
1120    "3std9allocator"=>"Sa",
1121    "3std12basic_string"=>"Sb",
1122    "3std12basic_stringIcE"=>"Ss",
1123    "3std13basic_istreamIcE"=>"Si",
1124    "3std13basic_ostreamIcE"=>"So",
1125    "3std14basic_iostreamIcE"=>"Sd"
1126);
1127
1128my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
1129my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter");
1130
1131my $ADD_TMPL_INSTANCES = 1;
1132my $EMERGENCY_MODE_48 = 0;
1133
1134my %ConstantSuffix = (
1135    "unsigned int"=>"u",
1136    "long"=>"l",
1137    "unsigned long"=>"ul",
1138    "long long"=>"ll",
1139    "unsigned long long"=>"ull"
1140);
1141
1142my %ConstantSuffixR =
1143reverse(%ConstantSuffix);
1144
1145my %OperatorMangling = (
1146    "~" => "co",
1147    "=" => "aS",
1148    "|" => "or",
1149    "^" => "eo",
1150    "&" => "an",#ad (addr)
1151    "==" => "eq",
1152    "!" => "nt",
1153    "!=" => "ne",
1154    "<" => "lt",
1155    "<=" => "le",
1156    "<<" => "ls",
1157    "<<=" => "lS",
1158    ">" => "gt",
1159    ">=" => "ge",
1160    ">>" => "rs",
1161    ">>=" => "rS",
1162    "()" => "cl",
1163    "%" => "rm",
1164    "[]" => "ix",
1165    "&&" => "aa",
1166    "||" => "oo",
1167    "*" => "ml",#de (deref)
1168    "++" => "pp",#
1169    "--" => "mm",#
1170    "new" => "nw",
1171    "delete" => "dl",
1172    "new[]" => "na",
1173    "delete[]" => "da",
1174    "+=" => "pL",
1175    "+" => "pl",#ps (pos)
1176    "-" => "mi",#ng (neg)
1177    "-=" => "mI",
1178    "*=" => "mL",
1179    "/=" => "dV",
1180    "&=" => "aN",
1181    "|=" => "oR",
1182    "%=" => "rM",
1183    "^=" => "eO",
1184    "/" => "dv",
1185    "->*" => "pm",
1186    "->" => "pt",#rf (ref)
1187    "," => "cm",
1188    "?" => "qu",
1189    "." => "dt",
1190    "sizeof"=> "sz"#st
1191);
1192
1193my %Intrinsic_Keywords = map {$_=>1} (
1194    "true",
1195    "false",
1196    "_Bool",
1197    "_Complex",
1198    "const",
1199    "int",
1200    "long",
1201    "void",
1202    "short",
1203    "float",
1204    "volatile",
1205    "restrict",
1206    "unsigned",
1207    "signed",
1208    "char",
1209    "double",
1210    "class",
1211    "struct",
1212    "union",
1213    "enum"
1214);
1215
1216my %GlibcHeader = map {$_=>1} (
1217    "aliases.h",
1218    "argp.h",
1219    "argz.h",
1220    "assert.h",
1221    "cpio.h",
1222    "ctype.h",
1223    "dirent.h",
1224    "envz.h",
1225    "errno.h",
1226    "error.h",
1227    "execinfo.h",
1228    "fcntl.h",
1229    "fstab.h",
1230    "ftw.h",
1231    "glob.h",
1232    "grp.h",
1233    "iconv.h",
1234    "ifaddrs.h",
1235    "inttypes.h",
1236    "langinfo.h",
1237    "limits.h",
1238    "link.h",
1239    "locale.h",
1240    "malloc.h",
1241    "math.h",
1242    "mntent.h",
1243    "monetary.h",
1244    "nl_types.h",
1245    "obstack.h",
1246    "printf.h",
1247    "pwd.h",
1248    "regex.h",
1249    "sched.h",
1250    "search.h",
1251    "setjmp.h",
1252    "shadow.h",
1253    "signal.h",
1254    "spawn.h",
1255    "stdarg.h",
1256    "stdint.h",
1257    "stdio.h",
1258    "stdlib.h",
1259    "string.h",
1260    "strings.h",
1261    "tar.h",
1262    "termios.h",
1263    "time.h",
1264    "ulimit.h",
1265    "unistd.h",
1266    "utime.h",
1267    "wchar.h",
1268    "wctype.h",
1269    "wordexp.h" );
1270
1271my %GlibcDir = map {$_=>1} (
1272    "arpa",
1273    "bits",
1274    "gnu",
1275    "netinet",
1276    "net",
1277    "nfs",
1278    "rpc",
1279    "sys",
1280    "linux" );
1281
1282my %WinHeaders = map {$_=>1} (
1283    "dos.h",
1284    "process.h",
1285    "winsock.h",
1286    "config-win.h",
1287    "mem.h",
1288    "windows.h",
1289    "winsock2.h",
1290    "crtdbg.h",
1291    "ws2tcpip.h"
1292);
1293
1294my %ObsoleteHeaders = map {$_=>1} (
1295    "iostream.h",
1296    "fstream.h"
1297);
1298
1299my %AlienHeaders = map {$_=>1} (
1300 # Solaris
1301    "thread.h",
1302    "sys/atomic.h",
1303 # HPUX
1304    "sys/stream.h",
1305 # Symbian
1306    "AknDoc.h",
1307 # Atari ST
1308    "ext.h",
1309    "tos.h",
1310 # MS-DOS
1311    "alloc.h",
1312 # Sparc
1313    "sys/atomic.h"
1314);
1315
1316my %ConfHeaders = map {$_=>1} (
1317    "atomic",
1318    "conf.h",
1319    "config.h",
1320    "configure.h",
1321    "build.h",
1322    "setup.h"
1323);
1324
1325my %LocalIncludes = map {$_=>1} (
1326    "/usr/local/include",
1327    "/usr/local" );
1328
1329my %OS_AddPath=(
1330# These paths are needed if the tool cannot detect them automatically
1331    "macos"=>{
1332        "include"=>[
1333            "/Library",
1334            "/Developer/usr/include"
1335        ],
1336        "lib"=>[
1337            "/Library",
1338            "/Developer/usr/lib"
1339        ],
1340        "bin"=>[
1341            "/Developer/usr/bin"
1342        ]
1343    },
1344    "beos"=>{
1345    # Haiku has GCC 2.95.3 by default
1346    # try to find GCC>=3.0 in /boot/develop/abi
1347        "include"=>[
1348            "/boot/common",
1349            "/boot/develop"
1350        ],
1351        "lib"=>[
1352            "/boot/common/lib",
1353            "/boot/system/lib",
1354            "/boot/apps"
1355        ],
1356        "bin"=>[
1357            "/boot/common/bin",
1358            "/boot/system/bin",
1359            "/boot/develop/abi"
1360        ]
1361    }
1362);
1363
1364my %Slash_Type=(
1365    "default"=>"/",
1366    "windows"=>"\\"
1367);
1368
1369my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1370
1371# Global Variables
1372my %COMMON_LANGUAGE=(
1373  1 => "C",
1374  2 => "C" );
1375
1376my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1377my $MAX_CPPFILT_FILE_SIZE = 50000;
1378my $CPPFILT_SUPPORT_FILE;
1379
1380my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1381
1382my $STDCXX_TESTING = 0;
1383my $GLIBC_TESTING = 0;
1384my $CPP_HEADERS = 0;
1385
1386my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1387my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
1388
1389my $TargetComponent;
1390
1391my $CheckUndefined = 0;
1392
1393# Set Target Component Name
1394if($TargetComponent_Opt) {
1395    $TargetComponent = lc($TargetComponent_Opt);
1396}
1397else
1398{ # default: library
1399  # other components: header, system, ...
1400    $TargetComponent = "library";
1401}
1402
1403my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1404
1405my $SystemRoot;
1406
1407my $MAIN_CPP_DIR;
1408my %RESULT;
1409my %LOG_PATH;
1410my %DEBUG_PATH;
1411my %Cache;
1412my %LibInfo;
1413my $COMPILE_ERRORS = 0;
1414my %CompilerOptions;
1415my %CheckedDyLib;
1416my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1417
1418# Constants (#defines)
1419my %Constants;
1420my %SkipConstants;
1421my %EnumConstants;
1422
1423# Extra Info
1424my %SymbolHeader;
1425my %KnownLibs;
1426
1427# Templates
1428my %TemplateInstance;
1429my %BasicTemplate;
1430my %TemplateArg;
1431my %TemplateDecl;
1432my %TemplateMap;
1433
1434# Types
1435my %TypeInfo;
1436my %SkipTypes = (
1437  "1"=>{},
1438  "2"=>{} );
1439my %CheckedTypes;
1440my %TName_Tid;
1441my %EnumMembName_Id;
1442my %NestedNameSpaces = (
1443  "1"=>{},
1444  "2"=>{} );
1445my %VirtualTable;
1446my %VirtualTable_Model;
1447my %ClassVTable;
1448my %ClassVTable_Content;
1449my %VTableClass;
1450my %AllocableClass;
1451my %ClassMethods;
1452my %ClassNames;
1453my %Class_SubClasses;
1454my %OverriddenMethods;
1455my %TypedefToAnon;
1456my $MAX_ID = 0;
1457
1458my %CheckedTypeInfo;
1459
1460# Typedefs
1461my %Typedef_BaseName;
1462my %Typedef_Tr;
1463my %Typedef_Eq;
1464my %StdCxxTypedef;
1465my %MissedTypedef;
1466my %MissedBase;
1467my %MissedBase_R;
1468my %TypeTypedef;
1469
1470# Symbols
1471my %SymbolInfo;
1472my %tr_name;
1473my %mangled_name_gcc;
1474my %mangled_name;
1475my %SkipSymbols = (
1476  "1"=>{},
1477  "2"=>{} );
1478my %SkipNameSpaces = (
1479  "1"=>{},
1480  "2"=>{} );
1481my %AddNameSpaces = (
1482  "1"=>{},
1483  "2"=>{} );
1484my %SymbolsList;
1485my %SkipSymbolsList;
1486my %SymbolsList_App;
1487my %CheckedSymbols;
1488my %Symbol_Library = (
1489  "1"=>{},
1490  "2"=>{} );
1491my %Library_Symbol = (
1492  "1"=>{},
1493  "2"=>{} );
1494my %DepSymbol_Library = (
1495  "1"=>{},
1496  "2"=>{} );
1497my %DepLibrary_Symbol = (
1498  "1"=>{},
1499  "2"=>{} );
1500my %MangledNames;
1501my %Func_ShortName;
1502my %AddIntParams;
1503my %Interface_Impl;
1504my %GlobalDataObject;
1505my %WeakSymbols;
1506my %Library_Needed= (
1507  "1"=>{},
1508  "2"=>{} );
1509
1510# Extra Info
1511my %UndefinedSymbols;
1512my %PreprocessedHeaders;
1513
1514# Headers
1515my %Include_Preamble = (
1516    "1"=>[],
1517    "2"=>[] );
1518my %Registered_Headers;
1519my %Registered_Sources;
1520my %HeaderName_Paths;
1521my %Header_Dependency;
1522my %Include_Neighbors;
1523my %Include_Paths = (
1524    "1"=>[],
1525    "2"=>[] );
1526my %INC_PATH_AUTODETECT = (
1527  "1"=>1,
1528  "2"=>1 );
1529my %Add_Include_Paths = (
1530    "1"=>[],
1531    "2"=>[] );
1532my %Skip_Include_Paths;
1533my %RegisteredDirs;
1534my %Header_ErrorRedirect;
1535my %Header_Includes;
1536my %Header_Includes_R;
1537my %Header_ShouldNotBeUsed;
1538my %RecursiveIncludes;
1539my %Header_Include_Prefix;
1540my %SkipHeaders;
1541my %SkipHeadersList=(
1542  "1"=>{},
1543  "2"=>{} );
1544my %SkipLibs;
1545my %Include_Order;
1546my %TUnit_NameSpaces;
1547my %TUnit_Classes;
1548my %TUnit_Funcs;
1549my %TUnit_Vars;
1550
1551my %CppMode = (
1552  "1"=>0,
1553  "2"=>0 );
1554my %AutoPreambleMode = (
1555  "1"=>0,
1556  "2"=>0 );
1557my %MinGWMode = (
1558  "1"=>0,
1559  "2"=>0 );
1560my %Cpp0xMode = (
1561  "1"=>0,
1562  "2"=>0 );
1563
1564# Shared Objects
1565my %RegisteredObjects;
1566my %RegisteredObjects_Short;
1567my %RegisteredSONAMEs;
1568my %RegisteredObject_Dirs;
1569
1570# System Objects
1571my %SystemObjects;
1572my @DefaultLibPaths;
1573my %DyLib_DefaultPath;
1574
1575# System Headers
1576my %SystemHeaders;
1577my @DefaultCppPaths;
1578my @DefaultGccPaths;
1579my @DefaultIncPaths;
1580my %DefaultCppHeader;
1581my %DefaultGccHeader;
1582my @UsersIncPath;
1583
1584# Merging
1585my %CompleteSignature;
1586my $Version;
1587my %AddedInt;
1588my %RemovedInt;
1589my %AddedInt_Virt;
1590my %RemovedInt_Virt;
1591my %VirtualReplacement;
1592my %ChangedTypedef;
1593my %CompatRules;
1594my %IncompleteRules;
1595my %UnknownRules;
1596my %VTableChanged_M;
1597my %ExtendedSymbols;
1598my %ReturnedClass;
1599my %ParamClass;
1600my %SourceAlternative;
1601my %SourceAlternative_B;
1602my %SourceReplacement;
1603my $CurrentSymbol; # for debugging
1604
1605# Calling Conventions
1606my %UseConv_Real = (
1607  1=>{ "R"=>0, "P"=>0 },
1608  2=>{ "R"=>0, "P"=>0 }
1609);
1610
1611# ABI Dump
1612my %UsedDump;
1613
1614# OS Compliance
1615my %TargetLibs;
1616my %TargetHeaders;
1617
1618# OS Specifics
1619my $OStarget = $OSgroup;
1620my %TargetTools;
1621
1622# Compliance Report
1623my %Type_MaxSeverity;
1624
1625# Recursion locks
1626my @RecurLib;
1627my @RecurTypes;
1628my @RecurTypes_Diff;
1629my @RecurInclude;
1630my @RecurConstant;
1631
1632# System
1633my %SystemPaths = (
1634    "include"=>[],
1635    "lib"=>[],
1636    "bin"=>[]
1637);
1638my @DefaultBinPaths;
1639my $GCC_PATH;
1640
1641# Symbols versioning
1642my %SymVer = (
1643  "1"=>{},
1644  "2"=>{} );
1645
1646# Problem descriptions
1647my %CompatProblems;
1648my %CompatProblems_Constants;
1649my %CompatProblems_Impl;
1650my %TotalAffected;
1651
1652# Reports
1653my $ContentID = 1;
1654my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1655my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1656my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1657my $ContentSpanEnd = "</span>\n";
1658my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1659my $ContentDivEnd = "</div>\n";
1660my $Content_Counter = 0;
1661
1662# Modes
1663my $JoinReport = 1;
1664my $DoubleReport = 0;
1665
1666sub get_Modules()
1667{
1668    my $TOOL_DIR = get_dirname($0);
1669    if(not $TOOL_DIR)
1670    { # patch for MS Windows
1671        $TOOL_DIR = ".";
1672    }
1673    my @SEARCH_DIRS = (
1674        # tool's directory
1675        abs_path($TOOL_DIR),
1676        # relative path to modules
1677        abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1678        # install path
1679        'MODULES_INSTALL_PATH'
1680    );
1681    foreach my $DIR (@SEARCH_DIRS)
1682    {
1683        if(not is_abs($DIR))
1684        { # relative path
1685            $DIR = abs_path($TOOL_DIR)."/".$DIR;
1686        }
1687        if(-d $DIR."/modules") {
1688            return $DIR."/modules";
1689        }
1690    }
1691    exitStatus("Module_Error", "can't find modules");
1692}
1693
1694my %LoadedModules = ();
1695
1696sub loadModule($)
1697{
1698    my $Name = $_[0];
1699    if(defined $LoadedModules{$Name}) {
1700        return;
1701    }
1702    my $Path = $MODULES_DIR."/Internals/$Name.pm";
1703    if(not -f $Path) {
1704        exitStatus("Module_Error", "can't access \'$Path\'");
1705    }
1706    require $Path;
1707    $LoadedModules{$Name} = 1;
1708}
1709
1710sub readModule($$)
1711{
1712    my ($Module, $Name) = @_;
1713    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
1714    if(not -f $Path) {
1715        exitStatus("Module_Error", "can't access \'$Path\'");
1716    }
1717    return readFile($Path);
1718}
1719
1720sub showPos($)
1721{
1722    my $Number = $_[0];
1723    if(not $Number) {
1724        $Number = 1;
1725    }
1726    else {
1727        $Number = int($Number)+1;
1728    }
1729    if($Number>3) {
1730        return $Number."th";
1731    }
1732    elsif($Number==1) {
1733        return "1st";
1734    }
1735    elsif($Number==2) {
1736        return "2nd";
1737    }
1738    elsif($Number==3) {
1739        return "3rd";
1740    }
1741    else {
1742        return $Number;
1743    }
1744}
1745
1746sub search_Tools($)
1747{
1748    my $Name = $_[0];
1749    return "" if(not $Name);
1750    if(my @Paths = keys(%TargetTools))
1751    {
1752        foreach my $Path (@Paths)
1753        {
1754            if(-f join_P($Path, $Name)) {
1755                return join_P($Path, $Name);
1756            }
1757            if($CrossPrefix)
1758            { # user-defined prefix (arm-none-symbianelf, ...)
1759                my $Candidate = join_P($Path, $CrossPrefix."-".$Name);
1760                if(-f $Candidate) {
1761                    return $Candidate;
1762                }
1763            }
1764        }
1765    }
1766    else {
1767        return "";
1768    }
1769}
1770
1771sub synch_Cmd($)
1772{
1773    my $Name = $_[0];
1774    if(not $GCC_PATH)
1775    { # GCC was not found yet
1776        return "";
1777    }
1778    my $Candidate = $GCC_PATH;
1779    if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
1780        return $Candidate;
1781    }
1782    return "";
1783}
1784
1785sub get_CmdPath($)
1786{
1787    my $Name = $_[0];
1788    return "" if(not $Name);
1789    if(defined $Cache{"get_CmdPath"}{$Name}) {
1790        return $Cache{"get_CmdPath"}{$Name};
1791    }
1792    my %BinUtils = map {$_=>1} (
1793        "c++filt",
1794        "objdump",
1795        "readelf"
1796    );
1797    if($BinUtils{$Name} and $GCC_PATH)
1798    {
1799        if(my $Dir = get_dirname($GCC_PATH)) {
1800            $TargetTools{$Dir}=1;
1801        }
1802    }
1803    my $Path = search_Tools($Name);
1804    if(not $Path and $OSgroup eq "windows") {
1805        $Path = search_Tools($Name.".exe");
1806    }
1807    if(not $Path and $BinUtils{$Name})
1808    {
1809        if($CrossPrefix)
1810        { # user-defined prefix
1811            $Path = search_Cmd($CrossPrefix."-".$Name);
1812        }
1813    }
1814    if(not $Path and $BinUtils{$Name})
1815    {
1816        if(my $Candidate = synch_Cmd($Name))
1817        { # synch with GCC
1818            if($Candidate=~/[\/\\]/)
1819            { # command path
1820                if(-f $Candidate) {
1821                    $Path = $Candidate;
1822                }
1823            }
1824            elsif($Candidate = search_Cmd($Candidate))
1825            { # command name
1826                $Path = $Candidate;
1827            }
1828        }
1829    }
1830    if(not $Path) {
1831        $Path = search_Cmd($Name);
1832    }
1833    if(not $Path and $OSgroup eq "windows")
1834    { # search for *.exe file
1835        $Path=search_Cmd($Name.".exe");
1836    }
1837    if($Path=~/\s/) {
1838        $Path = "\"".$Path."\"";
1839    }
1840    return ($Cache{"get_CmdPath"}{$Name}=$Path);
1841}
1842
1843sub search_Cmd($)
1844{
1845    my $Name = $_[0];
1846    return "" if(not $Name);
1847    if(defined $Cache{"search_Cmd"}{$Name}) {
1848        return $Cache{"search_Cmd"}{$Name};
1849    }
1850    if(my $DefaultPath = get_CmdPath_Default($Name)) {
1851        return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1852    }
1853    foreach my $Path (@{$SystemPaths{"bin"}})
1854    {
1855        my $CmdPath = join_P($Path,$Name);
1856        if(-f $CmdPath)
1857        {
1858            if($Name=~/gcc/) {
1859                next if(not check_gcc($CmdPath, "3"));
1860            }
1861            return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1862        }
1863    }
1864    return ($Cache{"search_Cmd"}{$Name} = "");
1865}
1866
1867sub get_CmdPath_Default($)
1868{ # search in PATH
1869    return "" if(not $_[0]);
1870    if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1871        return $Cache{"get_CmdPath_Default"}{$_[0]};
1872    }
1873    return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1874}
1875
1876sub get_CmdPath_Default_I($)
1877{ # search in PATH
1878    my $Name = $_[0];
1879    if($Name=~/find/)
1880    { # special case: search for "find" utility
1881        if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
1882            return "find";
1883        }
1884    }
1885    elsif($Name=~/gcc/) {
1886        return check_gcc($Name, "3");
1887    }
1888    if(checkCmd($Name)) {
1889        return $Name;
1890    }
1891    if($OSgroup eq "windows")
1892    {
1893        if(`$Name /? 2>\"$TMP_DIR/null\"`) {
1894            return $Name;
1895        }
1896    }
1897    foreach my $Path (@DefaultBinPaths)
1898    {
1899        if(-f $Path."/".$Name) {
1900            return join_P($Path, $Name);
1901        }
1902    }
1903    return "";
1904}
1905
1906sub classifyPath($)
1907{
1908    my $Path = $_[0];
1909    if($Path=~/[\*\[]/)
1910    { # wildcard
1911        $Path=~s/\*/.*/g;
1912        $Path=~s/\\/\\\\/g;
1913        return ($Path, "Pattern");
1914    }
1915    elsif($Path=~/[\/\\]/)
1916    { # directory or relative path
1917        return (path_format($Path, $OSgroup), "Path");
1918    }
1919    else {
1920        return ($Path, "Name");
1921    }
1922}
1923
1924sub readDescriptor($$)
1925{
1926    my ($LibVersion, $Content) = @_;
1927    return if(not $LibVersion);
1928    my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1929    if(not $Content) {
1930        exitStatus("Error", "$DName is empty");
1931    }
1932    if($Content!~/\</) {
1933        exitStatus("Error", "incorrect descriptor (see -d1 option)");
1934    }
1935    $Content=~s/\/\*(.|\n)+?\*\///g;
1936    $Content=~s/<\!--(.|\n)+?-->//g;
1937
1938    $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1939    if($TargetVersion{$LibVersion}) {
1940        $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1941    }
1942    if(not $Descriptor{$LibVersion}{"Version"}) {
1943        exitStatus("Error", "version in the $DName is not specified (<version> section)");
1944    }
1945    if($Content=~/{RELPATH}/)
1946    {
1947        if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1948            $Content =~ s/{RELPATH}/$RelDir/g;
1949        }
1950        else
1951        {
1952            my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1953            exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1954        }
1955    }
1956
1957    if(not $CheckObjectsOnly_Opt)
1958    {
1959        my $DHeaders = parseTag(\$Content, "headers");
1960        if(not $DHeaders) {
1961            exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1962        }
1963        elsif(lc($DHeaders) ne "none")
1964        { # append the descriptor headers list
1965            if($Descriptor{$LibVersion}{"Headers"})
1966            { # multiple descriptors
1967                $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1968            }
1969            else {
1970                $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1971            }
1972            foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1973            {
1974                if(not -e $Path) {
1975                    exitStatus("Access_Error", "can't access \'$Path\'");
1976                }
1977            }
1978        }
1979    }
1980    if(not $CheckHeadersOnly_Opt)
1981    {
1982        my $DObjects = parseTag(\$Content, "libs");
1983        if(not $DObjects) {
1984            exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1985        }
1986        elsif(lc($DObjects) ne "none")
1987        { # append the descriptor libraries list
1988            if($Descriptor{$LibVersion}{"Libs"})
1989            { # multiple descriptors
1990                $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1991            }
1992            else {
1993                $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1994            }
1995            foreach my $Path (split(/\s*\n\s*/, $DObjects))
1996            {
1997                if(not -e $Path) {
1998                    exitStatus("Access_Error", "can't access \'$Path\'");
1999                }
2000            }
2001        }
2002    }
2003    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
2004    {
2005        if(not -d $Path) {
2006            exitStatus("Access_Error", "can't access directory \'$Path\'");
2007        }
2008        $Path = get_abs_path($Path);
2009        $Path = path_format($Path, $OSgroup);
2010        push_U($SystemPaths{"include"}, $Path);
2011    }
2012    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
2013    {
2014        if(not -d $Path) {
2015            exitStatus("Access_Error", "can't access directory \'$Path\'");
2016        }
2017        $Path = get_abs_path($Path);
2018        $Path = path_format($Path, $OSgroup);
2019        push_U($SystemPaths{"lib"}, $Path);
2020    }
2021    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
2022    {
2023        if(not -d $Path) {
2024            exitStatus("Access_Error", "can't access directory \'$Path\'");
2025        }
2026        $Path = get_abs_path($Path);
2027        $Path = path_format($Path, $OSgroup);
2028        push_U($SystemPaths{"bin"}, $Path);
2029        $TargetTools{$Path}=1;
2030    }
2031    if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
2032        $CrossPrefix = $Prefix;
2033    }
2034    $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //=
2035    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
2036    {
2037        if(not -d $Path) {
2038            exitStatus("Access_Error", "can't access directory \'$Path\'");
2039        }
2040        $Path = get_abs_path($Path);
2041        $Path = path_format($Path, $OSgroup);
2042        push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
2043    }
2044    $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"});
2045    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
2046    {
2047        if(not -d $Path) {
2048            exitStatus("Access_Error", "can't access directory \'$Path\'");
2049        }
2050        $Path = get_abs_path($Path);
2051        $Path = path_format($Path, $OSgroup);
2052        push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
2053    }
2054    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
2055    { # skip some auto-generated include paths
2056        if(not is_abs($Path))
2057        {
2058            if(my $P = abs_path($Path)) {
2059                $Path = $P;
2060            }
2061        }
2062        $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
2063    }
2064    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
2065    { # skip direct including of some headers
2066        my ($CPath, $Type) = classifyPath($Path);
2067        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
2068    }
2069    $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
2070    foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"}))
2071    {
2072        if($Option!~/\A\-(Wl|l|L)/)
2073        { # skip linker options
2074            $CompilerOptions{$LibVersion} .= " ".$Option;
2075        }
2076    }
2077    $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
2078    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
2079    {
2080        $SkipHeadersList{$LibVersion}{$Path} = 1;
2081        my ($CPath, $Type) = classifyPath($Path);
2082        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
2083    }
2084    $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
2085    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
2086    {
2087        my ($CPath, $Type) = classifyPath($Path);
2088        $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
2089    }
2090    if(my $DDefines = parseTag(\$Content, "defines"))
2091    {
2092        if($Descriptor{$LibVersion}{"Defines"})
2093        { # multiple descriptors
2094            $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
2095        }
2096        else {
2097            $Descriptor{$LibVersion}{"Defines"} = $DDefines;
2098        }
2099    }
2100    foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
2101    {
2102        if($Order=~/\A(.+):(.+)\Z/) {
2103            $Include_Order{$LibVersion}{$1} = $2;
2104        }
2105    }
2106    foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
2107    split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
2108    { # opaque_types renamed to skip_types (1.23.4)
2109        $SkipTypes{$LibVersion}{$Type_Name} = 1;
2110    }
2111    foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
2112    split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
2113    { # skip_interfaces renamed to skip_symbols (1.22.1)
2114        $SkipSymbols{$LibVersion}{$Symbol} = 1;
2115    }
2116    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
2117        $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
2118    }
2119    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
2120        $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2121    }
2122    foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2123        $SkipConstants{$LibVersion}{$Constant} = 1;
2124    }
2125    if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2126    {
2127        if($Descriptor{$LibVersion}{"IncludePreamble"})
2128        { # multiple descriptors
2129            $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2130        }
2131        else {
2132            $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2133        }
2134    }
2135}
2136
2137sub parseTag(@)
2138{
2139    my $CodeRef = shift(@_);
2140    my $Tag = shift(@_);
2141    if(not $Tag or not $CodeRef) {
2142        return undef;
2143    }
2144    my $Sp = 0;
2145    if(@_) {
2146        $Sp = shift(@_);
2147    }
2148    my $Start = index(${$CodeRef}, "<$Tag>");
2149    if($Start!=-1)
2150    {
2151        my $End = index(${$CodeRef}, "</$Tag>");
2152        if($End!=-1)
2153        {
2154            my $TS = length($Tag)+3;
2155            my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2156            substr($Content, 0, $TS-1, ""); # cut start tag
2157            substr($Content, -$TS, $TS, ""); # cut end tag
2158            if(not $Sp)
2159            {
2160                $Content=~s/\A\s+//g;
2161                $Content=~s/\s+\Z//g;
2162            }
2163            if(substr($Content, 0, 1) ne "<") {
2164                $Content = xmlSpecChars_R($Content);
2165            }
2166            return $Content;
2167        }
2168    }
2169    return undef;
2170}
2171
2172sub getInfo($)
2173{
2174    my $DumpPath = $_[0];
2175    return if(not $DumpPath or not -f $DumpPath);
2176
2177    readTUDump($DumpPath);
2178
2179    # processing info
2180    setTemplateParams_All();
2181
2182    if($ExtraDump) {
2183        setAnonTypedef_All();
2184    }
2185
2186    getTypeInfo_All();
2187    simplifyNames();
2188    simplifyConstants();
2189    getVarInfo_All();
2190    getSymbolInfo_All();
2191
2192    # clean memory
2193    %LibInfo = ();
2194    %TemplateInstance = ();
2195    %BasicTemplate = ();
2196    %MangledNames = ();
2197    %TemplateDecl = ();
2198    %StdCxxTypedef = ();
2199    %MissedTypedef = ();
2200    %Typedef_Tr = ();
2201    %Typedef_Eq = ();
2202    %TypedefToAnon = ();
2203
2204    # clean cache
2205    delete($Cache{"getTypeAttr"});
2206    delete($Cache{"getTypeDeclId"});
2207
2208    if($ExtraDump)
2209    {
2210        remove_Unused($Version, "Extra");
2211    }
2212    else
2213    { # remove unused types
2214        if($BinaryOnly and not $ExtendedCheck)
2215        { # --binary
2216            remove_Unused($Version, "All");
2217        }
2218        else {
2219            remove_Unused($Version, "Extended");
2220        }
2221    }
2222
2223    if($CheckInfo)
2224    {
2225        foreach my $Tid (keys(%{$TypeInfo{$Version}})) {
2226            check_Completeness($TypeInfo{$Version}{$Tid}, $Version);
2227        }
2228
2229        foreach my $Sid (keys(%{$SymbolInfo{$Version}})) {
2230            check_Completeness($SymbolInfo{$Version}{$Sid}, $Version);
2231        }
2232    }
2233
2234    if($Debug) {
2235        # debugMangling($Version);
2236    }
2237}
2238
2239sub readTUDump($)
2240{
2241    my $DumpPath = $_[0];
2242
2243    open(TU_DUMP, $DumpPath);
2244    local $/ = undef;
2245    my $Content = <TU_DUMP>;
2246    close(TU_DUMP);
2247
2248    unlink($DumpPath);
2249
2250    $Content=~s/\n[ ]+/ /g;
2251    my @Lines = split("\n", $Content);
2252
2253    # clean memory
2254    undef $Content;
2255
2256    $MAX_ID = $#Lines+1; # number of lines == number of nodes
2257
2258    foreach (0 .. $#Lines)
2259    {
2260        if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
2261        { # get a number and attributes of a node
2262            next if(not $NodeType{$2});
2263            $LibInfo{$Version}{"info_type"}{$1}=$2;
2264            $LibInfo{$Version}{"info"}{$1}=$3;
2265        }
2266
2267        # clean memory
2268        delete($Lines[$_]);
2269    }
2270
2271    # clean memory
2272    undef @Lines;
2273}
2274
2275sub simplifyConstants()
2276{
2277    foreach my $Constant (keys(%{$Constants{$Version}}))
2278    {
2279        if(defined $Constants{$Version}{$Constant}{"Header"})
2280        {
2281            my $Value = $Constants{$Version}{$Constant}{"Value"};
2282            if(defined $EnumConstants{$Version}{$Value}) {
2283                $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"};
2284            }
2285        }
2286    }
2287}
2288
2289sub simplifyNames()
2290{
2291    foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2292    {
2293        if($Typedef_Eq{$Version}{$Base}) {
2294            next;
2295        }
2296        my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2297        if($#Translations==0)
2298        {
2299            if(length($Translations[0])<=length($Base)) {
2300                $Typedef_Eq{$Version}{$Base} = $Translations[0];
2301            }
2302        }
2303        else
2304        { # select most appropriate
2305            foreach my $Tr (@Translations)
2306            {
2307                if($Base=~/\A\Q$Tr\E/)
2308                {
2309                    $Typedef_Eq{$Version}{$Base} = $Tr;
2310                    last;
2311                }
2312            }
2313        }
2314    }
2315    foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
2316    {
2317        my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
2318        if(not $TypeName) {
2319            next;
2320        }
2321        next if(index($TypeName,"<")==-1);# template instances only
2322        if($TypeName=~/>(::\w+)+\Z/)
2323        { # skip unused types
2324            next;
2325        }
2326        foreach my $Base (sort {length($b)<=>length($a)}
2327        sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
2328        {
2329            next if(not $Base);
2330            next if(index($TypeName,$Base)==-1);
2331            next if(length($TypeName) - length($Base) <= 3);
2332            if(my $Typedef = $Typedef_Eq{$Version}{$Base})
2333            {
2334                $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2335                $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2336                if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
2337                {
2338                    foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2339                    {
2340                        if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2341                        {
2342                            $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2343                            $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
2344                            $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
2345                        }
2346                    }
2347                }
2348            }
2349        }
2350        $TypeName = formatName($TypeName, "T");
2351        $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2352        $TName_Tid{$Version}{$TypeName} = $TypeId;
2353    }
2354}
2355
2356sub setAnonTypedef_All()
2357{
2358    foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}}))
2359    {
2360        if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl")
2361        {
2362            if(isAnon(getNameByInfo($InfoId))) {
2363                $TypedefToAnon{getTypeId($InfoId)} = 1;
2364            }
2365        }
2366    }
2367}
2368
2369sub setTemplateParams_All()
2370{
2371    foreach (keys(%{$LibInfo{$Version}{"info"}}))
2372    {
2373        if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2374            setTemplateParams($_);
2375        }
2376    }
2377}
2378
2379sub setTemplateParams($)
2380{
2381    my $Tid = getTypeId($_[0]);
2382    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2383    {
2384        if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
2385        {
2386            my $TmplInst_Id = $2;
2387            setTemplateInstParams($_[0], $TmplInst_Id);
2388            while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2389                setTemplateInstParams($_[0], $TmplInst_Id);
2390            }
2391        }
2392
2393        $BasicTemplate{$Version}{$Tid} = $_[0];
2394
2395        if(my $Prms = getTreeAttr_Prms($_[0]))
2396        {
2397            if(my $Valu = getTreeAttr_Valu($Prms))
2398            {
2399                my $Vector = getTreeVec($Valu);
2400                foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector}))
2401                {
2402                    if(my $Val = getTreeAttr_Valu($Vector->{$Pos}))
2403                    {
2404                        if(my $Name = getNameByInfo($Val))
2405                        {
2406                            $TemplateArg{$Version}{$_[0]}{$Pos} = $Name;
2407                            if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") {
2408                                $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val;
2409                            }
2410                            else {
2411                                $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val);
2412                            }
2413                        }
2414                    }
2415                }
2416            }
2417        }
2418    }
2419    if(my $TypeId = getTreeAttr_Type($_[0]))
2420    {
2421        if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2422        {
2423            if($IType eq "record_type") {
2424                $TemplateDecl{$Version}{$TypeId} = 1;
2425            }
2426        }
2427    }
2428}
2429
2430sub setTemplateInstParams($$)
2431{
2432    my ($Tmpl, $Inst) = @_;
2433
2434    if(my $Info = $LibInfo{$Version}{"info"}{$Inst})
2435    {
2436        my ($Params_InfoId, $ElemId) = ();
2437        if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2438            $Params_InfoId = $1;
2439        }
2440        if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2441            $ElemId = $1;
2442        }
2443        if($Params_InfoId and $ElemId)
2444        {
2445            my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2446            while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2447            {
2448                my ($PPos, $PTypeId) = ($1, $2);
2449                if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2450                {
2451                    if($PType eq "template_type_parm") {
2452                        $TemplateDecl{$Version}{$ElemId} = 1;
2453                    }
2454                }
2455                if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2456                { # functions
2457                    $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
2458                    $BasicTemplate{$Version}{$ElemId} = $Tmpl;
2459                }
2460                else
2461                { # types
2462                    $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
2463                    $BasicTemplate{$Version}{$ElemId} = $Tmpl;
2464                }
2465            }
2466        }
2467    }
2468}
2469
2470sub getTypeDeclId($)
2471{
2472    if($_[0])
2473    {
2474        if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2475            return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2476        }
2477        if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2478        {
2479            if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2480                return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2481            }
2482        }
2483    }
2484    return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
2485}
2486
2487sub getTypeInfo_All()
2488{
2489    if(not check_gcc($GCC_PATH, "4.5"))
2490    { # support for GCC < 4.5
2491      # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2492      # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2493      # FIXME: check GCC versions
2494        addMissedTypes_Pre();
2495    }
2496
2497    foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2498    { # forward order only
2499        my $IType = $LibInfo{$Version}{"info_type"}{$_};
2500        if($IType=~/_type\Z/ and $IType ne "function_type"
2501        and $IType ne "method_type") {
2502            getTypeInfo("$_");
2503        }
2504    }
2505
2506    # add "..." type
2507    $TypeInfo{$Version}{"-1"} = {
2508        "Name" => "...",
2509        "Type" => "Intrinsic",
2510        "Tid" => "-1"
2511    };
2512    $TName_Tid{$Version}{"..."} = "-1";
2513
2514    if(not check_gcc($GCC_PATH, "4.5"))
2515    { # support for GCC < 4.5
2516        addMissedTypes_Post();
2517    }
2518
2519    if($ADD_TMPL_INSTANCES)
2520    {
2521        # templates
2522        foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}}))
2523        {
2524            if(defined $TemplateMap{$Version}{$Tid}
2525            and not defined $TypeInfo{$Version}{$Tid}{"Template"})
2526            {
2527                if(defined $TypeInfo{$Version}{$Tid}{"Memb"})
2528                {
2529                    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}}))
2530                    {
2531                        if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"})
2532                        {
2533                            if(my %MAttr = getTypeAttr($MembTypeId))
2534                            {
2535                                $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"};
2536                                $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version);
2537                            }
2538                        }
2539                    }
2540                }
2541                if(defined $TypeInfo{$Version}{$Tid}{"Base"})
2542                {
2543                    foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}}))
2544                    {
2545                        my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version);
2546
2547                        if($NBid ne $Bid)
2548                        {
2549                            %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}};
2550                            delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid});
2551                        }
2552                    }
2553                }
2554            }
2555        }
2556    }
2557}
2558
2559sub createType($$)
2560{
2561    my ($Attr, $LibVersion) = @_;
2562    my $NewId = ++$MAX_ID;
2563
2564    $Attr->{"Tid"} = $NewId;
2565    $TypeInfo{$Version}{$NewId} = $Attr;
2566    $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId;
2567
2568    return "$NewId";
2569}
2570
2571sub instType($$$)
2572{ # create template instances
2573    my ($Map, $Tid, $LibVersion) = @_;
2574
2575    if(not $TypeInfo{$LibVersion}{$Tid}) {
2576        return undef;
2577    }
2578    my $Attr = dclone($TypeInfo{$LibVersion}{$Tid});
2579
2580    foreach my $Key (sort keys(%{$Map}))
2581    {
2582        if(my $Val = $Map->{$Key})
2583        {
2584            $Attr->{"Name"}=~s/\b$Key\b/$Val/g;
2585
2586            if(defined $Attr->{"NameSpace"}) {
2587                $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g;
2588            }
2589            foreach (keys(%{$Attr->{"TParam"}})) {
2590                $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g;
2591            }
2592        }
2593        else
2594        { # remove absent
2595          # _Traits, etc.
2596            $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g;
2597            if(defined $Attr->{"NameSpace"}) {
2598                $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g;
2599            }
2600            foreach (keys(%{$Attr->{"TParam"}}))
2601            {
2602                if($Attr->{"TParam"}{$_}{"name"} eq $Key) {
2603                    delete($Attr->{"TParam"}{$_});
2604                }
2605                else {
2606                    $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g;
2607                }
2608            }
2609        }
2610    }
2611
2612    my $Tmpl = 0;
2613
2614    if(defined $Attr->{"TParam"})
2615    {
2616        foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}}))
2617        {
2618            my $PName = $Attr->{"TParam"}{$_}{"name"};
2619
2620            if(my $PTid = $TName_Tid{$LibVersion}{$PName})
2621            {
2622                my %Base = get_BaseType($PTid, $LibVersion);
2623
2624                if($Base{"Type"} eq "TemplateParam"
2625                or defined $Base{"Template"})
2626                {
2627                    $Tmpl = 1;
2628                    last
2629                }
2630            }
2631        }
2632    }
2633
2634    if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) {
2635        return "$Id";
2636    }
2637    else
2638    {
2639        if(not $Tmpl) {
2640            delete($Attr->{"Template"});
2641        }
2642
2643        my $New = createType($Attr, $LibVersion);
2644
2645        my %EMap = ();
2646        if(defined $TemplateMap{$LibVersion}{$Tid}) {
2647            %EMap = %{$TemplateMap{$LibVersion}{$Tid}};
2648        }
2649        foreach (keys(%{$Map})) {
2650            $EMap{$_} = $Map->{$_};
2651        }
2652
2653        if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) {
2654            $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion);
2655        }
2656        if(defined $TypeInfo{$LibVersion}{$New}{"Base"})
2657        {
2658            foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}}))
2659            {
2660                my $NBid = instType(\%EMap, $Bid, $LibVersion);
2661
2662                if($NBid ne $Bid)
2663                {
2664                    %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}};
2665                    delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid});
2666                }
2667            }
2668        }
2669
2670        if(defined $TypeInfo{$LibVersion}{$New}{"Memb"})
2671        {
2672            foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}}))
2673            {
2674                if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) {
2675                    $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion);
2676                }
2677            }
2678        }
2679
2680        if(defined $TypeInfo{$LibVersion}{$New}{"Param"})
2681        {
2682            foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) {
2683                $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion);
2684            }
2685        }
2686
2687        if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) {
2688            $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion);
2689        }
2690
2691        return $New;
2692    }
2693}
2694
2695sub addMissedTypes_Pre()
2696{
2697    my %MissedTypes = ();
2698    foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2699    { # detecting missed typedefs
2700        if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2701        {
2702            my $TypeId = getTreeAttr_Type($MissedTDid);
2703            next if(not $TypeId);
2704            my $TypeType = getTypeType($TypeId);
2705            if($TypeType eq "Unknown")
2706            { # template_type_parm
2707                next;
2708            }
2709            my $TypeDeclId = getTypeDeclId($TypeId);
2710            next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2711            my $TypedefName = getNameByInfo($MissedTDid);
2712            next if(not $TypedefName);
2713            next if($TypedefName eq "__float80");
2714            next if(isAnon($TypedefName));
2715            if(not $TypeDeclId
2716            or getNameByInfo($TypeDeclId) ne $TypedefName) {
2717                $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
2718            }
2719        }
2720    }
2721    my %AddTypes = ();
2722    foreach my $Tid (keys(%{$MissedTypes{$Version}}))
2723    { # add missed typedefs
2724        my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
2725        if(not @Missed or $#Missed>=1) {
2726            next;
2727        }
2728        my $MissedTDid = $Missed[0];
2729        my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
2730        if(not $TypedefName) {
2731            next;
2732        }
2733        my $NewId = ++$MAX_ID;
2734        my %MissedInfo = ( # typedef info
2735            "Name" => $TypedefName,
2736            "NameSpace" => $TypedefNS,
2737            "BaseType" => $Tid,
2738            "Type" => "Typedef",
2739            "Tid" => "$NewId" );
2740        my ($H, $L) = getLocation($MissedTDid);
2741        $MissedInfo{"Header"} = $H;
2742        $MissedInfo{"Line"} = $L;
2743        if($TypedefName=~/\*|\&|\s/)
2744        { # other types
2745            next;
2746        }
2747        if($TypedefName=~/>(::\w+)+\Z/)
2748        { # QFlags<Qt::DropAction>::enum_type
2749            next;
2750        }
2751        if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2752        { # double-check for the name of typedef
2753            my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
2754            next if(not $TName);
2755            if(length($TypedefName)>=length($TName))
2756            { # too long typedef
2757                next;
2758            }
2759            if($TName=~/\A\Q$TypedefName\E</) {
2760                next;
2761            }
2762            if($TypedefName=~/\A\Q$TName\E/)
2763            { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
2764                next;
2765            }
2766            if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
2767            { # std::_Vector_base and std::vector::_Base
2768                next;
2769            }
2770        }
2771
2772        $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2773
2774        # register typedef
2775        $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
2776        $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
2777        $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
2778    }
2779
2780    # add missed & remove other
2781    $TypeInfo{$Version} = \%AddTypes;
2782    delete($Cache{"getTypeAttr"}{$Version});
2783}
2784
2785sub addMissedTypes_Post()
2786{
2787    foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2788    {
2789        if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2790        {
2791            $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2792            if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2793                $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2794            }
2795        }
2796    }
2797}
2798
2799sub getTypeInfo($)
2800{
2801    my $TypeId = $_[0];
2802    %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2803    my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
2804    if(not $TName) {
2805        delete($TypeInfo{$Version}{$TypeId});
2806    }
2807}
2808
2809sub getArraySize($$)
2810{
2811    my ($TypeId, $BaseName) = @_;
2812    if(my $Size = getSize($TypeId))
2813    {
2814        my $Elems = $Size/$BYTE_SIZE;
2815        while($BaseName=~s/\s*\[(\d+)\]//) {
2816            $Elems/=$1;
2817        }
2818        if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2819        {
2820            if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2821                $Elems/=$BasicSize;
2822            }
2823        }
2824        return $Elems;
2825    }
2826    return 0;
2827}
2828
2829sub getTParams($$)
2830{
2831    my ($TypeId, $Kind) = @_;
2832    my @TmplParams = ();
2833    my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2834    foreach my $Pos (@Positions)
2835    {
2836        my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2837        my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2838        if(not $NodeType)
2839        { # typename_type
2840            return ();
2841        }
2842        if($NodeType eq "tree_vec")
2843        {
2844            if($Pos!=$#Positions)
2845            { # select last vector of parameters ( ns<P1>::type<P2> )
2846                next;
2847            }
2848        }
2849        my @Params = get_TemplateParam($Pos, $Param_TypeId);
2850        foreach my $P (@Params)
2851        {
2852            if($P eq "") {
2853                return ();
2854            }
2855            elsif($P ne "\@skip\@") {
2856                @TmplParams = (@TmplParams, $P);
2857            }
2858        }
2859    }
2860    return @TmplParams;
2861}
2862
2863sub getTypeAttr($)
2864{
2865    my $TypeId = $_[0];
2866    my %TypeAttr = ();
2867    if(defined $TypeInfo{$Version}{$TypeId}
2868    and $TypeInfo{$Version}{$TypeId}{"Name"})
2869    { # already created
2870        return %{$TypeInfo{$Version}{$TypeId}};
2871    }
2872    elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2873    { # incomplete type
2874        return ();
2875    }
2876    $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2877
2878    my $TypeDeclId = getTypeDeclId($TypeId);
2879    $TypeAttr{"Tid"} = $TypeId;
2880
2881    if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2882    {
2883        if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2884        {
2885            if($Info=~/qual[ ]*:/)
2886            {
2887                my $NewId = ++$MAX_ID;
2888
2889                $MissedBase{$Version}{$TypeId} = "$NewId";
2890                $MissedBase_R{$Version}{$NewId} = $TypeId;
2891                $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId};
2892                $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId};
2893            }
2894        }
2895        $TypeAttr{"Type"} = "Typedef";
2896    }
2897    else {
2898        $TypeAttr{"Type"} = getTypeType($TypeId);
2899    }
2900
2901    if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId))
2902    {
2903        if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl")
2904        { # local code
2905            return ();
2906        }
2907    }
2908
2909    if($TypeAttr{"Type"} eq "Unknown") {
2910        return ();
2911    }
2912    elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2913    {
2914        %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
2915        if(my $TName = $TypeAttr{"Name"})
2916        {
2917            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2918            $TName_Tid{$Version}{$TName} = $TypeId;
2919            return %TypeAttr;
2920        }
2921        else {
2922            return ();
2923        }
2924    }
2925    elsif($TypeAttr{"Type"} eq "Array")
2926    {
2927        my ($BTid, $BTSpec) = selectBaseType($TypeId);
2928        if(not $BTid) {
2929            return ();
2930        }
2931        if(my $Algn = getAlgn($TypeId)) {
2932            $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2933        }
2934        $TypeAttr{"BaseType"} = $BTid;
2935        if(my %BTAttr = getTypeAttr($BTid))
2936        {
2937            if(not $BTAttr{"Name"}) {
2938                return ();
2939            }
2940            if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
2941            {
2942                if(my $Size = getSize($TypeId)) {
2943                    $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2944                }
2945                if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
2946                    $TypeAttr{"Name"} = $1."[$NElems]".$2;
2947                }
2948                else {
2949                    $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
2950                }
2951            }
2952            else
2953            {
2954                $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
2955                if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
2956                    $TypeAttr{"Name"} = $1."[]".$2;
2957                }
2958                else {
2959                    $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
2960                }
2961            }
2962            $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
2963            if($BTAttr{"Header"})  {
2964                $TypeAttr{"Header"} = $BTAttr{"Header"};
2965            }
2966            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2967            $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2968            return %TypeAttr;
2969        }
2970        return ();
2971    }
2972    elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/)
2973    {
2974        %TypeAttr = getTrivialTypeAttr($TypeId);
2975        if($TypeAttr{"Name"})
2976        {
2977            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2978
2979            if(not defined $IntrinsicNames{$TypeAttr{"Name"}}
2980            or getTypeDeclId($TypeAttr{"Tid"}))
2981            { # NOTE: register only one int: with built-in decl
2982                if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2983                    $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2984                }
2985            }
2986            return %TypeAttr;
2987        }
2988        else {
2989            return ();
2990        }
2991    }
2992    elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/)
2993    {
2994        %TypeAttr = getTrivialTypeAttr($TypeId);
2995        if($TypeAttr{"Name"})
2996        {
2997            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2998            if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2999                $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
3000            }
3001            return %TypeAttr;
3002        }
3003        else {
3004            return ();
3005        }
3006    }
3007    elsif($TypeAttr{"Type"} eq "SizeOf")
3008    {
3009        $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId);
3010        my %BTAttr = getTypeAttr($TypeAttr{"BaseType"});
3011        $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")";
3012        if($TypeAttr{"Name"})
3013        {
3014            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
3015            return %TypeAttr;
3016        }
3017        else {
3018            return ();
3019        }
3020    }
3021    else
3022    { # derived types
3023        my ($BTid, $BTSpec) = selectBaseType($TypeId);
3024        if(not $BTid) {
3025            return ();
3026        }
3027        $TypeAttr{"BaseType"} = $BTid;
3028        if(defined $MissedTypedef{$Version}{$BTid})
3029        {
3030            if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
3031            {
3032                if($MissedTDid ne $TypeDeclId) {
3033                    $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
3034                }
3035            }
3036        }
3037        my %BTAttr = getTypeAttr($TypeAttr{"BaseType"});
3038        if(not $BTAttr{"Name"})
3039        { # templates
3040            return ();
3041        }
3042        if($BTAttr{"Type"} eq "Typedef")
3043        { # relinking typedefs
3044            my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version);
3045            if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
3046                $TypeAttr{"BaseType"} = $BaseBase{"Tid"};
3047            }
3048        }
3049        if($BTSpec)
3050        {
3051            if($TypeAttr{"Type"} eq "Pointer"
3052            and $BTAttr{"Name"}=~/\([\*]+\)/)
3053            {
3054                $TypeAttr{"Name"} = $BTAttr{"Name"};
3055                $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
3056            }
3057            else {
3058                $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
3059            }
3060        }
3061        else {
3062            $TypeAttr{"Name"} = $BTAttr{"Name"};
3063        }
3064        if($TypeAttr{"Type"} eq "Typedef")
3065        {
3066            $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
3067
3068            if(index($TypeAttr{"Name"}, "tmp_add_type")==0) {
3069                return ();
3070            }
3071
3072            if(isAnon($TypeAttr{"Name"}))
3073            { # anon typedef to anon type: ._N
3074                return ();
3075            }
3076
3077            if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i)
3078            { # artificial typedef of "struct X" to "X"
3079                $TypeAttr{"Artificial"} = 1;
3080            }
3081
3082            if(my $NS = getNameSpace($TypeDeclId))
3083            {
3084                my $TypeName = $TypeAttr{"Name"};
3085                if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
3086                { # "some_type" is the typedef to "struct some_type" in C++
3087                    if($3) {
3088                        $TypeAttr{"Name"} = $3."::".$TypeName;
3089                    }
3090                }
3091                else
3092                {
3093                    $TypeAttr{"NameSpace"} = $NS;
3094                    $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3095
3096                    if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
3097                    and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
3098                    {
3099                        if($BTAttr{"NameSpace"}
3100                        and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
3101                        { # types like "std::fpos<__mbstate_t>" are
3102                          # not covered by typedefs in the TU dump
3103                          # so trying to add such typedefs manually
3104                            $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
3105                            if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
3106                            {
3107                                if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
3108                                { # skip "other" in "std" and "type" in "boost"
3109                                    $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
3110                                }
3111                            }
3112                        }
3113                    }
3114                }
3115            }
3116            if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"}
3117            and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
3118            {
3119                if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
3120                { # typedef int*const TYPEDEF; // first
3121                  # int foo(TYPEDEF p); // const is optimized out
3122                    $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
3123                    if($BTAttr{"Name"}=~/</)
3124                    {
3125                        if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
3126                            $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
3127                        }
3128                    }
3129                }
3130            }
3131            ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
3132        }
3133        if(not $TypeAttr{"Size"})
3134        {
3135            if($TypeAttr{"Type"} eq "Pointer") {
3136                $TypeAttr{"Size"} = $WORD_SIZE{$Version};
3137            }
3138            elsif($BTAttr{"Size"}) {
3139                $TypeAttr{"Size"} = $BTAttr{"Size"};
3140            }
3141        }
3142        if(my $Algn = getAlgn($TypeId)) {
3143            $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3144        }
3145        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
3146        if(not $TypeAttr{"Header"} and $BTAttr{"Header"})  {
3147            $TypeAttr{"Header"} = $BTAttr{"Header"};
3148        }
3149        %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
3150        if($TypeAttr{"Name"} ne $BTAttr{"Name"})
3151        { # typedef to "class Class"
3152          # should not be registered in TName_Tid
3153            if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
3154                $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
3155            }
3156        }
3157        return %TypeAttr;
3158    }
3159}
3160
3161sub getTreeVec($)
3162{
3163    my %Vector = ();
3164    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3165    {
3166        while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
3167        { # string length is N-1 because of the null terminator
3168            $Vector{$1} = $2;
3169        }
3170    }
3171    return \%Vector;
3172}
3173
3174sub get_TemplateParam($$)
3175{
3176    my ($Pos, $Type_Id) = @_;
3177    return () if(not $Type_Id);
3178    my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
3179    return () if(not $NodeType);
3180    if($NodeType eq "integer_cst")
3181    { # int (1), unsigned (2u), char ('c' as 99), ...
3182        my $CstTid = getTreeAttr_Type($Type_Id);
3183        my %CstType = getTypeAttr($CstTid); # without recursion
3184        my $Num = getNodeIntCst($Type_Id);
3185        if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
3186            return ($Num.$CstSuffix);
3187        }
3188        else {
3189            return ("(".$CstType{"Name"}.")".$Num);
3190        }
3191    }
3192    elsif($NodeType eq "string_cst") {
3193        return (getNodeStrCst($Type_Id));
3194    }
3195    elsif($NodeType eq "tree_vec")
3196    {
3197        my $Vector = getTreeVec($Type_Id);
3198        my @Params = ();
3199        foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
3200        {
3201            foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
3202                push(@Params, $P2);
3203            }
3204        }
3205        return @Params;
3206    }
3207    elsif($NodeType eq "parm_decl")
3208    {
3209        (getNameByInfo($Type_Id));
3210    }
3211    else
3212    {
3213        my %ParamAttr = getTypeAttr($Type_Id);
3214        my $PName = $ParamAttr{"Name"};
3215        if(not $PName) {
3216            return ();
3217        }
3218        if($PName=~/\>/)
3219        {
3220            if(my $Cover = cover_stdcxx_typedef($PName)) {
3221                $PName = $Cover;
3222            }
3223        }
3224        if($Pos>=1 and
3225        $PName=~/\A$DEFAULT_STD_PARMS\</)
3226        { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
3227          # template<typename _Key, typename _Compare = std::less<_Key>
3228          # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
3229          # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
3230          # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
3231          # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
3232            return ("\@skip\@");
3233        }
3234        return ($PName);
3235    }
3236}
3237
3238sub cover_stdcxx_typedef($)
3239{
3240    my $TypeName = $_[0];
3241    if(my @Covers = sort {length($a)<=>length($b)}
3242    sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
3243    { # take the shortest typedef
3244      # FIXME: there may be more than
3245      # one typedefs to the same type
3246        return $Covers[0];
3247    }
3248    my $Covered = $TypeName;
3249    while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
3250    if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
3251    {
3252        if(my $Cover = $Covers[0])
3253        {
3254            $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
3255            $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
3256        }
3257    }
3258    return formatName($Covered, "T");
3259}
3260
3261sub getNodeIntCst($)
3262{
3263    my $CstId = $_[0];
3264    my $CstTypeId = getTreeAttr_Type($CstId);
3265    if($EnumMembName_Id{$Version}{$CstId}) {
3266        return $EnumMembName_Id{$Version}{$CstId};
3267    }
3268    elsif((my $Value = getTreeValue($CstId)) ne "")
3269    {
3270        if($Value eq "0")
3271        {
3272            if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
3273                return "false";
3274            }
3275            else {
3276                return "0";
3277            }
3278        }
3279        elsif($Value eq "1")
3280        {
3281            if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
3282                return "true";
3283            }
3284            else {
3285                return "1";
3286            }
3287        }
3288        else {
3289            return $Value;
3290        }
3291    }
3292    return "";
3293}
3294
3295sub getNodeStrCst($)
3296{
3297    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3298    {
3299        if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
3300        {
3301            if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
3302            { # string length is N-1 because of the null terminator
3303                return substr($1, 0, $2-1);
3304            }
3305            else
3306            { # identifier_node
3307                return substr($1, 0, $2);
3308            }
3309        }
3310    }
3311    return "";
3312}
3313
3314sub getMemPtrAttr($$$)
3315{ # function, method and field pointers
3316    my ($PtrId, $TypeId, $Type) = @_;
3317    my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
3318    if($Type eq "FieldPtr") {
3319        $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
3320    }
3321    my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
3322    my $MemPtrName = "";
3323    my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
3324    if($Type eq "MethodPtr")
3325    { # size of "method pointer" may be greater than WORD size
3326        if(my $Size = getSize($TypeId))
3327        {
3328            $Size/=$BYTE_SIZE;
3329            $TypeAttr{"Size"} = "$Size";
3330        }
3331    }
3332    if(my $Algn = getAlgn($TypeId)) {
3333        $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3334    }
3335    # Return
3336    if($Type eq "FieldPtr")
3337    {
3338        my %ReturnAttr = getTypeAttr($PtrId);
3339        if($ReturnAttr{"Name"}) {
3340            $MemPtrName .= $ReturnAttr{"Name"};
3341        }
3342        $TypeAttr{"Return"} = $PtrId;
3343    }
3344    else
3345    {
3346        if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3347        {
3348            my $ReturnTypeId = $1;
3349            my %ReturnAttr = getTypeAttr($ReturnTypeId);
3350            if(not $ReturnAttr{"Name"})
3351            { # templates
3352                return ();
3353            }
3354            $MemPtrName .= $ReturnAttr{"Name"};
3355            $TypeAttr{"Return"} = $ReturnTypeId;
3356        }
3357    }
3358    # Class
3359    if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3360    {
3361        $TypeAttr{"Class"} = $2;
3362        my %Class = getTypeAttr($TypeAttr{"Class"});
3363        if($Class{"Name"}) {
3364            $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3365        }
3366        else {
3367            $MemPtrName .= " (*)";
3368        }
3369    }
3370    else {
3371        $MemPtrName .= " (*)";
3372    }
3373    # Parameters
3374    if($Type eq "FuncPtr"
3375    or $Type eq "MethodPtr")
3376    {
3377        my @ParamTypeName = ();
3378        if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3379        {
3380            my $PTypeInfoId = $1;
3381            my ($Pos, $PPos) = (0, 0);
3382            while($PTypeInfoId)
3383            {
3384                my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3385                if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
3386                {
3387                    my $PTypeId = $1;
3388                    my %ParamAttr = getTypeAttr($PTypeId);
3389                    if(not $ParamAttr{"Name"})
3390                    { # templates (template_type_parm), etc.
3391                        return ();
3392                    }
3393                    if($ParamAttr{"Name"} eq "void") {
3394                        last;
3395                    }
3396                    if($Pos!=0 or $Type ne "MethodPtr")
3397                    {
3398                        $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
3399                        push(@ParamTypeName, $ParamAttr{"Name"});
3400                    }
3401                    if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3402                        $Pos+=1;
3403                    }
3404                    else {
3405                        last;
3406                    }
3407                }
3408                else {
3409                    last;
3410                }
3411            }
3412        }
3413        $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3414    }
3415    $TypeAttr{"Name"} = formatName($MemPtrName, "T");
3416    return %TypeAttr;
3417}
3418
3419sub getTreeTypeName($)
3420{
3421    my $TypeId = $_[0];
3422    if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3423    {
3424        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
3425        {
3426            if(my $Name = getNameByInfo($TypeId))
3427            { # bit_size_type
3428                return $Name;
3429            }
3430            elsif($Info=~/unsigned/) {
3431                return "unsigned int";
3432            }
3433            else {
3434                return "int";
3435            }
3436        }
3437        elsif($Info=~/name[ ]*:[ ]*@(\d+) /) {
3438            return getNameByInfo($1);
3439        }
3440    }
3441    return "";
3442}
3443
3444sub isFuncPtr($)
3445{
3446    my $Ptd = pointTo($_[0]);
3447    return 0 if(not $Ptd);
3448    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3449    {
3450        if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3451            return 0;
3452        }
3453    }
3454    if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3455    and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
3456    {
3457        if($InfoT1 eq "pointer_type"
3458        and $InfoT2 eq "function_type") {
3459            return 1;
3460        }
3461    }
3462    return 0;
3463}
3464
3465sub isMethodPtr($)
3466{
3467    my $Ptd = pointTo($_[0]);
3468    return 0 if(not $Ptd);
3469    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3470    {
3471        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3472        and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3473        and $Info=~/ ptrmem /) {
3474            return 1;
3475        }
3476    }
3477    return 0;
3478}
3479
3480sub isFieldPtr($)
3481{
3482    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3483    {
3484        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3485        and $Info=~/ ptrmem /) {
3486            return 1;
3487        }
3488    }
3489    return 0;
3490}
3491
3492sub pointTo($)
3493{
3494    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3495    {
3496        if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3497            return $1;
3498        }
3499    }
3500    return "";
3501}
3502
3503sub getTypeTypeByTypeId($)
3504{
3505    my $TypeId = $_[0];
3506    if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3507    {
3508        my $NType = $NodeType{$TType};
3509        if($NType eq "Intrinsic") {
3510            return $NType;
3511        }
3512        elsif(isFuncPtr($TypeId)) {
3513            return "FuncPtr";
3514        }
3515        elsif(isMethodPtr($TypeId)) {
3516            return "MethodPtr";
3517        }
3518        elsif(isFieldPtr($TypeId)) {
3519            return "FieldPtr";
3520        }
3521        elsif($NType ne "Other") {
3522            return $NType;
3523        }
3524    }
3525    return "Unknown";
3526}
3527
3528my %UnQual = (
3529    "r"=>"restrict",
3530    "v"=>"volatile",
3531    "c"=>"const",
3532    "cv"=>"const volatile"
3533);
3534
3535sub getQual($)
3536{
3537    my $TypeId = $_[0];
3538    if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3539    {
3540        my ($Qual, $To) = ();
3541        if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3542            $Qual = $UnQual{$1};
3543        }
3544        if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3545            $To = $1;
3546        }
3547        if($Qual and $To) {
3548            return ($Qual, $To);
3549        }
3550    }
3551    return ();
3552}
3553
3554sub getQualType($)
3555{
3556    if($_[0] eq "const volatile") {
3557        return "ConstVolatile";
3558    }
3559    return ucfirst($_[0]);
3560}
3561
3562sub getTypeType($)
3563{
3564    my $TypeId = $_[0];
3565    my $TypeDeclId = getTypeDeclId($TypeId);
3566    if(defined $MissedTypedef{$Version}{$TypeId})
3567    { # support for old GCC versions
3568        if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3569            return "Typedef";
3570        }
3571    }
3572    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3573    my ($Qual, $To) = getQual($TypeId);
3574    if(($Qual or $To) and $TypeDeclId
3575    and (getTypeId($TypeDeclId) ne $TypeId))
3576    { # qualified types (special)
3577        return getQualType($Qual);
3578    }
3579    elsif(not $MissedBase_R{$Version}{$TypeId}
3580    and isTypedef($TypeId)) {
3581        return "Typedef";
3582    }
3583    elsif($Qual)
3584    { # qualified types
3585        return getQualType($Qual);
3586    }
3587
3588    if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3589    { # typedef struct { ... } name
3590        $TypeTypedef{$Version}{$TypeId} = $1;
3591    }
3592
3593    my $TypeType = getTypeTypeByTypeId($TypeId);
3594    if($TypeType eq "Struct")
3595    {
3596        if($TypeDeclId
3597        and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3598            return "Template";
3599        }
3600    }
3601    return $TypeType;
3602}
3603
3604sub isTypedef($)
3605{
3606    if($_[0])
3607    {
3608        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type")
3609        { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16)));
3610            return 0;
3611        }
3612        if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3613        {
3614            if(my $TDid = getTypeDeclId($_[0]))
3615            {
3616                if(getTypeId($TDid) eq $_[0]
3617                and getNameByInfo($TDid))
3618                {
3619                    if($Info=~/unql[ ]*:[ ]*\@(\d+) /) {
3620                        return $1;
3621                    }
3622                }
3623            }
3624        }
3625    }
3626    return 0;
3627}
3628
3629sub selectBaseType($)
3630{
3631    my $TypeId = $_[0];
3632    if(defined $MissedTypedef{$Version}{$TypeId})
3633    { # add missed typedefs
3634        if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3635            return ($TypeId, "");
3636        }
3637    }
3638    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3639    my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
3640
3641    my $MB_R = $MissedBase_R{$Version}{$TypeId};
3642    my $MB = $MissedBase{$Version}{$TypeId};
3643
3644    my ($Qual, $To) = getQual($TypeId);
3645    if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
3646    and (getTypeId($1) ne $TypeId)
3647    and (not $MB_R or getTypeId($1) ne $MB_R))
3648    { # qualified types (special)
3649        return (getTypeId($1), $Qual);
3650    }
3651    elsif($MB)
3652    { # add base
3653        return ($MB, "");
3654    }
3655    elsif(not $MB_R and my $Bid = isTypedef($TypeId))
3656    { # typedefs
3657        return ($Bid, "");
3658    }
3659    elsif($Qual or $To)
3660    { # qualified types
3661        return ($To, $Qual);
3662    }
3663    elsif($InfoType eq "reference_type")
3664    {
3665        if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
3666            return ($1, "&");
3667        }
3668    }
3669    elsif($InfoType eq "array_type")
3670    {
3671        if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
3672            return ($1, "");
3673        }
3674    }
3675    elsif($InfoType eq "pointer_type")
3676    {
3677        if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
3678            return ($1, "*");
3679        }
3680    }
3681
3682    return (0, "");
3683}
3684
3685sub getSymbolInfo_All()
3686{
3687    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3688    { # reverse order
3689        if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
3690            getSymbolInfo($_);
3691        }
3692    }
3693
3694    if($ADD_TMPL_INSTANCES)
3695    {
3696        # templates
3697        foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}}))
3698        {
3699            my %Map = ();
3700
3701            if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"})
3702            {
3703                if(defined $TemplateMap{$Version}{$ClassId})
3704                {
3705                    foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) {
3706                        $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_};
3707                    }
3708                }
3709            }
3710
3711            if(defined $TemplateMap{$Version}{$Sid})
3712            {
3713                foreach (keys(%{$TemplateMap{$Version}{$Sid}})) {
3714                    $Map{$_} = $TemplateMap{$Version}{$Sid}{$_};
3715                }
3716            }
3717
3718            if(defined $SymbolInfo{$Version}{$Sid}{"Param"})
3719            {
3720                foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}}))
3721                {
3722                    my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"};
3723                    $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version);
3724                }
3725            }
3726            if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) {
3727                $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version);
3728            }
3729        }
3730    }
3731}
3732
3733sub getVarInfo_All()
3734{
3735    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3736    { # reverse order
3737        if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
3738            getVarInfo($_);
3739        }
3740    }
3741}
3742
3743sub isBuiltIn($) {
3744    return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
3745}
3746
3747sub getVarInfo($)
3748{
3749    my $InfoId = $_[0];
3750    if(my $NSid = getTreeAttr_Scpe($InfoId))
3751    {
3752        my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3753        if($NSInfoType and $NSInfoType eq "function_decl") {
3754            return;
3755        }
3756    }
3757    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3758    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3759    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3760        delete($SymbolInfo{$Version}{$InfoId});
3761        return;
3762    }
3763    my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
3764    if(not $ShortName) {
3765        delete($SymbolInfo{$Version}{$InfoId});
3766        return;
3767    }
3768    if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3769        delete($SymbolInfo{$Version}{$InfoId});
3770        return;
3771    }
3772    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
3773    if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3774    {
3775        if($OSgroup eq "windows")
3776        { # cut the offset
3777            $MnglName=~s/\@\d+\Z//g;
3778        }
3779        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3780    }
3781    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3782    and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
3783    { # validate mangled name
3784        delete($SymbolInfo{$Version}{$InfoId});
3785        return;
3786    }
3787    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3788    and index($ShortName, "_Z")==0)
3789    { # _ZTS, etc.
3790        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3791    }
3792    if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3793    { # non-public global data
3794        delete($SymbolInfo{$Version}{$InfoId});
3795        return;
3796    }
3797    $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
3798    if(my $Rid = getTypeId($InfoId))
3799    {
3800        if(not defined $TypeInfo{$Version}{$Rid}
3801        or not $TypeInfo{$Version}{$Rid}{"Name"})
3802        {
3803            delete($SymbolInfo{$Version}{$InfoId});
3804            return;
3805        }
3806        $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3807        my $Val = getDataVal($InfoId, $Rid);
3808        if(defined $Val) {
3809            $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3810        }
3811    }
3812    set_Class_And_Namespace($InfoId);
3813    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3814    {
3815        if(not defined $TypeInfo{$Version}{$ClassId}
3816        or not $TypeInfo{$Version}{$ClassId}{"Name"})
3817        {
3818            delete($SymbolInfo{$Version}{$InfoId});
3819            return;
3820        }
3821    }
3822    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3823    { # extern "C"
3824        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3825        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3826    }
3827    if($UserLang and $UserLang eq "C")
3828    { # --lang=C option
3829        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3830    }
3831    if(not $CheckHeadersOnly)
3832    {
3833        if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3834        {
3835            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3836            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3837            {
3838                if(link_symbol($ShortName, $Version, "-Deps"))
3839                { # "const" global data is mangled as _ZL... in the TU dump
3840                  # but not mangled when compiling a C shared library
3841                    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3842                }
3843            }
3844        }
3845    }
3846    if($COMMON_LANGUAGE{$Version} eq "C++")
3847    {
3848        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3849        { # for some symbols (_ZTI) the short name is the mangled name
3850            if(index($ShortName, "_Z")==0) {
3851                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3852            }
3853        }
3854        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3855        { # try to mangle symbol (link with libraries)
3856            $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3857        }
3858        if($OStarget eq "windows")
3859        {
3860            if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3861            { # link MS C++ symbols from library with GCC symbols from headers
3862                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3863            }
3864        }
3865    }
3866    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3867        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3868    }
3869    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3870    {
3871        if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3872        { # non-target symbols
3873            delete($SymbolInfo{$Version}{$InfoId});
3874            return;
3875        }
3876    }
3877    if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3878    {
3879        if(defined $MissedTypedef{$Version}{$Rid})
3880        {
3881            if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3882                $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3883            }
3884        }
3885    }
3886    setFuncAccess($InfoId);
3887    if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
3888        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3889    }
3890    if($ShortName=~/\A(_Z|\?)/) {
3891        delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3892    }
3893
3894    if($ExtraDump) {
3895        $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId);
3896    }
3897}
3898
3899sub isConstType($$)
3900{
3901    my ($TypeId, $LibVersion) = @_;
3902    my %Base = get_Type($TypeId, $LibVersion);
3903    while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
3904        %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
3905    }
3906    return ($Base{"Type"} eq "Const");
3907}
3908
3909sub getTrivialName($$)
3910{
3911    my ($TypeInfoId, $TypeId) = @_;
3912    my %TypeAttr = ();
3913    $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3914    if(not $TypeAttr{"Name"}) {
3915        $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3916    }
3917    ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3918    $TypeAttr{"Type"} = getTypeType($TypeId);
3919    $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
3920    if(isAnon($TypeAttr{"Name"}))
3921    {
3922        my $NameSpaceId = $TypeId;
3923        while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
3924        { # searching for a first not anon scope
3925            if($NSId eq $NameSpaceId) {
3926                last;
3927            }
3928            else
3929            {
3930                $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3931                if(not $TypeAttr{"NameSpace"}
3932                or not isAnon($TypeAttr{"NameSpace"})) {
3933                    last;
3934                }
3935            }
3936            $NameSpaceId = $NSId;
3937        }
3938    }
3939    else
3940    {
3941        if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
3942        {
3943            if($NameSpaceId ne $TypeId) {
3944                $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3945            }
3946        }
3947    }
3948    if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) {
3949        $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3950    }
3951    $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
3952    if(isAnon($TypeAttr{"Name"}))
3953    { # anon-struct-header.h-line
3954        $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
3955        $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
3956        if($TypeAttr{"NameSpace"}) {
3957            $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3958        }
3959    }
3960    if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3961    and getTypeDeclId($TypeId) eq $TypeInfoId)
3962    {
3963        my @TParams = getTParams($TypeId, "Type");
3964        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
3965    }
3966    return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3967}
3968
3969sub getTrivialTypeAttr($)
3970{
3971    my $TypeId = $_[0];
3972    my $TypeInfoId = getTypeDeclId($_[0]);
3973
3974    my %TypeAttr = ();
3975
3976    if($TemplateDecl{$Version}{$TypeId})
3977    { # template_decl
3978        $TypeAttr{"Template"} = 1;
3979    }
3980
3981    setTypeAccess($TypeId, \%TypeAttr);
3982    ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3983    if(isBuiltIn($TypeAttr{"Header"}))
3984    {
3985        delete($TypeAttr{"Header"});
3986        delete($TypeAttr{"Line"});
3987    }
3988    $TypeAttr{"Type"} = getTypeType($TypeId);
3989    ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3990    if(not $TypeAttr{"Name"}) {
3991        return ();
3992    }
3993    if(not $TypeAttr{"NameSpace"}) {
3994        delete($TypeAttr{"NameSpace"});
3995    }
3996
3997    my $Tmpl = undef;
3998
3999    if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
4000    {
4001        $Tmpl = $BasicTemplate{$Version}{$TypeId};
4002
4003        if(my @TParams = getTParams($TypeId, "Type"))
4004        {
4005            foreach my $Pos (0 .. $#TParams)
4006            {
4007                my $Val = $TParams[$Pos];
4008                $TypeAttr{"TParam"}{$Pos}{"name"} = $Val;
4009
4010                if(not defined $TypeAttr{"Template"})
4011                {
4012                    my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version);
4013
4014                    if($Base{"Type"} eq "TemplateParam"
4015                    or defined $Base{"Template"}) {
4016                        $TypeAttr{"Template"} = 1;
4017                    }
4018                }
4019
4020                if($Tmpl)
4021                {
4022                    if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos})
4023                    {
4024                        $TemplateMap{$Version}{$TypeId}{$Arg} = $Val;
4025
4026                        if($Val eq $Arg) {
4027                            $TypeAttr{"Template"} = 1;
4028                        }
4029                    }
4030                }
4031            }
4032
4033            if($Tmpl)
4034            {
4035                foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}}))
4036                {
4037                    if($Pos>$#TParams)
4038                    {
4039                        my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos};
4040                        $TemplateMap{$Version}{$TypeId}{$Arg} = "";
4041                    }
4042                }
4043            }
4044        }
4045
4046        if($ADD_TMPL_INSTANCES)
4047        {
4048            if($Tmpl)
4049            {
4050                if(my $MainInst = getTreeAttr_Type($Tmpl))
4051                {
4052                    if(not getTreeAttr_Flds($TypeId))
4053                    {
4054                        if(my $Flds = getTreeAttr_Flds($MainInst)) {
4055                            $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds ";
4056                        }
4057                    }
4058                    if(not getTreeAttr_Binf($TypeId))
4059                    {
4060                        if(my $Binf = getTreeAttr_Binf($MainInst)) {
4061                            $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf ";
4062                        }
4063                    }
4064                }
4065            }
4066        }
4067    }
4068
4069    my $StaticFields = setTypeMemb($TypeId, \%TypeAttr);
4070
4071    if(my $Size = getSize($TypeId))
4072    {
4073        $Size = $Size/$BYTE_SIZE;
4074        $TypeAttr{"Size"} = "$Size";
4075    }
4076    else
4077    {
4078        if($ExtraDump)
4079        {
4080            if(not defined $TypeAttr{"Memb"}
4081            and not $Tmpl)
4082            { # declaration only
4083                $TypeAttr{"Forward"} = 1;
4084            }
4085        }
4086    }
4087
4088    if($TypeAttr{"Type"} eq "Struct"
4089    and ($StaticFields or detect_lang($TypeId)))
4090    {
4091        $TypeAttr{"Type"} = "Class";
4092        $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
4093    }
4094    if($TypeAttr{"Type"} eq "Struct"
4095    or $TypeAttr{"Type"} eq "Class")
4096    {
4097        my $Skip = setBaseClasses($TypeId, \%TypeAttr);
4098        if($Skip) {
4099            return ();
4100        }
4101    }
4102    if(my $Algn = getAlgn($TypeId)) {
4103        $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
4104    }
4105    setSpec($TypeId, \%TypeAttr);
4106
4107    if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/)
4108    {
4109        if(not $TypedefToAnon{$TypeId}
4110        and not defined $TemplateInstance{$Version}{"Type"}{$TypeId})
4111        {
4112            if(not isAnon($TypeAttr{"Name"})) {
4113                $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"};
4114            }
4115        }
4116    }
4117
4118    $TypeAttr{"Tid"} = $TypeId;
4119    if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
4120    {
4121        my @Entries = split(/\n/, $VTable);
4122        foreach (1 .. $#Entries)
4123        {
4124            my $Entry = $Entries[$_];
4125            if($Entry=~/\A(\d+)\s+(.+)\Z/) {
4126                $TypeAttr{"VTable"}{$1} = simplifyVTable($2);
4127            }
4128        }
4129    }
4130
4131    if($TypeAttr{"Type"} eq "Enum")
4132    {
4133        if(not $TypeAttr{"NameSpace"})
4134        {
4135            foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
4136            {
4137                my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
4138                my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"};
4139                $EnumConstants{$Version}{$MName} = {
4140                    "Value"=>$MVal,
4141                    "Header"=>$TypeAttr{"Header"}
4142                };
4143                if(isAnon($TypeAttr{"Name"}))
4144                {
4145                    if($ExtraDump
4146                    or is_target_header($TypeAttr{"Header"}, $Version))
4147                    {
4148                        %{$Constants{$Version}{$MName}} = (
4149                            "Value" => $MVal,
4150                            "Header" => $TypeAttr{"Header"}
4151                        );
4152                    }
4153                }
4154            }
4155        }
4156    }
4157    if($ExtraDump)
4158    {
4159        if(defined $TypedefToAnon{$TypeId}) {
4160            $TypeAttr{"AnonTypedef"} = 1;
4161        }
4162    }
4163
4164    return %TypeAttr;
4165}
4166
4167sub simplifyVTable($)
4168{
4169    my $Content = $_[0];
4170    if($Content=~s/ \[with (.+)]//)
4171    { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
4172        if(my @Elems = separate_Params($1, 0, 0))
4173        {
4174            foreach my $Elem (@Elems)
4175            {
4176                if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/)
4177                {
4178                    my ($Arg, $Val) = ($1, $2);
4179
4180                    if(defined $DEFAULT_STD_ARGS{$Arg}) {
4181                        $Content=~s/,\s*$Arg\b//g;
4182                    }
4183                    else {
4184                        $Content=~s/\b$Arg\b/$Val/g;
4185                    }
4186                }
4187            }
4188        }
4189    }
4190
4191    return $Content;
4192}
4193
4194sub detect_lang($)
4195{
4196    my $TypeId = $_[0];
4197    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
4198    if(check_gcc($GCC_PATH, "4"))
4199    { # GCC 4 fncs-node points to only non-artificial methods
4200        return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
4201    }
4202    else
4203    { # GCC 3
4204        my $Fncs = getTreeAttr_Fncs($TypeId);
4205        while($Fncs)
4206        {
4207            if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
4208                return 1;
4209            }
4210            $Fncs = getTreeAttr_Chan($Fncs);
4211        }
4212    }
4213    return 0;
4214}
4215
4216sub setSpec($$)
4217{
4218    my ($TypeId, $TypeAttr) = @_;
4219    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
4220    if($Info=~/\s+spec\s+/) {
4221        $TypeAttr->{"Spec"} = 1;
4222    }
4223}
4224
4225sub setBaseClasses($$)
4226{
4227    my ($TypeId, $TypeAttr) = @_;
4228    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
4229    if(my $Binf = getTreeAttr_Binf($TypeId))
4230    {
4231        my $Info = $LibInfo{$Version}{"info"}{$Binf};
4232        my $Pos = 0;
4233        while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
4234        {
4235            my ($Access, $BInfoId) = ($1, $2);
4236            my $ClassId = getBinfClassId($BInfoId);
4237            my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
4238            if(not $CType or $CType eq "template_type_parm"
4239            or $CType eq "typename_type")
4240            { # skip
4241                # return 1;
4242            }
4243            my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
4244            if($Access=~/prot/) {
4245                $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
4246            }
4247            elsif($Access=~/priv/) {
4248                $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
4249            }
4250            $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
4251            if($BaseInfo=~/virt/)
4252            { # virtual base
4253                $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
4254            }
4255            $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
4256            $Pos += 1;
4257        }
4258    }
4259    return 0;
4260}
4261
4262sub getBinfClassId($)
4263{
4264    my $Info = $LibInfo{$Version}{"info"}{$_[0]};
4265    $Info=~/type[ ]*:[ ]*@(\d+) /;
4266    return $1;
4267}
4268
4269sub unmangledFormat($$)
4270{
4271    my ($Name, $LibVersion) = @_;
4272    $Name = uncover_typedefs($Name, $LibVersion);
4273    while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
4274    $Name=~s/\(\w+\)(\d)/$1/;
4275    return $Name;
4276}
4277
4278sub modelUnmangled($$)
4279{
4280    my ($InfoId, $Compiler) = @_;
4281    if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
4282        return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
4283    }
4284    my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4285    if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4286        $PureSignature = "~".$PureSignature;
4287    }
4288    if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
4289    {
4290        my (@Params, @ParamTypes) = ();
4291        if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
4292        and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4293            @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
4294        }
4295        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4296        { # checking parameters
4297            my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
4298            my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"};
4299            my %PType = get_PureType($PId, $TypeInfo{$Version});
4300            my $PTName = unmangledFormat($PType{"Name"}, $Version);
4301
4302            if($PName eq "this"
4303            and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method")
4304            {
4305                next;
4306            }
4307
4308            $PTName=~s/\b(restrict|register)\b//g;
4309            if($Compiler eq "MSVC") {
4310                $PTName=~s/\blong long\b/__int64/;
4311            }
4312            @ParamTypes = (@ParamTypes, $PTName);
4313        }
4314        if(@ParamTypes) {
4315            $PureSignature .= "(".join(", ", @ParamTypes).")";
4316        }
4317        else
4318        {
4319            if($Compiler eq "MSVC")
4320            {
4321                $PureSignature .= "(void)";
4322            }
4323            else
4324            { # GCC
4325                $PureSignature .= "()";
4326            }
4327        }
4328        $PureSignature = delete_keywords($PureSignature);
4329    }
4330    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4331    {
4332        my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
4333        $PureSignature = $ClassName."::".$PureSignature;
4334    }
4335    elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
4336        $PureSignature = $NS."::".$PureSignature;
4337    }
4338    if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
4339        $PureSignature .= " const";
4340    }
4341    if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
4342        $PureSignature .= " volatile";
4343    }
4344    my $ShowReturn = 0;
4345    if($Compiler eq "MSVC"
4346    and $SymbolInfo{$Version}{$InfoId}{"Data"})
4347    {
4348        $ShowReturn=1;
4349    }
4350    elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
4351    and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
4352    {
4353        $ShowReturn=1;
4354    }
4355    if($ShowReturn)
4356    { # mangled names for template function specializations include return value
4357        if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
4358        {
4359            my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
4360            my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
4361            $PureSignature = $ReturnName." ".$PureSignature;
4362        }
4363    }
4364    return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
4365}
4366
4367sub mangle_symbol($$$)
4368{ # mangling for simple methods
4369  # see gcc-4.6.0/gcc/cp/mangle.c
4370    my ($InfoId, $LibVersion, $Compiler) = @_;
4371    if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
4372        return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
4373    }
4374    my $Mangled = "";
4375    if($Compiler eq "GCC") {
4376        $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
4377    }
4378    elsif($Compiler eq "MSVC") {
4379        $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
4380    }
4381    return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
4382}
4383
4384sub mangle_symbol_MSVC($$)
4385{
4386    my ($InfoId, $LibVersion) = @_;
4387    return "";
4388}
4389
4390sub mangle_symbol_GCC($$)
4391{ # see gcc-4.6.0/gcc/cp/mangle.c
4392    my ($InfoId, $LibVersion) = @_;
4393    my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
4394    my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
4395    my %Repl = ();# SN_ replacements
4396    if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
4397    {
4398        my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
4399        if($MangledClass!~/\AN/) {
4400            $MangledClass = "N".$MangledClass;
4401        }
4402        else {
4403            $MangledClass=~s/E\Z//;
4404        }
4405        if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
4406            $MangledClass=~s/\AN/NV/;
4407        }
4408        if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
4409            $MangledClass=~s/\AN/NK/;
4410        }
4411        $Mangled .= $MangledClass;
4412    }
4413    elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
4414    { # mangled by name due to the absence of structured info
4415        my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
4416        if($MangledNS!~/\AN/) {
4417            $MangledNS = "N".$MangledNS;
4418        }
4419        else {
4420            $MangledNS=~s/E\Z//;
4421        }
4422        $Mangled .= $MangledNS;
4423    }
4424    my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
4425    my @TParams = ();
4426    if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
4427    { # parsing mode
4428        foreach (@TPos) {
4429            push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
4430        }
4431    }
4432    elsif($TmplParams)
4433    { # remangling mode
4434      # support for old ABI dumps
4435        @TParams = separate_Params($TmplParams, 0, 0);
4436    }
4437    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
4438        $Mangled .= "C1";
4439    }
4440    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
4441        $Mangled .= "D0";
4442    }
4443    elsif($ShortName)
4444    {
4445        if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
4446        {
4447            if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
4448            and isConstType($Return, $LibVersion))
4449            { # "const" global data is mangled as _ZL...
4450                $Mangled .= "L";
4451            }
4452        }
4453        if($ShortName=~/\Aoperator(\W.*)\Z/)
4454        {
4455            my $Op = $1;
4456            $Op=~s/\A[ ]+//g;
4457            if(my $OpMngl = $OperatorMangling{$Op}) {
4458                $Mangled .= $OpMngl;
4459            }
4460            else { # conversion operator
4461                $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
4462            }
4463        }
4464        else {
4465            $Mangled .= length($ShortName).$ShortName;
4466        }
4467        if(@TParams)
4468        { # templates
4469            $Mangled .= "I";
4470            foreach my $TParam (@TParams) {
4471                $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
4472            }
4473            $Mangled .= "E";
4474        }
4475        if(not $ClassId and @TParams) {
4476            add_substitution($ShortName, \%Repl, 0);
4477        }
4478    }
4479    if($ClassId or $NameSpace) {
4480        $Mangled .= "E";
4481    }
4482    if(@TParams)
4483    {
4484        if($Return) {
4485            $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
4486        }
4487    }
4488    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
4489    {
4490        my @Params = ();
4491        if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
4492        and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
4493            @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
4494        }
4495        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4496        { # checking parameters
4497            my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
4498            $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
4499        }
4500        if(not @Params) {
4501            $Mangled .= "v";
4502        }
4503    }
4504    $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
4505    $Mangled = write_stdcxx_substitution($Mangled);
4506    if($Mangled eq "_Z") {
4507        return "";
4508    }
4509    return $Mangled;
4510}
4511
4512sub correct_incharge($$$)
4513{
4514    my ($InfoId, $LibVersion, $Mangled) = @_;
4515    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4516    {
4517        if($MangledNames{$LibVersion}{$Mangled}) {
4518            $Mangled=~s/C1([EI])/C2$1/;
4519        }
4520    }
4521    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4522    {
4523        if($MangledNames{$LibVersion}{$Mangled}) {
4524            $Mangled=~s/D0([EI])/D1$1/;
4525        }
4526        if($MangledNames{$LibVersion}{$Mangled}) {
4527            $Mangled=~s/D1([EI])/D2$1/;
4528        }
4529    }
4530    return $Mangled;
4531}
4532
4533sub template_Base($)
4534{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
4535  # NOTE: operators: >>, <<
4536    my $Name = $_[0];
4537    if($Name!~/>\Z/ or $Name!~/</) {
4538        return $Name;
4539    }
4540    my $TParams = $Name;
4541    while(my $CPos = find_center($TParams, "<"))
4542    { # search for the last <T>
4543        $TParams = substr($TParams, $CPos);
4544    }
4545    if($TParams=~s/\A<(.+)>\Z/$1/) {
4546        $Name=~s/<\Q$TParams\E>\Z//;
4547    }
4548    else
4549    { # error
4550        $TParams = "";
4551    }
4552    return ($Name, $TParams);
4553}
4554
4555sub get_sub_ns($)
4556{
4557    my $Name = $_[0];
4558    my @NS = ();
4559    while(my $CPos = find_center($Name, ":"))
4560    {
4561        push(@NS, substr($Name, 0, $CPos));
4562        $Name = substr($Name, $CPos);
4563        $Name=~s/\A:://;
4564    }
4565    return (join("::", @NS), $Name);
4566}
4567
4568sub mangle_ns($$$)
4569{
4570    my ($Name, $LibVersion, $Repl) = @_;
4571    if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4572    {
4573        my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4574        $Mangled=~s/\AN(.+)E\Z/$1/;
4575        return $Mangled;
4576
4577    }
4578    else
4579    {
4580        my ($MangledNS, $SubNS) = ("", "");
4581        ($SubNS, $Name) = get_sub_ns($Name);
4582        if($SubNS) {
4583            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4584        }
4585        $MangledNS .= length($Name).$Name;
4586        add_substitution($MangledNS, $Repl, 0);
4587        return $MangledNS;
4588    }
4589}
4590
4591sub mangle_param($$$)
4592{
4593    my ($PTid, $LibVersion, $Repl) = @_;
4594    my ($MPrefix, $Mangled) = ("", "");
4595    my %ReplCopy = %{$Repl};
4596    my %BaseType = get_BaseType($PTid, $LibVersion);
4597    my $BaseType_Name = $BaseType{"Name"};
4598    $BaseType_Name=~s/\A(struct|union|enum) //g;
4599    if(not $BaseType_Name) {
4600        return "";
4601    }
4602    my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
4603    my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
4604    while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4605    while($Suffix=~/(&|\*|const)\Z/)
4606    {
4607        if($Suffix=~s/[ ]*&\Z//) {
4608            $MPrefix .= "R";
4609        }
4610        if($Suffix=~s/[ ]*\*\Z//) {
4611            $MPrefix .= "P";
4612        }
4613        if($Suffix=~s/[ ]*const\Z//)
4614        {
4615            if($MPrefix=~/R|P/
4616            or $Suffix=~/&|\*/) {
4617                $MPrefix .= "K";
4618            }
4619        }
4620        if($Suffix=~s/[ ]*volatile\Z//) {
4621            $MPrefix .= "V";
4622        }
4623        #if($Suffix=~s/[ ]*restrict\Z//) {
4624            #$MPrefix .= "r";
4625        #}
4626    }
4627    if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4628        $Mangled .= $Token;
4629    }
4630    elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4631    {
4632        my @TParams = ();
4633        if(my @TPos = keys(%{$BaseType{"TParam"}}))
4634        { # parsing mode
4635            foreach (@TPos) {
4636                push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4637            }
4638        }
4639        elsif($TmplParams)
4640        { # remangling mode
4641          # support for old ABI dumps
4642            @TParams = separate_Params($TmplParams, 0, 0);
4643        }
4644        my $MangledNS = "";
4645        my ($SubNS, $SName) = get_sub_ns($ShortName);
4646        if($SubNS) {
4647            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4648        }
4649        $MangledNS .= length($SName).$SName;
4650        if(@TParams) {
4651            add_substitution($MangledNS, $Repl, 0);
4652        }
4653        $Mangled .= "N".$MangledNS;
4654        if(@TParams)
4655        { # templates
4656            $Mangled .= "I";
4657            foreach my $TParam (@TParams) {
4658                $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4659            }
4660            $Mangled .= "E";
4661        }
4662        $Mangled .= "E";
4663    }
4664    elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4665    {
4666        if($BaseType{"Type"} eq "MethodPtr") {
4667            $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4668        }
4669        else {
4670            $Mangled .= "PF";
4671        }
4672        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4673        my @Params = keys(%{$BaseType{"Param"}});
4674        foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4675            $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4676        }
4677        if(not @Params) {
4678            $Mangled .= "v";
4679        }
4680        $Mangled .= "E";
4681    }
4682    elsif($BaseType{"Type"} eq "FieldPtr")
4683    {
4684        $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4685        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4686    }
4687    $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4688    if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4689    {
4690        if($Mangled eq $Optimized)
4691        {
4692            if($ShortName!~/::/)
4693            { # remove "N ... E"
4694                if($MPrefix) {
4695                    $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4696                }
4697                else {
4698                    $Mangled=~s/\AN(.+)E\Z/$1/g;
4699                }
4700            }
4701        }
4702        else {
4703            $Mangled = $Optimized;
4704        }
4705    }
4706    add_substitution($Mangled, $Repl, 1);
4707    return $Mangled;
4708}
4709
4710sub mangle_template_param($$$)
4711{ # types + literals
4712    my ($TParam, $LibVersion, $Repl) = @_;
4713    if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4714        return mangle_param($TPTid, $LibVersion, $Repl);
4715    }
4716    elsif($TParam=~/\A(\d+)(\w+)\Z/)
4717    { # class_name<1u>::method(...)
4718        return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4719    }
4720    elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4721    { # class_name<(signed char)1>::method(...)
4722        return "L".$IntrinsicMangling{$1}.$2."E";
4723    }
4724    elsif($TParam eq "true")
4725    { # class_name<true>::method(...)
4726        return "Lb1E";
4727    }
4728    elsif($TParam eq "false")
4729    { # class_name<true>::method(...)
4730        return "Lb0E";
4731    }
4732    else { # internal error
4733        return length($TParam).$TParam;
4734    }
4735}
4736
4737sub add_substitution($$$)
4738{
4739    my ($Value, $Repl, $Rec) = @_;
4740    if($Rec)
4741    { # subtypes
4742        my @Subs = ($Value);
4743        while($Value=~s/\A(R|P|K)//) {
4744            push(@Subs, $Value);
4745        }
4746        foreach (reverse(@Subs)) {
4747            add_substitution($_, $Repl, 0);
4748        }
4749        return;
4750    }
4751    return if($Value=~/\AS(\d*)_\Z/);
4752    $Value=~s/\AN(.+)E\Z/$1/g;
4753    return if(defined $Repl->{$Value});
4754    return if(length($Value)<=1);
4755    return if($StdcxxMangling{$Value});
4756    # check for duplicates
4757    my $Base = $Value;
4758    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4759    {
4760        my $Num = $Repl->{$Type};
4761        my $Replace = macro_mangle($Num);
4762        $Base=~s/\Q$Replace\E/$Type/;
4763    }
4764    if(my $OldNum = $Repl->{$Base})
4765    {
4766        $Repl->{$Value} = $OldNum;
4767        return;
4768    }
4769    my @Repls = sort {$b<=>$a} values(%{$Repl});
4770    if(@Repls) {
4771        $Repl->{$Value} = $Repls[0]+1;
4772    }
4773    else {
4774        $Repl->{$Value} = -1;
4775    }
4776    # register duplicates
4777    # upward
4778    $Base = $Value;
4779    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4780    {
4781        next if($Base eq $Type);
4782        my $Num = $Repl->{$Type};
4783        my $Replace = macro_mangle($Num);
4784        $Base=~s/\Q$Type\E/$Replace/;
4785        $Repl->{$Base} = $Repl->{$Value};
4786    }
4787}
4788
4789sub macro_mangle($)
4790{
4791    my $Num = $_[0];
4792    if($Num==-1) {
4793        return "S_";
4794    }
4795    else
4796    {
4797        my $Code = "";
4798        if($Num<10)
4799        { # S0_, S1_, S2_, ...
4800            $Code = $Num;
4801        }
4802        elsif($Num>=10 and $Num<=35)
4803        { # SA_, SB_, SC_, ...
4804            $Code = chr(55+$Num);
4805        }
4806        else
4807        { # S10_, S11_, S12_
4808            $Code = $Num-26; # 26 is length of english alphabet
4809        }
4810        return "S".$Code."_";
4811    }
4812}
4813
4814sub write_stdcxx_substitution($)
4815{
4816    my $Mangled = $_[0];
4817    if($StdcxxMangling{$Mangled}) {
4818        return $StdcxxMangling{$Mangled};
4819    }
4820    else
4821    {
4822        my @Repls = keys(%StdcxxMangling);
4823        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4824        foreach my $MangledType (@Repls)
4825        {
4826            my $Replace = $StdcxxMangling{$MangledType};
4827            #if($Mangled!~/$Replace/) {
4828                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4829                $Mangled=~s/\Q$MangledType\E/$Replace/g;
4830            #}
4831        }
4832    }
4833    return $Mangled;
4834}
4835
4836sub write_substitution($$)
4837{
4838    my ($Mangled, $Repl) = @_;
4839    if(defined $Repl->{$Mangled}
4840    and my $MnglNum = $Repl->{$Mangled}) {
4841        $Mangled = macro_mangle($MnglNum);
4842    }
4843    else
4844    {
4845        my @Repls = keys(%{$Repl});
4846        #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4847        # FIXME: how to apply replacements? by num or by pos
4848        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4849        foreach my $MangledType (@Repls)
4850        {
4851            my $Replace = macro_mangle($Repl->{$MangledType});
4852            if($Mangled!~/$Replace/) {
4853                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4854                $Mangled=~s/\Q$MangledType\E/$Replace/g;
4855            }
4856        }
4857    }
4858    return $Mangled;
4859}
4860
4861sub delete_keywords($)
4862{
4863    my $TypeName = $_[0];
4864    $TypeName=~s/\b(enum|struct|union|class) //g;
4865    return $TypeName;
4866}
4867
4868sub uncover_typedefs($$)
4869{
4870    my ($TypeName, $LibVersion) = @_;
4871    return "" if(not $TypeName);
4872    if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4873        return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4874    }
4875    my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
4876    while($TypeName_New ne $TypeName_Pre)
4877    {
4878        $TypeName_Pre = $TypeName_New;
4879        my $TypeName_Copy = $TypeName_New;
4880        my %Words = ();
4881        while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
4882        {
4883            if(not $Intrinsic_Keywords{$1}) {
4884                $Words{$1} = 1;
4885            }
4886        }
4887        foreach my $Word (keys(%Words))
4888        {
4889            my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4890            next if(not $BaseType_Name);
4891            next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
4892            if($BaseType_Name=~/\([\*]+\)/)
4893            { # FuncPtr
4894                if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4895                {
4896                    my $Type_Suffix = $1;
4897                    $TypeName_New = $BaseType_Name;
4898                    if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4899                        $TypeName_New = formatName($TypeName_New, "T");
4900                    }
4901                }
4902            }
4903            else
4904            {
4905                if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
4906                    $TypeName_New = formatName($TypeName_New, "T");
4907                }
4908            }
4909        }
4910    }
4911    return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4912}
4913
4914sub isInternal($)
4915{
4916    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4917    {
4918        if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4919        {
4920            if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4921            { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4922                return 1;
4923            }
4924        }
4925    }
4926    return 0;
4927}
4928
4929sub getDataVal($$)
4930{
4931    my ($InfoId, $TypeId) = @_;
4932    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4933    {
4934        if($Info=~/init[ ]*:[ ]*@(\d+) /)
4935        {
4936            if(defined $LibInfo{$Version}{"info_type"}{$1}
4937            and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4938            {
4939                if(my $Nop = getTreeAttr_Op($1))
4940                {
4941                    if(defined $LibInfo{$Version}{"info_type"}{$Nop}
4942                    and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr")
4943                    {
4944                        if(my $Addr = getTreeAttr_Op($1)) {
4945                            return getInitVal($Addr, $TypeId);
4946                        }
4947                    }
4948                }
4949            }
4950            else {
4951                return getInitVal($1, $TypeId);
4952            }
4953        }
4954    }
4955    return undef;
4956}
4957
4958sub getInitVal($$)
4959{
4960    my ($InfoId, $TypeId) = @_;
4961    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4962    {
4963        if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4964        {
4965            if($InfoType eq "integer_cst")
4966            {
4967                my $Val = getNodeIntCst($InfoId);
4968                if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
4969                { # characters
4970                    $Val = chr($Val);
4971                }
4972                return $Val;
4973            }
4974            elsif($InfoType eq "string_cst") {
4975                return getNodeStrCst($InfoId);
4976            }
4977            elsif($InfoType eq "var_decl")
4978            {
4979                if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4980                    return $Name;
4981                }
4982            }
4983        }
4984    }
4985    return undef;
4986}
4987
4988sub set_Class_And_Namespace($)
4989{
4990    my $InfoId = $_[0];
4991    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4992    {
4993        if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
4994        {
4995            my $NSInfoId = $1;
4996            if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4997            {
4998                if($InfoType eq "namespace_decl") {
4999                    $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
5000                }
5001                elsif($InfoType eq "record_type") {
5002                    $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
5003                }
5004            }
5005        }
5006    }
5007    if($SymbolInfo{$Version}{$InfoId}{"Class"}
5008    or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
5009    {
5010        if($COMMON_LANGUAGE{$Version} ne "C++")
5011        { # skip
5012            return 1;
5013        }
5014    }
5015
5016    return 0;
5017}
5018
5019sub debugMangling($)
5020{
5021    my $LibVersion = $_[0];
5022    my %Mangled = ();
5023    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
5024    {
5025        if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
5026        {
5027            if($Mngl=~/\A(_Z|\?)/) {
5028                $Mangled{$Mngl}=$InfoId;
5029            }
5030        }
5031    }
5032    translateSymbols(keys(%Mangled), $LibVersion);
5033    foreach my $Mngl (keys(%Mangled))
5034    {
5035        my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
5036        my $U2 = $tr_name{$Mngl};
5037        if($U1 ne $U2) {
5038            printMsg("INFO", "INCORRECT MANGLING:\n  $Mngl\n  $U1\n  $U2\n");
5039        }
5040    }
5041}
5042
5043sub linkSymbol($)
5044{ # link symbols from shared libraries
5045  # with the symbols from header files
5046    my $InfoId = $_[0];
5047    # try to mangle symbol
5048    if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
5049    or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"})
5050    or $EMERGENCY_MODE_48)
5051    { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
5052      # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
5053      # GCC 4.8 doesn't mangle anything
5054        if(not $CheckHeadersOnly)
5055        {
5056            if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
5057                return correct_incharge($InfoId, $Version, $Mangled);
5058            }
5059        }
5060        if($CheckHeadersOnly
5061        or not $BinaryOnly
5062        or $EMERGENCY_MODE_48)
5063        { # 1. --headers-only mode
5064          # 2. not mangled src-only symbols
5065            if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
5066                return $Mangled;
5067            }
5068        }
5069    }
5070    return "";
5071}
5072
5073sub setLanguage($$)
5074{
5075    my ($LibVersion, $Lang) = @_;
5076    if(not $UserLang) {
5077        $COMMON_LANGUAGE{$LibVersion} = $Lang;
5078    }
5079}
5080
5081sub getSymbolInfo($)
5082{
5083    my $InfoId = $_[0];
5084    if(isInternal($InfoId)) {
5085        return;
5086    }
5087    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
5088    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
5089    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
5090    {
5091        delete($SymbolInfo{$Version}{$InfoId});
5092        return;
5093    }
5094    setFuncAccess($InfoId);
5095    setFuncKind($InfoId);
5096    if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
5097    {
5098        delete($SymbolInfo{$Version}{$InfoId});
5099        return;
5100    }
5101
5102    $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
5103    if(my $Return = getFuncReturn($InfoId))
5104    {
5105        if(not defined $TypeInfo{$Version}{$Return}
5106        or not $TypeInfo{$Version}{$Return}{"Name"})
5107        {
5108            delete($SymbolInfo{$Version}{$InfoId});
5109            return;
5110        }
5111        $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return;
5112    }
5113    if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
5114    {
5115        if(defined $MissedTypedef{$Version}{$Rid})
5116        {
5117            if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
5118                $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
5119            }
5120        }
5121    }
5122    if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
5123        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
5124    }
5125    my $Orig = getFuncOrig($InfoId);
5126    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
5127    if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1)
5128    {
5129        delete($SymbolInfo{$Version}{$InfoId});
5130        return;
5131    }
5132
5133    if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0)
5134    {
5135        delete($SymbolInfo{$Version}{$InfoId});
5136        return;
5137    }
5138
5139    if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
5140    {
5141        my $Tmpl = $BasicTemplate{$Version}{$InfoId};
5142
5143        my @TParams = getTParams($Orig, "Func");
5144        if(not @TParams)
5145        {
5146            delete($SymbolInfo{$Version}{$InfoId});
5147            return;
5148        }
5149        foreach my $Pos (0 .. $#TParams)
5150        {
5151            my $Val = $TParams[$Pos];
5152            $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val;
5153
5154            if($Tmpl)
5155            {
5156                if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos})
5157                {
5158                    $TemplateMap{$Version}{$InfoId}{$Arg} = $Val;
5159                }
5160            }
5161        }
5162
5163        if($Tmpl)
5164        {
5165            foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}}))
5166            {
5167                if($Pos>$#TParams)
5168                {
5169                    my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos};
5170                    $TemplateMap{$Version}{$InfoId}{$Arg} = "";
5171                }
5172            }
5173        }
5174
5175        my $PrmsInLine = join(", ", @TParams);
5176        if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
5177        { # operator<< <T>, operator>> <T>
5178            $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
5179        }
5180        $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
5181        $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
5182    }
5183    else
5184    { # support for GCC 3.4
5185        $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
5186    }
5187    if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
5188    {
5189        if($OSgroup eq "windows")
5190        { # cut the offset
5191            $MnglName=~s/\@\d+\Z//g;
5192        }
5193        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
5194
5195        # NOTE: mangling of some symbols may change depending on GCC version
5196        # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
5197        # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
5198    }
5199
5200    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
5201    and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
5202    {
5203        delete($SymbolInfo{$Version}{$InfoId});
5204        return;
5205    }
5206    if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
5207    { # destructors have an empty parameter list
5208        my $Skip = setFuncParams($InfoId);
5209        if($Skip)
5210        {
5211            delete($SymbolInfo{$Version}{$InfoId});
5212            return;
5213        }
5214    }
5215    if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
5216        $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
5217    }
5218
5219    if(set_Class_And_Namespace($InfoId))
5220    {
5221        delete($SymbolInfo{$Version}{$InfoId});
5222        return;
5223    }
5224
5225    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
5226    {
5227        if(not defined $TypeInfo{$Version}{$ClassId}
5228        or not $TypeInfo{$Version}{$ClassId}{"Name"})
5229        {
5230            delete($SymbolInfo{$Version}{$InfoId});
5231            return;
5232        }
5233    }
5234    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
5235    { # extern "C"
5236        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
5237        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
5238    }
5239    if($UserLang and $UserLang eq "C")
5240    { # --lang=C option
5241        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
5242    }
5243    if($COMMON_LANGUAGE{$Version} eq "C++")
5244    { # correct mangled & short names
5245      # C++ or --headers-only mode
5246        if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
5247        { # support for old GCC versions: reconstruct real names for constructors and destructors
5248            $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
5249            $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
5250        }
5251        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
5252        { # try to mangle symbol (link with libraries)
5253            if(my $Mangled = linkSymbol($InfoId)) {
5254                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
5255            }
5256        }
5257        if($OStarget eq "windows")
5258        { # link MS C++ symbols from library with GCC symbols from headers
5259            if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
5260            { # exported symbols
5261                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
5262            }
5263            elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
5264            { # pure virtual symbols
5265                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
5266            }
5267        }
5268    }
5269    else
5270    { # not mangled in C
5271        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
5272    }
5273    if(not $CheckHeadersOnly
5274    and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
5275    and not $SymbolInfo{$Version}{$InfoId}{"Class"})
5276    {
5277        my $Incorrect = 0;
5278
5279        if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
5280        {
5281            if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0
5282            and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
5283            { # mangled in the TU dump, but not mangled in the library
5284                $Incorrect = 1;
5285            }
5286        }
5287        else
5288        {
5289            if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C")
5290            { # all C++ functions are not mangled in the TU dump
5291                $Incorrect = 1;
5292            }
5293        }
5294        if($Incorrect)
5295        {
5296            if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) {
5297                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
5298            }
5299        }
5300    }
5301    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
5302    { # can't detect symbol name
5303        delete($SymbolInfo{$Version}{$InfoId});
5304        return;
5305    }
5306    if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
5307    and my $Spec = getVirtSpec($Orig))
5308    { # identify virtual and pure virtual functions
5309      # NOTE: constructors cannot be virtual
5310      # NOTE: in GCC 4.7 D1 destructors have no virtual spec
5311      # in the TU dump, so taking it from the original symbol
5312        if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
5313        and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
5314        { # NOTE: D2 destructors are not present in a v-table
5315            $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
5316        }
5317    }
5318    if(isInline($InfoId)) {
5319        $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
5320    }
5321    if(hasThrow($InfoId)) {
5322        $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
5323    }
5324    if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
5325    and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
5326    {
5327        if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
5328        and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
5329        { # inline or auto-generated constructor
5330            delete($TypeInfo{$Version}{$ClassId}{"Copied"});
5331        }
5332    }
5333    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
5334    {
5335        if(not $ExtraDump)
5336        {
5337            if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
5338            { # non-target symbols
5339                delete($SymbolInfo{$Version}{$InfoId});
5340                return;
5341            }
5342        }
5343    }
5344    if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
5345    or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
5346    or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
5347    or $SymbolInfo{$Version}{$InfoId}{"Class"})
5348    {
5349        if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
5350        {
5351            delete($SymbolInfo{$Version}{$InfoId});
5352            return;
5353        }
5354    }
5355    if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
5356    {
5357        if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
5358        { # one instance for one mangled name only
5359            delete($SymbolInfo{$Version}{$InfoId});
5360            return;
5361        }
5362        else {
5363            $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
5364        }
5365    }
5366    if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
5367    or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
5368        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
5369    }
5370    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
5371    and $SymbolInfo{$Version}{$InfoId}{"Class"})
5372    {
5373        if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
5374        { # static methods
5375            $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
5376        }
5377    }
5378    if(getFuncLink($InfoId) eq "Static") {
5379        $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
5380    }
5381    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
5382    {
5383        if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
5384        {
5385            if($Unmangled=~/\.\_\d/)
5386            {
5387                delete($SymbolInfo{$Version}{$InfoId});
5388                return;
5389            }
5390        }
5391    }
5392
5393    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
5394        $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
5395    }
5396    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
5397        $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
5398    }
5399
5400    if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
5401        $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
5402    }
5403
5404    if($ExtraDump) {
5405        $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId);
5406    }
5407}
5408
5409sub guessHeader($)
5410{
5411    my $InfoId = $_[0];
5412    my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
5413    my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"};
5414    my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):"";
5415    my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"};
5416    if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName})
5417    {
5418        if(get_filename($HPath) eq $Header)
5419        {
5420            my $HDir = get_filename(get_dirname($HPath));
5421            if($HDir ne "include"
5422            and $HDir=~/\A[a-z]+\Z/i) {
5423                return join_P($HDir, $Header);
5424            }
5425        }
5426    }
5427    return $Header;
5428}
5429
5430sub isInline($)
5431{ # "body: undefined" in the tree
5432  # -fkeep-inline-functions GCC option should be specified
5433    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5434    {
5435        if($Info=~/ undefined /i) {
5436            return 0;
5437        }
5438    }
5439    return 1;
5440}
5441
5442sub hasThrow($)
5443{
5444    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5445    {
5446        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5447            return getTreeAttr_Unql($1, "unql");
5448        }
5449    }
5450    return 1;
5451}
5452
5453sub getTypeId($)
5454{
5455    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5456    {
5457        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5458            return $1;
5459        }
5460    }
5461    return "";
5462}
5463
5464sub setTypeMemb($$)
5465{
5466    my ($TypeId, $TypeAttr) = @_;
5467    my $TypeType = $TypeAttr->{"Type"};
5468    my ($Pos, $UnnamedPos) = (0, 0);
5469    my $StaticFields = 0;
5470    if($TypeType eq "Enum")
5471    {
5472        my $MInfoId = getTreeAttr_Csts($TypeId);
5473        while($MInfoId)
5474        {
5475            $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId);
5476            my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId));
5477            $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
5478            $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
5479            $MInfoId = getNextElem($MInfoId);
5480            $Pos += 1;
5481        }
5482    }
5483    elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
5484    {
5485        my $MInfoId = getTreeAttr_Flds($TypeId);
5486        while($MInfoId)
5487        {
5488            my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId};
5489            my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId};
5490            if(not $IType or $IType ne "field_decl")
5491            { # search for fields, skip other stuff in the declaration
5492
5493                if($IType eq "var_decl")
5494                { # static field
5495                    $StaticFields = 1;
5496                }
5497
5498                $MInfoId = getNextElem($MInfoId);
5499                next;
5500            }
5501            my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId));
5502            if(index($StructMembName, "_vptr.")==0)
5503            { # virtual tables
5504                $StructMembName = "_vptr";
5505            }
5506            if(not $StructMembName)
5507            { # unnamed fields
5508                if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
5509                {
5510                    my $UnnamedTid = getTreeAttr_Type($MInfoId);
5511                    my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
5512                    if(isAnon($UnnamedTName))
5513                    { # rename unnamed fields to unnamed0, unnamed1, ...
5514                        $StructMembName = "unnamed".($UnnamedPos++);
5515                    }
5516                }
5517            }
5518            if(not $StructMembName)
5519            { # unnamed fields and base classes
5520                $MInfoId = getNextElem($MInfoId);
5521                next;
5522            }
5523            my $MembTypeId = getTreeAttr_Type($MInfoId);
5524            if(defined $MissedTypedef{$Version}{$MembTypeId})
5525            {
5526                if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
5527                    $MembTypeId = $AddedTid;
5528                }
5529            }
5530
5531            $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
5532            $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
5533            if((my $Access = getTreeAccess($MInfoId)) ne "public")
5534            { # marked only protected and private, public by default
5535                $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
5536            }
5537            if($MInfo=~/spec:\s*mutable /)
5538            { # mutable fields
5539                $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
5540            }
5541            if(my $Algn = getAlgn($MInfoId)) {
5542                $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
5543            }
5544            if(my $BFSize = getBitField($MInfoId))
5545            { # in bits
5546                $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
5547            }
5548            else
5549            { # in bytes
5550                if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1)
5551                { # template
5552                    delete($TypeAttr->{"Memb"}{$Pos}{"algn"});
5553                }
5554                else {
5555                    $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
5556                }
5557            }
5558
5559            $MInfoId = getNextElem($MInfoId);
5560            $Pos += 1;
5561        }
5562    }
5563
5564    return $StaticFields;
5565}
5566
5567sub setFuncParams($)
5568{
5569    my $InfoId = $_[0];
5570    my $ParamInfoId = getTreeAttr_Args($InfoId);
5571
5572    my $FType = getFuncType($InfoId);
5573
5574    if($FType eq "Method")
5575    { # check type of "this" pointer
5576        my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
5577        if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
5578        {
5579            if($ObjectName=~/\bconst(| volatile)\*const\b/) {
5580                $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
5581            }
5582            if($ObjectName=~/\bvolatile\b/) {
5583                $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
5584            }
5585        }
5586        else
5587        { # skip
5588            return 1;
5589        }
5590        # skip "this"-parameter
5591        # $ParamInfoId = getNextElem($ParamInfoId);
5592    }
5593    my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1);
5594    while($ParamInfoId)
5595    { # formal args
5596        my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
5597        my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
5598        if(not $ParamName)
5599        { # unnamed
5600            $ParamName = "p".($PPos+1);
5601        }
5602        if(defined $MissedTypedef{$Version}{$ParamTypeId})
5603        {
5604            if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
5605                $ParamTypeId = $AddedTid;
5606            }
5607        }
5608        my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
5609        if(not $PType or $PType eq "Unknown") {
5610            return 1;
5611        }
5612        my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
5613        if(not $PTName) {
5614            return 1;
5615        }
5616        if($PTName eq "void") {
5617            last;
5618        }
5619        if($ParamName eq "__vtt_parm"
5620        and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
5621        {
5622            $Vtt_Pos = $Pos;
5623            $ParamInfoId = getNextElem($ParamInfoId);
5624            next;
5625        }
5626        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5627
5628        if(my %Base = get_BaseType($ParamTypeId, $Version))
5629        {
5630            if(defined $Base{"Template"}) {
5631                return 1;
5632            }
5633        }
5634
5635        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
5636        if(my $Algn = getAlgn($ParamInfoId)) {
5637            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5638        }
5639        if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5640        { # foo(register type arg)
5641            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
5642        }
5643        $ParamInfoId = getNextElem($ParamInfoId);
5644        $Pos += 1;
5645        if($ParamName ne "this" or $FType ne "Method") {
5646            $PPos += 1;
5647        }
5648    }
5649    if(setFuncArgs($InfoId, $Vtt_Pos)) {
5650        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
5651    }
5652    return 0;
5653}
5654
5655sub setFuncArgs($$)
5656{
5657    my ($InfoId, $Vtt_Pos) = @_;
5658    my $FuncTypeId = getFuncTypeId($InfoId);
5659    my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
5660    my $FType = getFuncType($InfoId);
5661
5662    if($FType eq "Method")
5663    {
5664        # skip "this"-parameter
5665        # $ParamListElemId = getNextElem($ParamListElemId);
5666    }
5667    if(not $ParamListElemId)
5668    { # foo(...)
5669        return 1;
5670    }
5671    my $HaveVoid = 0;
5672    my ($Pos, $PPos) = (0, 0);
5673    while($ParamListElemId)
5674    { # actual params: may differ from formal args
5675      # formal int*const
5676      # actual: int*
5677        if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
5678        {
5679            $Vtt_Pos=-1;
5680            $ParamListElemId = getNextElem($ParamListElemId);
5681            next;
5682        }
5683        my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5684        if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
5685        {
5686            $HaveVoid = 1;
5687            last;
5688        }
5689        else
5690        {
5691            if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
5692            {
5693                $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5694                if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5695                { # unnamed
5696                    $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1);
5697                }
5698            }
5699            elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
5700            {
5701                if($Pos>0 or getFuncType($InfoId) ne "Method")
5702                { # params
5703                    if($OldId ne $ParamTypeId)
5704                    {
5705                        my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version});
5706                        my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version});
5707
5708                        if($Old_Pure{"Name"} ne $New_Pure{"Name"}) {
5709                            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5710                        }
5711                    }
5712                }
5713            }
5714        }
5715        if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
5716        { # default arguments
5717            if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5718            {
5719                if($PurpType eq "nop_expr")
5720                { # func ( const char* arg = (const char*)(void*)0 )
5721                    $PurpId = getTreeAttr_Op($PurpId);
5722                }
5723                my $Val = getInitVal($PurpId, $ParamTypeId);
5724                if(defined $Val) {
5725                    $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5726                }
5727            }
5728        }
5729        $ParamListElemId = getNextElem($ParamListElemId);
5730        if($Pos!=0 or $FType ne "Method") {
5731            $PPos += 1;
5732        }
5733        $Pos += 1;
5734    }
5735    return ($Pos>=1 and not $HaveVoid);
5736}
5737
5738sub getTreeAttr_Chan($)
5739{
5740    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5741    {
5742        if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5743            return $1;
5744        }
5745    }
5746    return "";
5747}
5748
5749sub getTreeAttr_Chain($)
5750{
5751    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5752    {
5753        if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5754            return $1;
5755        }
5756    }
5757    return "";
5758}
5759
5760sub getTreeAttr_Unql($)
5761{
5762    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5763    {
5764        if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5765            return $1;
5766        }
5767    }
5768    return "";
5769}
5770
5771sub getTreeAttr_Scpe($)
5772{
5773    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5774    {
5775        if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5776            return $1;
5777        }
5778    }
5779    return "";
5780}
5781
5782sub getTreeAttr_Type($)
5783{
5784    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5785    {
5786        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5787            return $1;
5788        }
5789    }
5790    return "";
5791}
5792
5793sub getTreeAttr_Name($)
5794{
5795    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5796    {
5797        if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5798            return $1;
5799        }
5800    }
5801    return "";
5802}
5803
5804sub getTreeAttr_Mngl($)
5805{
5806    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5807    {
5808        if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5809            return $1;
5810        }
5811    }
5812    return "";
5813}
5814
5815sub getTreeAttr_Prms($)
5816{
5817    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5818    {
5819        if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5820            return $1;
5821        }
5822    }
5823    return "";
5824}
5825
5826sub getTreeAttr_Fncs($)
5827{
5828    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5829    {
5830        if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5831            return $1;
5832        }
5833    }
5834    return "";
5835}
5836
5837sub getTreeAttr_Csts($)
5838{
5839    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5840    {
5841        if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5842            return $1;
5843        }
5844    }
5845    return "";
5846}
5847
5848sub getTreeAttr_Purp($)
5849{
5850    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5851    {
5852        if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5853            return $1;
5854        }
5855    }
5856    return "";
5857}
5858
5859sub getTreeAttr_Op($)
5860{
5861    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5862    {
5863        if($Info=~/op 0[ ]*:[ ]*@(\d+) /) {
5864            return $1;
5865        }
5866    }
5867    return "";
5868}
5869
5870sub getTreeAttr_Valu($)
5871{
5872    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5873    {
5874        if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5875            return $1;
5876        }
5877    }
5878    return "";
5879}
5880
5881sub getTreeAttr_Flds($)
5882{
5883    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5884    {
5885        if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5886            return $1;
5887        }
5888    }
5889    return "";
5890}
5891
5892sub getTreeAttr_Binf($)
5893{
5894    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5895    {
5896        if($Info=~/binf[ ]*:[ ]*@(\d+) /) {
5897            return $1;
5898        }
5899    }
5900    return "";
5901}
5902
5903sub getTreeAttr_Args($)
5904{
5905    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5906    {
5907        if($Info=~/args[ ]*:[ ]*@(\d+) /) {
5908            return $1;
5909        }
5910    }
5911    return "";
5912}
5913
5914sub getTreeValue($)
5915{
5916    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5917    {
5918        if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5919            return $1;
5920        }
5921    }
5922    return "";
5923}
5924
5925sub getTreeAccess($)
5926{
5927    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5928    {
5929        if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5930        {
5931            my $Access = $1;
5932            if($Access eq "prot") {
5933                return "protected";
5934            }
5935            elsif($Access eq "priv") {
5936                return "private";
5937            }
5938        }
5939        elsif($Info=~/ protected /)
5940        { # support for old GCC versions
5941            return "protected";
5942        }
5943        elsif($Info=~/ private /)
5944        { # support for old GCC versions
5945            return "private";
5946        }
5947    }
5948    return "public";
5949}
5950
5951sub setFuncAccess($)
5952{
5953    my $Access = getTreeAccess($_[0]);
5954    if($Access eq "protected") {
5955        $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
5956    }
5957    elsif($Access eq "private") {
5958        $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
5959    }
5960}
5961
5962sub setTypeAccess($$)
5963{
5964    my ($TypeId, $TypeAttr) = @_;
5965    my $Access = getTreeAccess($TypeId);
5966    if($Access eq "protected") {
5967        $TypeAttr->{"Protected"} = 1;
5968    }
5969    elsif($Access eq "private") {
5970        $TypeAttr->{"Private"} = 1;
5971    }
5972}
5973
5974sub setFuncKind($)
5975{
5976    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5977    {
5978        if($Info=~/pseudo tmpl/) {
5979            $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5980        }
5981        elsif($Info=~/ constructor /) {
5982            $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5983        }
5984        elsif($Info=~/ destructor /) {
5985            $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5986        }
5987    }
5988}
5989
5990sub getVirtSpec($)
5991{
5992    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5993    {
5994        if($Info=~/spec[ ]*:[ ]*pure /) {
5995            return "PureVirt";
5996        }
5997        elsif($Info=~/spec[ ]*:[ ]*virt /) {
5998            return "Virt";
5999        }
6000        elsif($Info=~/ pure\s+virtual /)
6001        { # support for old GCC versions
6002            return "PureVirt";
6003        }
6004        elsif($Info=~/ virtual /)
6005        { # support for old GCC versions
6006            return "Virt";
6007        }
6008    }
6009    return "";
6010}
6011
6012sub getFuncLink($)
6013{
6014    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6015    {
6016        if($Info=~/link[ ]*:[ ]*static /) {
6017            return "Static";
6018        }
6019        elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
6020            return $1;
6021        }
6022    }
6023    return "";
6024}
6025
6026sub select_Symbol_NS($$)
6027{
6028    my ($Symbol, $LibVersion) = @_;
6029    return "" if(not $Symbol or not $LibVersion);
6030    my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
6031    if(not $NS)
6032    {
6033        if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6034            $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"};
6035        }
6036    }
6037    if($NS)
6038    {
6039        if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
6040            return $NS;
6041        }
6042        else
6043        {
6044            while($NS=~s/::[^:]+\Z//)
6045            {
6046                if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
6047                    return $NS;
6048                }
6049            }
6050        }
6051    }
6052
6053    return "";
6054}
6055
6056sub select_Type_NS($$)
6057{
6058    my ($TypeName, $LibVersion) = @_;
6059    return "" if(not $TypeName or not $LibVersion);
6060    if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"})
6061    {
6062        if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
6063            return $NS;
6064        }
6065        else
6066        {
6067            while($NS=~s/::[^:]+\Z//)
6068            {
6069                if(defined $NestedNameSpaces{$LibVersion}{$NS}) {
6070                    return $NS;
6071                }
6072            }
6073        }
6074    }
6075    return "";
6076}
6077
6078sub getNameSpace($)
6079{
6080    my $InfoId = $_[0];
6081    if(my $NSInfoId = getTreeAttr_Scpe($InfoId))
6082    {
6083        if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
6084        {
6085            if($InfoType eq "namespace_decl")
6086            {
6087                if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
6088                {
6089                    my $NameSpace = getTreeStr($1);
6090                    if($NameSpace eq "::")
6091                    { # global namespace
6092                        return "";
6093                    }
6094                    if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
6095                        $NameSpace = $BaseNameSpace."::".$NameSpace;
6096                    }
6097                    $NestedNameSpaces{$Version}{$NameSpace} = 1;
6098                    return $NameSpace;
6099                }
6100                else {
6101                    return "";
6102                }
6103            }
6104            elsif($InfoType ne "function_decl")
6105            { # inside data type
6106                my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
6107                return $Name;
6108            }
6109        }
6110    }
6111    return "";
6112}
6113
6114sub getEnumMembVal($)
6115{
6116    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6117    {
6118        if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
6119        {
6120            if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
6121            {
6122                if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
6123                { # in newer versions of GCC the value is in the "const_decl->cnst" node
6124                    return getTreeValue($1);
6125                }
6126                else
6127                { # some old versions of GCC (3.3) have the value in the "integer_cst" node
6128                    return getTreeValue($1);
6129                }
6130            }
6131        }
6132    }
6133    return "";
6134}
6135
6136sub getSize($)
6137{
6138    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6139    {
6140        if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
6141            return getTreeValue($1);
6142        }
6143    }
6144    return 0;
6145}
6146
6147sub getAlgn($)
6148{
6149    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6150    {
6151        if($Info=~/algn[ ]*:[ ]*(\d+) /) {
6152            return $1;
6153        }
6154    }
6155    return "";
6156}
6157
6158sub getBitField($)
6159{
6160    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6161    {
6162        if($Info=~/ bitfield /) {
6163            return getSize($_[0]);
6164        }
6165    }
6166    return 0;
6167}
6168
6169sub getNextElem($)
6170{
6171    if(my $Chan = getTreeAttr_Chan($_[0])) {
6172        return $Chan;
6173    }
6174    elsif(my $Chain = getTreeAttr_Chain($_[0])) {
6175        return $Chain;
6176    }
6177    return "";
6178}
6179
6180sub registerHeader($$)
6181{ # input: absolute path of header, relative path or name
6182    my ($Header, $LibVersion) = @_;
6183    if(not $Header) {
6184        return "";
6185    }
6186    if(is_abs($Header) and not -f $Header)
6187    { # incorrect absolute path
6188        exitStatus("Access_Error", "can't access \'$Header\'");
6189    }
6190    if(skipHeader($Header, $LibVersion))
6191    { # skip
6192        return "";
6193    }
6194    if(my $Header_Path = identifyHeader($Header, $LibVersion))
6195    {
6196        detect_header_includes($Header_Path, $LibVersion);
6197
6198        if(defined $Tolerance and $Tolerance=~/3/)
6199        { # 3 - skip headers that include non-Linux headers
6200            if($OSgroup ne "windows")
6201            {
6202                foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}}))
6203                {
6204                    if(specificHeader($Inc, "windows")) {
6205                        return "";
6206                    }
6207                }
6208            }
6209        }
6210
6211        if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
6212        { # redirect
6213            if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
6214            or skipHeader($RHeader_Path, $LibVersion))
6215            { # skip
6216                return "";
6217            }
6218            $Header_Path = $RHeader_Path;
6219        }
6220        elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
6221        { # skip
6222            return "";
6223        }
6224
6225        if(my $HName = get_filename($Header_Path))
6226        { # register
6227            $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
6228            $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
6229        }
6230
6231        if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
6232        or $Header!~/\.(\w+)\Z/)
6233        { # hpp, hh, etc.
6234            setLanguage($LibVersion, "C++");
6235            $CPP_HEADERS = 1;
6236        }
6237
6238        if($CheckHeadersOnly
6239        and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
6240        { # /usr/include/c++/4.6.1/...
6241            $STDCXX_TESTING = 1;
6242        }
6243
6244        return $Header_Path;
6245    }
6246    return "";
6247}
6248
6249sub registerDir($$$)
6250{
6251    my ($Dir, $WithDeps, $LibVersion) = @_;
6252    $Dir=~s/[\/\\]+\Z//g;
6253    return if(not $LibVersion or not $Dir or not -d $Dir);
6254    $Dir = get_abs_path($Dir);
6255
6256    my $Mode = "All";
6257    if($WithDeps)
6258    {
6259        if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
6260            return;
6261        }
6262        elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
6263            $Mode = "DepsOnly";
6264        }
6265    }
6266    else
6267    {
6268        if($RegisteredDirs{$LibVersion}{$Dir}{1}
6269        or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
6270            return;
6271        }
6272    }
6273    $Header_Dependency{$LibVersion}{$Dir} = 1;
6274    $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
6275    if($Mode eq "DepsOnly")
6276    {
6277        foreach my $Path (cmd_find($Dir,"d")) {
6278            $Header_Dependency{$LibVersion}{$Path} = 1;
6279        }
6280        return;
6281    }
6282    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f"))
6283    {
6284        if($WithDeps)
6285        {
6286            my $SubDir = $Path;
6287            while(($SubDir = get_dirname($SubDir)) ne $Dir)
6288            { # register all sub directories
6289                $Header_Dependency{$LibVersion}{$SubDir} = 1;
6290            }
6291        }
6292        next if(is_not_header($Path));
6293        next if(ignore_path($Path));
6294        # Neighbors
6295        foreach my $Part (get_prefixes($Path)) {
6296            $Include_Neighbors{$LibVersion}{$Part} = $Path;
6297        }
6298    }
6299    if(get_filename($Dir) eq "include")
6300    { # search for "lib/include/" directory
6301        my $LibDir = $Dir;
6302        if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
6303            registerDir($LibDir, $WithDeps, $LibVersion);
6304        }
6305    }
6306}
6307
6308sub parse_redirect($$$)
6309{
6310    my ($Content, $Path, $LibVersion) = @_;
6311    my @Errors = ();
6312    while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
6313        push(@Errors, $1);
6314    }
6315    my $Redirect = "";
6316    foreach (@Errors)
6317    {
6318        s/\s{2,}/ /g;
6319        if(/(only|must\ include
6320        |update\ to\ include
6321        |replaced\ with
6322        |replaced\ by|renamed\ to
6323        |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
6324        {
6325            $Redirect = $2;
6326            last;
6327        }
6328        elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
6329        {
6330            $Redirect = $2;
6331            last;
6332        }
6333        elsif(/this\ header\ should\ not\ be\ used
6334         |programs\ should\ not\ directly\ include
6335         |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
6336         |is\ not\ supported\ API\ for\ general\ use
6337         |do\ not\ use
6338         |should\ not\ be\ (used|using)
6339         |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
6340            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6341        }
6342    }
6343    if($Redirect)
6344    {
6345        $Redirect=~s/\A<//g;
6346        $Redirect=~s/>\Z//g;
6347    }
6348    return $Redirect;
6349}
6350
6351sub parse_includes($$)
6352{
6353    my ($Content, $Path) = @_;
6354    my %Includes = ();
6355    while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m)
6356    { # C/C++: include, Objective C/C++: import directive
6357        my $Header = $2;
6358        my $Method = substr($Header, 0, 1, "");
6359        substr($Header, length($Header)-1, 1, "");
6360        $Header = path_format($Header, $OSgroup);
6361        if($Method eq "\"" or is_abs($Header))
6362        {
6363            if(-e join_P(get_dirname($Path), $Header))
6364            { # relative path exists
6365                $Includes{$Header} = -1;
6366            }
6367            else
6368            { # include "..." that doesn't exist is equal to include <...>
6369                $Includes{$Header} = 2;
6370            }
6371        }
6372        else {
6373            $Includes{$Header} = 1;
6374        }
6375    }
6376    if($ExtraInfo)
6377    {
6378        while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m)
6379        { # FT_FREETYPE_H
6380            $Includes{$2} = 0;
6381        }
6382    }
6383    return \%Includes;
6384}
6385
6386sub ignore_path($)
6387{
6388    my $Path = $_[0];
6389    if($Path=~/\~\Z/)
6390    {# skipping system backup files
6391        return 1;
6392    }
6393    if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
6394    {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
6395        return 1;
6396    }
6397    return 0;
6398}
6399
6400sub sortByWord($$)
6401{
6402    my ($ArrRef, $W) = @_;
6403    return if(length($W)<2);
6404    @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
6405}
6406
6407sub sortHeaders($$)
6408{
6409    my ($H1, $H2) = @_;
6410
6411    $H1=~s/\.[a-z]+\Z//ig;
6412    $H2=~s/\.[a-z]+\Z//ig;
6413
6414    my $Hname1 = get_filename($H1);
6415    my $Hname2 = get_filename($H2);
6416    my $HDir1 = get_dirname($H1);
6417    my $HDir2 = get_dirname($H2);
6418    my $Dirname1 = get_filename($HDir1);
6419    my $Dirname2 = get_filename($HDir2);
6420
6421    $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
6422    $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/;
6423
6424    if($_[0] eq $_[1]
6425    or $H1 eq $H2) {
6426        return 0;
6427    }
6428    elsif($H1=~/\A\Q$H2\E/) {
6429        return 1;
6430    }
6431    elsif($H2=~/\A\Q$H1\E/) {
6432        return -1;
6433    }
6434    elsif($HDir1=~/\Q$Hname1\E/i
6435    and $HDir2!~/\Q$Hname2\E/i)
6436    { # include/glib-2.0/glib.h
6437        return -1;
6438    }
6439    elsif($HDir2=~/\Q$Hname2\E/i
6440    and $HDir1!~/\Q$Hname1\E/i)
6441    { # include/glib-2.0/glib.h
6442        return 1;
6443    }
6444    elsif($Hname1=~/\Q$Dirname1\E/i
6445    and $Hname2!~/\Q$Dirname2\E/i)
6446    { # include/hildon-thumbnail/hildon-thumbnail-factory.h
6447        return -1;
6448    }
6449    elsif($Hname2=~/\Q$Dirname2\E/i
6450    and $Hname1!~/\Q$Dirname1\E/i)
6451    { # include/hildon-thumbnail/hildon-thumbnail-factory.h
6452        return 1;
6453    }
6454    elsif($Hname1=~/(config|lib|util)/i
6455    and $Hname2!~/(config|lib|util)/i)
6456    { # include/alsa/asoundlib.h
6457        return -1;
6458    }
6459    elsif($Hname2=~/(config|lib|util)/i
6460    and $Hname1!~/(config|lib|util)/i)
6461    { # include/alsa/asoundlib.h
6462        return 1;
6463    }
6464    else
6465    {
6466        my $R1 = checkRelevance($H1);
6467        my $R2 = checkRelevance($H2);
6468        if($R1 and not $R2)
6469        { # libebook/e-book.h
6470            return -1;
6471        }
6472        elsif($R2 and not $R1)
6473        { # libebook/e-book.h
6474            return 1;
6475        }
6476        else
6477        {
6478            return (lc($H1) cmp lc($H2));
6479        }
6480    }
6481}
6482
6483sub searchForHeaders($)
6484{
6485    my $LibVersion = $_[0];
6486
6487    # gcc standard include paths
6488    registerGccHeaders();
6489
6490    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
6491    { # c++ standard include paths
6492        registerCppHeaders();
6493    }
6494
6495    # processing header paths
6496    foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}},
6497    @{$Descriptor{$LibVersion}{"AddIncludePaths"}})
6498    {
6499        my $IPath = $Path;
6500        if($SystemRoot)
6501        {
6502            if(is_abs($Path)) {
6503                $Path = $SystemRoot.$Path;
6504            }
6505        }
6506        if(not -e $Path) {
6507            exitStatus("Access_Error", "can't access \'$Path\'");
6508        }
6509        elsif(-f $Path) {
6510            exitStatus("Access_Error", "\'$Path\' - not a directory");
6511        }
6512        elsif(-d $Path)
6513        {
6514            $Path = get_abs_path($Path);
6515            registerDir($Path, 0, $LibVersion);
6516            if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
6517                push(@{$Add_Include_Paths{$LibVersion}}, $Path);
6518            }
6519            else {
6520                push(@{$Include_Paths{$LibVersion}}, $Path);
6521            }
6522        }
6523    }
6524    if(@{$Include_Paths{$LibVersion}}) {
6525        $INC_PATH_AUTODETECT{$LibVersion} = 0;
6526    }
6527
6528    # registering directories
6529    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
6530    {
6531        next if(not -e $Path);
6532        $Path = get_abs_path($Path);
6533        $Path = path_format($Path, $OSgroup);
6534        if(-d $Path) {
6535            registerDir($Path, 1, $LibVersion);
6536        }
6537        elsif(-f $Path)
6538        {
6539            my $Dir = get_dirname($Path);
6540            if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
6541            and not $LocalIncludes{$Dir})
6542            {
6543                registerDir($Dir, 1, $LibVersion);
6544                # if(my $OutDir = get_dirname($Dir))
6545                # { # registering the outer directory
6546                #     if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
6547                #     and not $LocalIncludes{$OutDir}) {
6548                #         registerDir($OutDir, 0, $LibVersion);
6549                #     }
6550                # }
6551            }
6552        }
6553    }
6554
6555    # clean memory
6556    %RegisteredDirs = ();
6557
6558    # registering headers
6559    my $Position = 0;
6560    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
6561    {
6562        if(is_abs($Dest) and not -e $Dest) {
6563            exitStatus("Access_Error", "can't access \'$Dest\'");
6564        }
6565        $Dest = path_format($Dest, $OSgroup);
6566        if(is_header($Dest, 1, $LibVersion))
6567        {
6568            if(my $HPath = registerHeader($Dest, $LibVersion)) {
6569                $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
6570            }
6571        }
6572        elsif(-d $Dest)
6573        {
6574            my @Registered = ();
6575            foreach my $Path (cmd_find($Dest,"f"))
6576            {
6577                next if(ignore_path($Path));
6578                next if(not is_header($Path, 0, $LibVersion));
6579                if(my $HPath = registerHeader($Path, $LibVersion)) {
6580                    push(@Registered, $HPath);
6581                }
6582            }
6583            @Registered = sort {sortHeaders($a, $b)} @Registered;
6584            sortByWord(\@Registered, $TargetLibraryShortName);
6585            foreach my $Path (@Registered) {
6586                $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
6587            }
6588        }
6589        else {
6590            exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
6591        }
6592    }
6593
6594    if(defined $Tolerance and $Tolerance=~/4/)
6595    { # 4 - skip headers included by others
6596        foreach my $Path (keys(%{$Registered_Headers{$LibVersion}}))
6597        {
6598            if(defined $Header_Includes_R{$LibVersion}{$Path}) {
6599                delete($Registered_Headers{$LibVersion}{$Path});
6600            }
6601        }
6602    }
6603
6604    if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
6605    { # preparing preamble headers
6606        foreach my $Header (split(/\s*\n\s*/, $HList))
6607        {
6608            if(is_abs($Header) and not -f $Header) {
6609                exitStatus("Access_Error", "can't access file \'$Header\'");
6610            }
6611            $Header = path_format($Header, $OSgroup);
6612            if(my $Header_Path = is_header($Header, 1, $LibVersion))
6613            {
6614                next if(skipHeader($Header_Path, $LibVersion));
6615                push_U($Include_Preamble{$LibVersion}, $Header_Path);
6616            }
6617            else {
6618                exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
6619            }
6620        }
6621    }
6622    foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
6623    { # set relative paths (for duplicates)
6624        if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
6625        { # search for duplicates
6626            my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
6627            my $Prefix = get_dirname($FirstPath);
6628            while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
6629            { # detect a shortest distinguishing prefix
6630                my $NewPrefix = $1;
6631                my %Identity = ();
6632                foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
6633                {
6634                    if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
6635                        $Identity{$Path} = $1;
6636                    }
6637                }
6638                if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
6639                { # all names are differend with current prefix
6640                    foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
6641                        $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
6642                    }
6643                    last;
6644                }
6645                $Prefix = $NewPrefix; # increase prefix
6646            }
6647        }
6648    }
6649
6650    # clean memory
6651    %HeaderName_Paths = ();
6652
6653    foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
6654    { # ordering headers according to descriptor
6655        my $PairName = $Include_Order{$LibVersion}{$HeaderName};
6656        my ($Pos, $PairPos) = (-1, -1);
6657        my ($Path, $PairPath) = ();
6658        my @Paths = keys(%{$Registered_Headers{$LibVersion}});
6659        @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
6660        foreach my $Header_Path (@Paths)
6661        {
6662            if(get_filename($Header_Path) eq $PairName)
6663            {
6664                $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
6665                $PairPath = $Header_Path;
6666            }
6667            if(get_filename($Header_Path) eq $HeaderName)
6668            {
6669                $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
6670                $Path = $Header_Path;
6671            }
6672        }
6673        if($PairPos!=-1 and $Pos!=-1
6674        and int($PairPos)<int($Pos))
6675        {
6676            my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
6677            %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
6678            %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
6679        }
6680    }
6681    if(not keys(%{$Registered_Headers{$LibVersion}})) {
6682        exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
6683    }
6684}
6685
6686sub detect_real_includes($$)
6687{
6688    my ($AbsPath, $LibVersion) = @_;
6689    return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
6690    if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
6691    or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6692        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6693    }
6694    $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
6695
6696    my $Path = callPreprocessor($AbsPath, "", $LibVersion);
6697    return () if(not $Path);
6698    open(PREPROC, $Path);
6699    while(<PREPROC>)
6700    {
6701        if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
6702        {
6703            my $Include = path_format($1, $OSgroup);
6704            if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
6705                next;
6706            }
6707            if($Include eq $AbsPath) {
6708                next;
6709            }
6710            $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
6711        }
6712    }
6713    close(PREPROC);
6714    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6715}
6716
6717sub detect_header_includes($$)
6718{
6719    my ($Path, $LibVersion) = @_;
6720    return if(not $LibVersion or not $Path);
6721    if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
6722        return;
6723    }
6724    $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
6725
6726    if(not -e $Path) {
6727        return;
6728    }
6729
6730    my $Content = readFile($Path);
6731    if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
6732    { # detect error directive in headers
6733        if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
6734        {
6735            if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
6736                $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
6737            }
6738            if($RedirectPath ne $Path) {
6739                $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6740            }
6741        }
6742        else
6743        { # can't find
6744            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6745        }
6746    }
6747    if(my $Inc = parse_includes($Content, $Path))
6748    {
6749        foreach my $Include (keys(%{$Inc}))
6750        { # detect includes
6751            $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6752
6753            if(defined $Tolerance and $Tolerance=~/4/)
6754            {
6755                if(my $HPath = identifyHeader($Include, $LibVersion))
6756                {
6757                    $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1;
6758                }
6759            }
6760        }
6761    }
6762}
6763
6764sub fromLibc($)
6765{ # system GLIBC header
6766    my $Path = $_[0];
6767    my ($Dir, $Name) = separate_path($Path);
6768    if($OStarget eq "symbian")
6769    {
6770        if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name})
6771        { # epoc32/include/libc/{stdio, ...}.h
6772            return 1;
6773        }
6774    }
6775    else
6776    {
6777        if($Dir eq "/usr/include" and $GlibcHeader{$Name})
6778        { # /usr/include/{stdio, ...}.h
6779            return 1;
6780        }
6781    }
6782    return 0;
6783}
6784
6785sub isLibcDir($)
6786{ # system GLIBC directory
6787    my $Dir = $_[0];
6788    my ($OutDir, $Name) = separate_path($Dir);
6789    if($OStarget eq "symbian")
6790    {
6791        if(get_filename($OutDir) eq "libc"
6792        and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6793        { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h
6794            return 1;
6795        }
6796    }
6797    else
6798    { # linux
6799        if($OutDir eq "/usr/include"
6800        and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6801        { # /usr/include/{sys,bits,asm,asm-*}/*.h
6802            return 1;
6803        }
6804    }
6805    return 0;
6806}
6807
6808sub detect_recursive_includes($$)
6809{
6810    my ($AbsPath, $LibVersion) = @_;
6811    return () if(not $AbsPath);
6812    if(isCyclical(\@RecurInclude, $AbsPath)) {
6813        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6814    }
6815    my ($AbsDir, $Name) = separate_path($AbsPath);
6816    if(isLibcDir($AbsDir))
6817    { # system GLIBC internals
6818        return () if(not $ExtraInfo);
6819    }
6820    if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6821        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6822    }
6823    return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6824
6825    if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING)
6826    { # skip /usr/include/c++/*/ headers
6827        return () if(not $ExtraInfo);
6828    }
6829
6830    push(@RecurInclude, $AbsPath);
6831    if(grep { $AbsDir eq $_ } @DefaultGccPaths
6832    or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath)))
6833    { # check "real" (non-"model") include paths
6834        my @Paths = detect_real_includes($AbsPath, $LibVersion);
6835        pop(@RecurInclude);
6836        return @Paths;
6837    }
6838    if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6839        detect_header_includes($AbsPath, $LibVersion);
6840    }
6841    foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6842    {
6843        my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
6844        my $HPath = "";
6845        if($IncType<0)
6846        { # for #include "..."
6847            my $Candidate = join_P($AbsDir, $Include);
6848            if(-f $Candidate) {
6849                $HPath = realpath($Candidate);
6850            }
6851        }
6852        elsif($IncType>0
6853        and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
6854        { # search for the nearest header
6855          # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6856            my $Candidate = join_P(get_dirname($AbsDir), $Include);
6857            if(-f $Candidate) {
6858                $HPath = $Candidate;
6859            }
6860        }
6861        if(not $HPath) {
6862            $HPath = identifyHeader($Include, $LibVersion);
6863        }
6864        next if(not $HPath);
6865        if($HPath eq $AbsPath) {
6866            next;
6867        }
6868
6869        if($Debug)
6870        { # boundary headers
6871#             if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6872#             {
6873#                 print STDERR "$AbsPath -> $HPath\n";
6874#             }
6875        }
6876
6877        $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6878        if($IncType>0)
6879        { # only include <...>, skip include "..." prefixes
6880            $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6881        }
6882        foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6883        {
6884            if($IncPath eq $AbsPath) {
6885                next;
6886            }
6887            my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6888            if($RIncType==-1)
6889            { # include "..."
6890                $RIncType = $IncType;
6891            }
6892            elsif($RIncType==2)
6893            {
6894                if($IncType!=-1) {
6895                    $RIncType = $IncType;
6896                }
6897            }
6898            $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
6899            foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6900                $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6901            }
6902        }
6903        foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6904        {
6905            if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6906            and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6907            { # distinguish math.h from glibc and math.h from the tested library
6908                delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6909                last;
6910            }
6911        }
6912    }
6913    pop(@RecurInclude);
6914    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6915}
6916
6917sub find_in_framework($$$)
6918{
6919    my ($Header, $Framework, $LibVersion) = @_;
6920    return "" if(not $Header or not $Framework or not $LibVersion);
6921    if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6922        return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6923    }
6924    foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6925    {
6926        if(get_filename($Dependency) eq $Framework
6927        and -f get_dirname($Dependency)."/".$Header) {
6928            return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6929        }
6930    }
6931    return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6932}
6933
6934sub find_in_defaults($)
6935{
6936    my $Header = $_[0];
6937    return "" if(not $Header);
6938    if(defined $Cache{"find_in_defaults"}{$Header}) {
6939        return $Cache{"find_in_defaults"}{$Header};
6940    }
6941    foreach my $Dir (@DefaultIncPaths,
6942                     @DefaultGccPaths,
6943                     @DefaultCppPaths,
6944                     @UsersIncPath)
6945    {
6946        next if(not $Dir);
6947        if(-f $Dir."/".$Header) {
6948            return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6949        }
6950    }
6951    return ($Cache{"find_in_defaults"}{$Header}="");
6952}
6953
6954sub cmp_paths($$)
6955{
6956    my ($Path1, $Path2) = @_;
6957    my @Parts1 = split(/[\/\\]/, $Path1);
6958    my @Parts2 = split(/[\/\\]/, $Path2);
6959    foreach my $Num (0 .. $#Parts1)
6960    {
6961        my $Part1 = $Parts1[$Num];
6962        my $Part2 = $Parts2[$Num];
6963        if($GlibcDir{$Part1}
6964        and not $GlibcDir{$Part2}) {
6965            return 1;
6966        }
6967        elsif($GlibcDir{$Part2}
6968        and not $GlibcDir{$Part1}) {
6969            return -1;
6970        }
6971        elsif($Part1=~/glib/
6972        and $Part2!~/glib/) {
6973            return 1;
6974        }
6975        elsif($Part1!~/glib/
6976        and $Part2=~/glib/) {
6977            return -1;
6978        }
6979        elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6980            return $CmpRes;
6981        }
6982    }
6983    return 0;
6984}
6985
6986sub checkRelevance($)
6987{
6988    my $Path = $_[0];
6989    return 0 if(not $Path);
6990
6991    if($SystemRoot) {
6992        $Path = cut_path_prefix($Path, $SystemRoot);
6993    }
6994
6995    my $Name = lc(get_filename($Path));
6996    my $Dir = lc(get_dirname($Path));
6997
6998    $Name=~s/\.\w+\Z//g; # remove extension (.h)
6999
7000    foreach my $Token (split(/[_\d\W]+/, $Name))
7001    {
7002        my $Len = length($Token);
7003        next if($Len<=1);
7004        if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/)
7005        { # include/evolution-data-server-1.4/libebook/e-book.h
7006            return 1;
7007        }
7008        if($Len>=4 and index($Dir, $Token)!=-1)
7009        { # include/gupnp-1.0/libgupnp/gupnp-context.h
7010            return 1;
7011        }
7012    }
7013    return 0;
7014}
7015
7016sub checkFamily(@)
7017{
7018    my @Paths = @_;
7019    return 1 if($#Paths<=0);
7020    my %Prefix = ();
7021    foreach my $Path (@Paths)
7022    {
7023        if($SystemRoot) {
7024            $Path = cut_path_prefix($Path, $SystemRoot);
7025        }
7026        if(my $Dir = get_dirname($Path))
7027        {
7028            $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
7029            $Prefix{$Dir} += 1;
7030            $Prefix{get_dirname($Dir)} += 1;
7031        }
7032    }
7033    foreach (sort keys(%Prefix))
7034    {
7035        if(get_depth($_)>=3
7036        and $Prefix{$_}==$#Paths+1) {
7037            return 1;
7038        }
7039    }
7040    return 0;
7041}
7042
7043sub isAcceptable($$$)
7044{
7045    my ($Header, $Candidate, $LibVersion) = @_;
7046    my $HName = get_filename($Header);
7047    if(get_dirname($Header))
7048    { # with prefix
7049        return 1;
7050    }
7051    if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
7052    { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
7053        return 1;
7054    }
7055    if(checkRelevance($Candidate))
7056    { # allow to search for atk.h in /usr/include/atk-1.0/atk/
7057        return 1;
7058    }
7059    if(checkFamily(getSystemHeaders($HName, $LibVersion)))
7060    { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
7061      # /usr/include/qt4/Qt/qsslconfiguration.h
7062        return 1;
7063    }
7064    if($OStarget eq "symbian")
7065    {
7066        if($Candidate=~/[\/\\]stdapis[\/\\]/) {
7067            return 1;
7068        }
7069    }
7070    return 0;
7071}
7072
7073sub isRelevant($$$)
7074{ # disallow to search for "abstract" headers in too deep directories
7075    my ($Header, $Candidate, $LibVersion) = @_;
7076    my $HName = get_filename($Header);
7077    if($OStarget eq "symbian")
7078    {
7079        if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
7080            return 0;
7081        }
7082    }
7083    if($OStarget ne "bsd")
7084    {
7085        if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
7086        { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
7087            return 0;
7088        }
7089    }
7090    if($OStarget ne "windows")
7091    {
7092        if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
7093        { # skip /usr/include/wine/msvcrt
7094            return 0;
7095        }
7096    }
7097    if(not get_dirname($Header)
7098    and $Candidate=~/[\/\\]wx[\/\\]/)
7099    { # do NOT search in system /wx/ directory
7100      # for headers without a prefix: sstream.h
7101        return 0;
7102    }
7103    if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
7104    and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
7105    { # skip ../c++/3.3.3/ if using ../c++/4.5/
7106        return 0;
7107    }
7108    if($Candidate=~/[\/\\]asm-/
7109    and (my $Arch = getArch($LibVersion)) ne "unknown")
7110    { # arch-specific header files
7111        if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
7112        {# skip ../asm-arm/ if using x86 architecture
7113            return 0;
7114        }
7115    }
7116    my @Candidates = getSystemHeaders($HName, $LibVersion);
7117    if($#Candidates==1)
7118    { # unique header
7119        return 1;
7120    }
7121    my @SCandidates = getSystemHeaders($Header, $LibVersion);
7122    if($#SCandidates==1)
7123    { # unique name
7124        return 1;
7125    }
7126    my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
7127    if(get_depth($Candidate)-$SystemDepth>=5)
7128    { # abstract headers in too deep directories
7129      # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
7130        if(not isAcceptable($Header, $Candidate, $LibVersion)) {
7131            return 0;
7132        }
7133    }
7134    if($Header eq "parser.h"
7135    and $Candidate!~/\/libxml2\//)
7136    { # select parser.h from xml2 library
7137        return 0;
7138    }
7139    if(not get_dirname($Header)
7140    and keys(%{$SystemHeaders{$HName}})>=3)
7141    { # many headers with the same name
7142      # like thread.h included without a prefix
7143        if(not checkFamily(@Candidates)) {
7144            return 0;
7145        }
7146    }
7147    return 1;
7148}
7149
7150sub selectSystemHeader($$)
7151{ # cache function
7152    if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
7153        return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
7154    }
7155    return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
7156}
7157
7158sub selectSystemHeader_I($$)
7159{
7160    my ($Header, $LibVersion) = @_;
7161    if(-f $Header) {
7162        return $Header;
7163    }
7164    if(is_abs($Header) and not -f $Header)
7165    { # incorrect absolute path
7166        return "";
7167    }
7168    if(defined $ConfHeaders{lc($Header)})
7169    { # too abstract configuration headers
7170        return "";
7171    }
7172    my $HName = get_filename($Header);
7173    if($OSgroup ne "windows")
7174    {
7175        if(defined $WinHeaders{lc($HName)}
7176        or $HName=~/windows|win32|win64/i)
7177        { # windows headers
7178            return "";
7179        }
7180    }
7181    if($OSgroup ne "macos")
7182    {
7183        if($HName eq "fp.h")
7184        { # pngconf.h includes fp.h in Mac OS
7185            return "";
7186        }
7187    }
7188
7189    if(defined $ObsoleteHeaders{$HName})
7190    { # obsolete headers
7191        return "";
7192    }
7193    if($OSgroup eq "linux" or $OSgroup eq "bsd")
7194    {
7195        if(defined $AlienHeaders{$HName}
7196        or defined $AlienHeaders{$Header})
7197        { # alien headers from other systems
7198            return "";
7199        }
7200    }
7201
7202    foreach my $Path (@{$SystemPaths{"include"}})
7203    { # search in default paths
7204        if(-f $Path."/".$Header) {
7205            return join_P($Path,$Header);
7206        }
7207    }
7208    if(not defined $Cache{"checkSystemFiles"})
7209    { # register all headers in system include dirs
7210        checkSystemFiles();
7211    }
7212    foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
7213    sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
7214    {
7215        if(isRelevant($Header, $Candidate, $LibVersion)) {
7216            return $Candidate;
7217        }
7218    }
7219    # error
7220    return "";
7221}
7222
7223sub getSystemHeaders($$)
7224{
7225    my ($Header, $LibVersion) = @_;
7226    my @Candidates = ();
7227    foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
7228    {
7229        if(skipHeader($Candidate, $LibVersion)) {
7230            next;
7231        }
7232        push(@Candidates, $Candidate);
7233    }
7234    return @Candidates;
7235}
7236
7237sub cut_path_prefix($$)
7238{
7239    my ($Path, $Prefix) = @_;
7240    return $Path if(not $Prefix);
7241    $Prefix=~s/[\/\\]+\Z//;
7242    $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
7243    return $Path;
7244}
7245
7246sub is_default_include_dir($)
7247{
7248    my $Dir = $_[0];
7249    $Dir=~s/[\/\\]+\Z//;
7250    return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths);
7251}
7252
7253sub identifyHeader($$)
7254{ # cache function
7255    my ($Header, $LibVersion) = @_;
7256    if(not $Header) {
7257        return "";
7258    }
7259    $Header=~s/\A(\.\.[\\\/])+//g;
7260    if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
7261        return $Cache{"identifyHeader"}{$LibVersion}{$Header};
7262    }
7263    return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
7264}
7265
7266sub identifyHeader_I($$)
7267{ # search for header by absolute path, relative path or name
7268    my ($Header, $LibVersion) = @_;
7269    if(-f $Header)
7270    { # it's relative or absolute path
7271        return get_abs_path($Header);
7272    }
7273    elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
7274    and my $HeaderDir = find_in_defaults($Header))
7275    { # search for libc headers in the /usr/include
7276      # for non-libc target library before searching
7277      # in the library paths
7278        return join_P($HeaderDir,$Header);
7279    }
7280    elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
7281    { # search in the target library paths
7282        return $Path;
7283    }
7284    elsif(defined $DefaultGccHeader{$Header})
7285    { # search in the internal GCC include paths
7286        return $DefaultGccHeader{$Header};
7287    }
7288    elsif(my $DefaultDir = find_in_defaults($Header))
7289    { # search in the default GCC include paths
7290        return join_P($DefaultDir,$Header);
7291    }
7292    elsif(defined $DefaultCppHeader{$Header})
7293    { # search in the default G++ include paths
7294        return $DefaultCppHeader{$Header};
7295    }
7296    elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
7297    { # search everywhere in the system
7298        return $AnyPath;
7299    }
7300    elsif($OSgroup eq "macos")
7301    { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
7302        if(my $Dir = get_dirname($Header))
7303        {
7304            my $RelPath = "Headers\/".get_filename($Header);
7305            if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
7306                return join_P($HeaderDir, $RelPath);
7307            }
7308        }
7309    }
7310    # cannot find anything
7311    return "";
7312}
7313
7314sub getLocation($)
7315{
7316    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7317    {
7318        if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
7319            return (path_format($1, $OSgroup), $2);
7320        }
7321    }
7322    return ();
7323}
7324
7325sub getNameByInfo($)
7326{
7327    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7328    {
7329        if($Info=~/name[ ]*:[ ]*@(\d+) /)
7330        {
7331            if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
7332            {
7333                if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
7334                { # short unsigned int (may include spaces)
7335                    my $Str = $1;
7336                    if($CppMode{$Version}
7337                    and $Str=~/\Ac99_(.+)\Z/)
7338                    {
7339                        if($CppKeywords_A{$1}) {
7340                            $Str=$1;
7341                        }
7342                    }
7343                    return $Str;
7344                }
7345            }
7346        }
7347    }
7348    return "";
7349}
7350
7351sub getTreeStr($)
7352{
7353    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7354    {
7355        if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
7356        {
7357            my $Str = $1;
7358            if($CppMode{$Version}
7359            and $Str=~/\Ac99_(.+)\Z/)
7360            {
7361                if($CppKeywords_A{$1}) {
7362                    $Str=$1;
7363                }
7364            }
7365            return $Str;
7366        }
7367    }
7368    return "";
7369}
7370
7371sub getFuncShortName($)
7372{
7373    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7374    {
7375        if(index($Info, " operator ")!=-1)
7376        {
7377            if(index($Info, " conversion ")!=-1)
7378            {
7379                if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
7380                {
7381                    if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
7382                        return "operator ".$RName;
7383                    }
7384                }
7385            }
7386            else
7387            {
7388                if($Info=~/ operator[ ]+([a-zA-Z]+) /)
7389                {
7390                    if(my $Ind = $Operator_Indication{$1}) {
7391                        return "operator".$Ind;
7392                    }
7393                    elsif(not $UnknownOperator{$1})
7394                    {
7395                        printMsg("WARNING", "unknown operator $1");
7396                        $UnknownOperator{$1} = 1;
7397                    }
7398                }
7399            }
7400        }
7401        else
7402        {
7403            if($Info=~/name[ ]*:[ ]*@(\d+) /) {
7404                return getTreeStr($1);
7405            }
7406        }
7407    }
7408    return "";
7409}
7410
7411sub getFuncReturn($)
7412{
7413    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7414    {
7415        if($Info=~/type[ ]*:[ ]*@(\d+) /)
7416        {
7417            if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
7418                return $1;
7419            }
7420        }
7421    }
7422    return "";
7423}
7424
7425sub getFuncOrig($)
7426{
7427    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7428    {
7429        if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
7430            return $1;
7431        }
7432    }
7433    return $_[0];
7434}
7435
7436sub unmangleArray(@)
7437{
7438    if($_[0]=~/\A\?/)
7439    { # MSVC mangling
7440        my $UndNameCmd = get_CmdPath("undname");
7441        if(not $UndNameCmd) {
7442            exitStatus("Not_Found", "can't find \"undname\"");
7443        }
7444        writeFile("$TMP_DIR/unmangle", join("\n", @_));
7445        return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
7446    }
7447    else
7448    { # GCC mangling
7449        my $CppFiltCmd = get_CmdPath("c++filt");
7450        if(not $CppFiltCmd) {
7451            exitStatus("Not_Found", "can't find c++filt in PATH");
7452        }
7453        if(not defined $CPPFILT_SUPPORT_FILE)
7454        {
7455            my $Info = `$CppFiltCmd -h 2>&1`;
7456            $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
7457        }
7458        my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":"";
7459        if($CPPFILT_SUPPORT_FILE)
7460        { # new versions of c++filt can take a file
7461            if($#_>$MAX_CPPFILT_FILE_SIZE)
7462            { # c++filt <= 2.22 may crash on large files (larger than 8mb)
7463              # this is fixed in the oncoming version of Binutils
7464                my @Half = splice(@_, 0, ($#_+1)/2);
7465                return (unmangleArray(@Half), unmangleArray(@_))
7466            }
7467            else
7468            {
7469                writeFile("$TMP_DIR/unmangle", join("\n", @_));
7470                my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
7471                if($?==139)
7472                { # segmentation fault
7473                    printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
7474                }
7475                return split(/\n/, $Res);
7476            }
7477        }
7478        else
7479        { # old-style unmangling
7480            if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
7481            {
7482                my @Half = splice(@_, 0, ($#_+1)/2);
7483                return (unmangleArray(@Half), unmangleArray(@_))
7484            }
7485            else
7486            {
7487                my $Strings = join(" ", @_);
7488                my $Res = `$CppFiltCmd $NoStrip $Strings`;
7489                if($?==139)
7490                { # segmentation fault
7491                    printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
7492                }
7493                return split(/\n/, $Res);
7494            }
7495        }
7496    }
7497}
7498
7499sub get_SignatureNoInfo($$)
7500{
7501    my ($Symbol, $LibVersion) = @_;
7502    if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
7503        return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
7504    }
7505    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
7506    my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
7507    if($Symbol=~/\A(_Z|\?)/)
7508    { # C++
7509        # some standard typedefs
7510        $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
7511        $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;
7512    }
7513    if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
7514    { # ELF format marks data as OBJECT
7515        if($GlobalDataObject{$LibVersion}{$Symbol}) {
7516            $Signature .= " [data]";
7517        }
7518        elsif($Symbol!~/\A(_Z|\?)/) {
7519            $Signature .= " (...)";
7520        }
7521    }
7522    if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
7523    {
7524        my $ShortName = substr($Signature, 0, find_center($Signature, "("));
7525        $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
7526    }
7527    if($SymbolVersion) {
7528        $Signature .= $VersionSpec.$SymbolVersion;
7529    }
7530    return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
7531}
7532
7533sub get_ChargeLevel($$)
7534{
7535    my ($Symbol, $LibVersion) = @_;
7536    return "" if($Symbol!~/\A(_Z|\?)/);
7537    if(defined $CompleteSignature{$LibVersion}{$Symbol}
7538    and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
7539    {
7540        if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
7541        {
7542            if($Symbol=~/C1[EI]/) {
7543                return "[in-charge]";
7544            }
7545            elsif($Symbol=~/C2[EI]/) {
7546                return "[not-in-charge]";
7547            }
7548        }
7549        elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
7550        {
7551            if($Symbol=~/D1[EI]/) {
7552                return "[in-charge]";
7553            }
7554            elsif($Symbol=~/D2[EI]/) {
7555                return "[not-in-charge]";
7556            }
7557            elsif($Symbol=~/D0[EI]/) {
7558                return "[in-charge-deleting]";
7559            }
7560        }
7561    }
7562    else
7563    {
7564        if($Symbol=~/C1[EI]/) {
7565            return "[in-charge]";
7566        }
7567        elsif($Symbol=~/C2[EI]/) {
7568            return "[not-in-charge]";
7569        }
7570        elsif($Symbol=~/D1[EI]/) {
7571            return "[in-charge]";
7572        }
7573        elsif($Symbol=~/D2[EI]/) {
7574            return "[not-in-charge]";
7575        }
7576        elsif($Symbol=~/D0[EI]/) {
7577            return "[in-charge-deleting]";
7578        }
7579    }
7580    return "";
7581}
7582
7583sub get_Signature_M($$)
7584{
7585    my ($Symbol, $LibVersion) = @_;
7586    my $Signature_M = $tr_name{$Symbol};
7587    if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
7588    { # add return type name
7589        $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
7590    }
7591    return $Signature_M;
7592}
7593
7594sub get_Signature($$)
7595{
7596    my ($Symbol, $LibVersion) = @_;
7597    if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
7598        return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
7599    }
7600    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
7601    if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
7602    { # non-public global data
7603        return get_SignatureNoInfo($Symbol, $LibVersion);
7604    }
7605    my ($Signature, @Param_Types_FromUnmangledName) = ();
7606    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
7607    if($Symbol=~/\A(_Z|\?)/)
7608    {
7609        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
7610        {
7611            $Signature .= $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::";
7612            if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) {
7613                $Signature .= "~";
7614            }
7615            $Signature .= $ShortName;
7616        }
7617        elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
7618            $Signature .= $NameSpace."::".$ShortName;
7619        }
7620        else {
7621            $Signature .= $ShortName;
7622        }
7623        my ($Short, $Params) = split_Signature($tr_name{$MnglName});
7624        @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
7625    }
7626    else
7627    {
7628        $Signature .= $MnglName;
7629    }
7630    my @ParamArray = ();
7631    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
7632    {
7633        next if($Pos eq "");
7634        my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
7635        next if(not $ParamTypeId);
7636        my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
7637        if(not $ParamTypeName) {
7638            $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
7639        }
7640        foreach my $Typedef (keys(%ChangedTypedef))
7641        {
7642            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
7643                $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
7644            }
7645        }
7646        if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"})
7647        {
7648            if($ParamName eq "this"
7649            and $Symbol=~/\A(_Z|\?)/)
7650            { # do NOT show first hidded "this"-parameter
7651                next;
7652            }
7653            push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
7654        }
7655        else {
7656            push(@ParamArray, $ParamTypeName);
7657        }
7658    }
7659    if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
7660    or $GlobalDataObject{$LibVersion}{$Symbol}) {
7661        $Signature .= " [data]";
7662    }
7663    else
7664    {
7665        if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
7666        { # add [in-charge]
7667            $Signature .= " ".$ChargeLevel;
7668        }
7669        $Signature .= " (".join(", ", @ParamArray).")";
7670        if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
7671        or $Symbol=~/\A_ZN(V|)K/) {
7672            $Signature .= " const";
7673        }
7674        if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
7675        or $Symbol=~/\A_ZN(K|)V/) {
7676            $Signature .= " volatile";
7677        }
7678        if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
7679        and $Symbol=~/\A(_Z|\?)/)
7680        { # for static methods
7681            $Signature .= " [static]";
7682        }
7683    }
7684    if(defined $ShowRetVal
7685    and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
7686        $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
7687    }
7688    if($SymbolVersion) {
7689        $Signature .= $VersionSpec.$SymbolVersion;
7690    }
7691    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature);
7692}
7693
7694sub create_member_decl($$)
7695{
7696    my ($TName, $Member) = @_;
7697    if($TName=~/\([\*]+\)/)
7698    {
7699        $TName=~s/\(([\*]+)\)/\($1$Member\)/;
7700        return $TName;
7701    }
7702    else
7703    {
7704        my @ArraySizes = ();
7705        while($TName=~s/(\[[^\[\]]*\])\Z//) {
7706            push(@ArraySizes, $1);
7707        }
7708        return $TName." ".$Member.join("", @ArraySizes);
7709    }
7710}
7711
7712sub getFuncType($)
7713{
7714    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7715    {
7716        if($Info=~/type[ ]*:[ ]*@(\d+) /)
7717        {
7718            if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
7719            {
7720                if($Type eq "method_type") {
7721                    return "Method";
7722                }
7723                elsif($Type eq "function_type") {
7724                    return "Function";
7725                }
7726                else {
7727                    return "Other";
7728                }
7729            }
7730        }
7731    }
7732    return "";
7733}
7734
7735sub getFuncTypeId($)
7736{
7737    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7738    {
7739        if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
7740            return $1;
7741        }
7742    }
7743    return 0;
7744}
7745
7746sub isAnon($)
7747{ # "._N" or "$_N" in older GCC versions
7748    return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
7749}
7750
7751sub formatName($$)
7752{ # type name correction
7753    if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
7754        return $Cache{"formatName"}{$_[1]}{$_[0]};
7755    }
7756
7757    my $N = $_[0];
7758
7759    if($_[1] ne "S")
7760    {
7761        $N=~s/\A[ ]+//g;
7762        $N=~s/[ ]+\Z//g;
7763        $N=~s/[ ]{2,}/ /g;
7764    }
7765
7766    $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
7767
7768    $N=~s/\bvolatile const\b/const volatile/g;
7769
7770    $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7771    $N=~s/\b(short|long) int\b/$1/g;
7772
7773    $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
7774
7775    while($N=~s/>>/> >/g) {};
7776
7777    if($_[1] eq "S")
7778    {
7779        if(index($N, "operator")!=-1) {
7780            $N=~s/\b(operator[ ]*)> >/$1>>/;
7781        }
7782    }
7783
7784    return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
7785}
7786
7787sub get_HeaderDeps($$)
7788{
7789    my ($AbsPath, $LibVersion) = @_;
7790    return () if(not $AbsPath or not $LibVersion);
7791    if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7792        return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7793    }
7794    my %IncDir = ();
7795    detect_recursive_includes($AbsPath, $LibVersion);
7796    foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7797    {
7798        next if(not $HeaderPath);
7799        next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7800        my $Dir = get_dirname($HeaderPath);
7801        foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7802        {
7803            my $Dep = $Dir;
7804            if($Prefix)
7805            {
7806                if($OSgroup eq "windows")
7807                { # case insensitive seach on windows
7808                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7809                        next;
7810                    }
7811                }
7812                elsif($OSgroup eq "macos")
7813                { # seach in frameworks
7814                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7815                    {
7816                        if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7817                        {# frameworks
7818                            my ($HFramework, $HName) = ($1, $2);
7819                            $Dep = $HFramework;
7820                        }
7821                        else
7822                        {# mismatch
7823                            next;
7824                        }
7825                    }
7826                }
7827                elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7828                { # Linux, FreeBSD
7829                    next;
7830                }
7831            }
7832            if(not $Dep)
7833            { # nothing to include
7834                next;
7835            }
7836            if(is_default_include_dir($Dep))
7837            { # included by the compiler
7838                next;
7839            }
7840            if(get_depth($Dep)==1)
7841            { # too short
7842                next;
7843            }
7844            if(isLibcDir($Dep))
7845            { # do NOT include /usr/include/{sys,bits}
7846                next;
7847            }
7848            $IncDir{$Dep} = 1;
7849        }
7850    }
7851    $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7852    return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7853}
7854
7855sub sortIncPaths($$)
7856{
7857    my ($ArrRef, $LibVersion) = @_;
7858    if(not $ArrRef or $#{$ArrRef}<0) {
7859        return $ArrRef;
7860    }
7861    @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7862    @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
7863    @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
7864    return $ArrRef;
7865}
7866
7867sub sortDeps($$$)
7868{
7869    if($Header_Dependency{$_[2]}{$_[0]}
7870    and not $Header_Dependency{$_[2]}{$_[1]}) {
7871        return 1;
7872    }
7873    elsif(not $Header_Dependency{$_[2]}{$_[0]}
7874    and $Header_Dependency{$_[2]}{$_[1]}) {
7875        return -1;
7876    }
7877    return 0;
7878}
7879
7880sub join_P($$)
7881{
7882    my $S = "/";
7883    if($OSgroup eq "windows") {
7884        $S = "\\";
7885    }
7886    return join($S, @_);
7887}
7888
7889sub get_namespace_additions($)
7890{
7891    my $NameSpaces = $_[0];
7892    my ($Additions, $AddNameSpaceId) = ("", 1);
7893    foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7894    {
7895        next if($SkipNameSpaces{$Version}{$NS});
7896        next if(not $NS or $NameSpaces->{$NS}==-1);
7897        next if($NS=~/(\A|::)iterator(::|\Z)/i);
7898        next if($NS=~/\A__/i);
7899        next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
7900        $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
7901        my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7902        my @NS_Parts = split(/::/, $NS);
7903        next if($#NS_Parts==-1);
7904        next if($NS_Parts[0]=~/\A(random|or)\Z/);
7905        foreach my $NS_Part (@NS_Parts)
7906        {
7907            $TypeDecl_Prefix .= "namespace $NS_Part\{";
7908            $TypeDecl_Suffix .= "}";
7909        }
7910        my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix;
7911        my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7912        $Additions.="  $TypeDecl\n  $FuncDecl\n";
7913        $AddNameSpaceId+=1;
7914    }
7915    return $Additions;
7916}
7917
7918sub path_format($$)
7919{
7920    my ($Path, $Fmt) = @_;
7921    $Path=~s/[\/\\]+\.?\Z//g;
7922    if($Fmt eq "windows")
7923    {
7924        $Path=~s/\//\\/g;
7925        $Path=lc($Path);
7926    }
7927    else
7928    { # forward slash to pass into MinGW GCC
7929        $Path=~s/\\/\//g;
7930    }
7931    return $Path;
7932}
7933
7934sub inc_opt($$)
7935{
7936    my ($Path, $Style) = @_;
7937    if($Style eq "GCC")
7938    { # GCC options
7939        if($OSgroup eq "windows")
7940        { # to MinGW GCC
7941            return "-I\"".path_format($Path, "unix")."\"";
7942        }
7943        elsif($OSgroup eq "macos"
7944        and $Path=~/\.framework\Z/)
7945        { # to Apple's GCC
7946            return "-F".esc(get_dirname($Path));
7947        }
7948        else {
7949            return "-I".esc($Path);
7950        }
7951    }
7952    elsif($Style eq "CL") {
7953        return "/I \"".$Path."\"";
7954    }
7955    return "";
7956}
7957
7958sub platformSpecs($)
7959{
7960    my $LibVersion = $_[0];
7961    my $Arch = getArch($LibVersion);
7962    if($OStarget eq "symbian")
7963    { # options for GCCE compiler
7964        my %Symbian_Opts = map {$_=>1} (
7965            "-D__GCCE__",
7966            "-DUNICODE",
7967            "-fexceptions",
7968            "-D__SYMBIAN32__",
7969            "-D__MARM_INTERWORK__",
7970            "-D_UNICODE",
7971            "-D__S60_50__",
7972            "-D__S60_3X__",
7973            "-D__SERIES60_3X__",
7974            "-D__EPOC32__",
7975            "-D__MARM__",
7976            "-D__EABI__",
7977            "-D__MARM_ARMV5__",
7978            "-D__SUPPORT_CPP_EXCEPTIONS__",
7979            "-march=armv5t",
7980            "-mapcs",
7981            "-mthumb-interwork",
7982            "-DEKA2",
7983            "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7984        );
7985        return join(" ", keys(%Symbian_Opts));
7986    }
7987    elsif($OSgroup eq "windows"
7988    and get_dumpmachine($GCC_PATH)=~/mingw/i)
7989    { # add options to MinGW compiler
7990      # to simulate the MSVC compiler
7991        my %MinGW_Opts = map {$_=>1} (
7992            "-D_WIN32",
7993            "-D_STDCALL_SUPPORTED",
7994            "-D__int64=\"long long\"",
7995            "-D__int32=int",
7996            "-D__int16=short",
7997            "-D__int8=char",
7998            "-D__possibly_notnullterminated=\" \"",
7999            "-D__nullterminated=\" \"",
8000            "-D__nullnullterminated=\" \"",
8001            "-D__w64=\" \"",
8002            "-D__ptr32=\" \"",
8003            "-D__ptr64=\" \"",
8004            "-D__forceinline=inline",
8005            "-D__inline=inline",
8006            "-D__uuidof(x)=IID()",
8007            "-D__try=",
8008            "-D__except(x)=",
8009            "-D__declspec(x)=__attribute__((x))",
8010            "-D__pragma(x)=",
8011            "-D_inline=inline",
8012            "-D__forceinline=__inline",
8013            "-D__stdcall=__attribute__((__stdcall__))",
8014            "-D__cdecl=__attribute__((__cdecl__))",
8015            "-D__fastcall=__attribute__((__fastcall__))",
8016            "-D__thiscall=__attribute__((__thiscall__))",
8017            "-D_stdcall=__attribute__((__stdcall__))",
8018            "-D_cdecl=__attribute__((__cdecl__))",
8019            "-D_fastcall=__attribute__((__fastcall__))",
8020            "-D_thiscall=__attribute__((__thiscall__))",
8021            "-DSHSTDAPI_(x)=x",
8022            "-D_MSC_EXTENSIONS",
8023            "-DSECURITY_WIN32",
8024            "-D_MSC_VER=1500",
8025            "-D_USE_DECLSPECS_FOR_SAL",
8026            "-D__noop=\" \"",
8027            "-DDECLSPEC_DEPRECATED=\" \"",
8028            "-D__builtin_alignof(x)=__alignof__(x)",
8029            "-DSORTPP_PASS");
8030        if($Arch eq "x86") {
8031            $MinGW_Opts{"-D_M_IX86=300"}=1;
8032        }
8033        elsif($Arch eq "x86_64") {
8034            $MinGW_Opts{"-D_M_AMD64=300"}=1;
8035        }
8036        elsif($Arch eq "ia64") {
8037            $MinGW_Opts{"-D_M_IA64=300"}=1;
8038        }
8039        return join(" ", keys(%MinGW_Opts));
8040    }
8041    return "";
8042}
8043
8044my %C_Structure = map {$_=>1} (
8045# FIXME: Can't separate union and struct data types before dumping,
8046# so it sometimes cause compilation errors for unknown reason
8047# when trying to declare TYPE* tmp_add_class_N
8048# This is a list of such structures + list of other C structures
8049    "sigval",
8050    "sigevent",
8051    "sigaction",
8052    "sigvec",
8053    "sigstack",
8054    "timeval",
8055    "timezone",
8056    "rusage",
8057    "rlimit",
8058    "wait",
8059    "flock",
8060    "stat",
8061    "_stat",
8062    "stat32",
8063    "_stat32",
8064    "stat64",
8065    "_stat64",
8066    "_stati64",
8067    "if_nameindex",
8068    "usb_device",
8069    "sigaltstack",
8070    "sysinfo",
8071    "timeLocale",
8072    "tcp_debug",
8073    "rpc_createerr",
8074 # Other
8075    "timespec",
8076    "random_data",
8077    "drand48_data",
8078    "_IO_marker",
8079    "_IO_FILE",
8080    "lconv",
8081    "sched_param",
8082    "tm",
8083    "itimerspec",
8084    "_pthread_cleanup_buffer",
8085    "fd_set",
8086    "siginfo",
8087    "mallinfo",
8088    "timex",
8089    "sigcontext",
8090    "ucontext",
8091 # Mac
8092    "_timex",
8093    "_class_t",
8094    "_category_t",
8095    "_class_ro_t",
8096    "_protocol_t",
8097    "_message_ref_t",
8098    "_super_message_ref_t",
8099    "_ivar_t",
8100    "_ivar_list_t"
8101);
8102
8103sub getCompileCmd($$$)
8104{
8105    my ($Path, $Opt, $Inc) = @_;
8106    my $GccCall = $GCC_PATH;
8107    if($Opt) {
8108        $GccCall .= " ".$Opt;
8109    }
8110    $GccCall .= " -x ";
8111    if($OSgroup eq "macos") {
8112        $GccCall .= "objective-";
8113    }
8114
8115    if($EMERGENCY_MODE_48)
8116    { # workaround for GCC 4.8 (C only)
8117        $GccCall .= "c++";
8118    }
8119    elsif(check_gcc($GCC_PATH, "4"))
8120    { # compile as "C++" header
8121      # to obtain complete dump using GCC 4.0
8122        $GccCall .= "c++-header";
8123    }
8124    else
8125    { # compile as "C++" source
8126      # GCC 3.3 cannot compile headers
8127        $GccCall .= "c++";
8128    }
8129    if(my $Opts = platformSpecs($Version))
8130    {# platform-specific options
8131        $GccCall .= " ".$Opts;
8132    }
8133    # allow extra qualifications
8134    # and other nonconformant code
8135    $GccCall .= " -fpermissive";
8136    $GccCall .= " -w";
8137    if($NoStdInc)
8138    {
8139        $GccCall .= " -nostdinc";
8140        $GccCall .= " -nostdinc++";
8141    }
8142    if($CompilerOptions{$Version})
8143    { # user-defined options
8144        $GccCall .= " ".$CompilerOptions{$Version};
8145    }
8146    $GccCall .= " \"$Path\"";
8147    if($Inc)
8148    { # include paths
8149        $GccCall .= " ".$Inc;
8150    }
8151    return $GccCall;
8152}
8153
8154sub detectPreamble($$)
8155{
8156    my ($Content, $LibVersion) = @_;
8157    my %HeaderElems = (
8158        # Types
8159        "stdio.h" => ["FILE", "va_list"],
8160        "stddef.h" => ["NULL", "ptrdiff_t"],
8161        "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
8162                       "int8_t", "int16_t", "int32_t", "int64_t"],
8163        "time.h" => ["time_t"],
8164        "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
8165                          "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
8166        "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
8167        "stdbool.h" => ["_Bool"],
8168        "rpc/xdr.h" => ["bool_t"],
8169        "in_systm.h" => ["n_long", "n_short"],
8170        # Fields
8171        "arpa/inet.h" => ["fw_src", "ip_src"],
8172        # Functions
8173        "stdlib.h" => ["free", "malloc", "size_t"],
8174        "string.h" => ["memmove", "strcmp"]
8175    );
8176    my %AutoPreamble = ();
8177    foreach (keys(%HeaderElems))
8178    {
8179        foreach my $Elem (@{$HeaderElems{$_}}) {
8180            $AutoPreamble{$Elem} = $_;
8181        }
8182    }
8183    my %Types = ();
8184    while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
8185    { # error: 'FILE' has not been declared
8186        $Types{$2} = 1;
8187    }
8188    if(keys(%Types))
8189    {
8190        my %AddHeaders = ();
8191        foreach my $Type (keys(%Types))
8192        {
8193            if(my $Header = $AutoPreamble{$Type})
8194            {
8195                if(my $Path = identifyHeader($Header, $LibVersion))
8196                {
8197                    if(skipHeader($Path, $LibVersion)) {
8198                        next;
8199                    }
8200                    $Path = path_format($Path, $OSgroup);
8201                    $AddHeaders{$Path}{"Type"} = $Type;
8202                    $AddHeaders{$Path}{"Header"} = $Header;
8203                }
8204            }
8205        }
8206        if(keys(%AddHeaders)) {
8207            return \%AddHeaders;
8208        }
8209    }
8210    return undef;
8211}
8212
8213sub checkCTags($)
8214{
8215    my $Path = $_[0];
8216    if(not $Path) {
8217        return;
8218    }
8219    my $CTags = undef;
8220
8221    if($OSgroup eq "bsd")
8222    { # use ectags on BSD
8223        $CTags = get_CmdPath("ectags");
8224        if(not $CTags) {
8225            printMsg("WARNING", "can't find \'ectags\' program");
8226        }
8227    }
8228    if(not $CTags) {
8229        $CTags = get_CmdPath("ctags");
8230    }
8231    if(not $CTags)
8232    {
8233        printMsg("WARNING", "can't find \'ctags\' program");
8234        return;
8235    }
8236
8237    if($OSgroup ne "linux")
8238    { # macos, freebsd, etc.
8239        my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
8240        if($Info!~/exuberant/i)
8241        {
8242            printMsg("WARNING", "incompatible version of \'ctags\' program");
8243            return;
8244        }
8245    }
8246
8247    my $Out = $TMP_DIR."/ctags.txt";
8248    system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
8249    if($Debug) {
8250        copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
8251    }
8252    open(CTAGS, "<", $Out);
8253    while(my $Line = <CTAGS>)
8254    {
8255        chomp($Line);
8256        my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
8257        if(defined $Intrinsic_Keywords{$Name})
8258        { # noise
8259            next;
8260        }
8261        if($Type eq "n")
8262        {
8263            if(index($Scpe, "class:")==0) {
8264                next;
8265            }
8266            if(index($Scpe, "struct:")==0) {
8267                next;
8268            }
8269            if(index($Scpe, "namespace:")==0)
8270            {
8271                if($Scpe=~s/\Anamespace://) {
8272                    $Name = $Scpe."::".$Name;
8273                }
8274            }
8275            $TUnit_NameSpaces{$Version}{$Name} = 1;
8276        }
8277        elsif($Type eq "p")
8278        {
8279            if(not $Scpe or index($Scpe, "namespace:")==0) {
8280                $TUnit_Funcs{$Version}{$Name} = 1;
8281            }
8282        }
8283        elsif($Type eq "x")
8284        {
8285            if(not $Scpe or index($Scpe, "namespace:")==0) {
8286                $TUnit_Vars{$Version}{$Name} = 1;
8287            }
8288        }
8289    }
8290    close(CTAGS);
8291}
8292
8293sub preChange($$)
8294{
8295    my ($HeaderPath, $IncStr) = @_;
8296
8297    my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr);
8298    my $Content = undef;
8299
8300    if($OStarget eq "windows"
8301    and get_dumpmachine($GCC_PATH)=~/mingw/i
8302    and $MinGWMode{$Version}!=-1)
8303    { # modify headers to compile by MinGW
8304        if(not $Content)
8305        { # preprocessing
8306            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
8307        }
8308        if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
8309        { # __asm { ... }
8310            $MinGWMode{$Version}=1;
8311        }
8312        if($Content=~s/\s+(\/ \/.*?)\n/\n/g)
8313        { # comments after preprocessing
8314            $MinGWMode{$Version}=1;
8315        }
8316        if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
8317        { # 0xffui8
8318            $MinGWMode{$Version}=1;
8319        }
8320
8321        if($MinGWMode{$Version}) {
8322            printMsg("INFO", "Using MinGW compatibility mode");
8323        }
8324    }
8325
8326    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
8327    and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS)
8328    { # rename C++ keywords in C code
8329      # disable this code by -cpp-compatible option
8330        if(not $Content)
8331        { # preprocessing
8332            $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
8333        }
8334        my $RegExp_C = join("|", keys(%CppKeywords_C));
8335        my $RegExp_F = join("|", keys(%CppKeywords_F));
8336        my $RegExp_O = join("|", keys(%CppKeywords_O));
8337
8338        my $Detected = undef;
8339
8340        while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
8341        { # MATCH:
8342          # int foo(int new, int class, int (*new)(int));
8343          # unsigned private: 8;
8344          # DO NOT MATCH:
8345          # #pragma GCC visibility push(default)
8346            $CppMode{$Version} = 1;
8347            $Detected = "$1$2$3$4" if(not defined $Detected);
8348        }
8349        if($Content=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
8350        { # MATCH:
8351          # int delete(...);
8352          # int explicit(...);
8353          # DO NOT MATCH:
8354          # void operator delete(...)
8355            $CppMode{$Version} = 1;
8356            $Detected = "$1$2$3" if(not defined $Detected);
8357        }
8358        if($Content=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
8359        { # MATCH:
8360          # int bool;
8361          # DO NOT MATCH:
8362          # bool X;
8363          # return *this;
8364          # throw;
8365            $CppMode{$Version} = 1;
8366            $Detected = "$1$2$3" if(not defined $Detected);
8367        }
8368        if($Content=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
8369        { # MATCH:
8370          # int operator(...);
8371          # DO NOT MATCH:
8372          # int operator()(...);
8373            $CppMode{$Version} = 1;
8374            $Detected = "$1$2$3" if(not defined $Detected);
8375        }
8376        if($Content=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
8377        { # MATCH:
8378          # int foo(int operator);
8379          # int foo(int operator, int other);
8380          # DO NOT MATCH:
8381          # int operator,(...);
8382            $CppMode{$Version} = 1;
8383            $Detected = "$1$2$3" if(not defined $Detected);
8384        }
8385        if($Content=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
8386        { # MATCH:
8387          # int foo(gboolean *bool);
8388          # DO NOT MATCH:
8389          # void setTabEnabled(int index, bool);
8390            $CppMode{$Version} = 1;
8391            $Detected = "$1$2$3" if(not defined $Detected);
8392        }
8393        if($Content=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
8394        { # MATCH:
8395          # int foo(int* this);
8396          # int bar(int this);
8397          # int baz(int throw);
8398          # DO NOT MATCH:
8399          # foo(X, this);
8400            $CppMode{$Version} = 1;
8401            $Detected = "$1$2$3$4" if(not defined $Detected);
8402        }
8403        if($Content=~s/(struct |extern )(template) /$1c99_$2 /g)
8404        { # MATCH:
8405          # struct template {...};
8406          # extern template foo(...);
8407            $CppMode{$Version} = 1;
8408            $Detected = "$1$2" if(not defined $Detected);
8409        }
8410
8411        if($CppMode{$Version} == 1)
8412        {
8413            if($Debug)
8414            {
8415                $Detected=~s/\A\s+//g;
8416                printMsg("INFO", "Detected code: \"$Detected\"");
8417            }
8418        }
8419
8420        # remove typedef enum NAME NAME;
8421        my @FwdTypedefs = $Content=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
8422        my $N = 0;
8423        while($N<=$#FwdTypedefs-1)
8424        {
8425            my $S = $FwdTypedefs[$N];
8426            if($S eq $FwdTypedefs[$N+1])
8427            {
8428                $Content=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
8429                $CppMode{$Version} = 1;
8430
8431                if($Debug) {
8432                    printMsg("INFO", "Detected code: \"typedef enum $S $S;\"");
8433                }
8434            }
8435            $N+=2;
8436        }
8437
8438        if($CppMode{$Version}==1) {
8439            printMsg("INFO", "Using C++ compatibility mode");
8440        }
8441    }
8442
8443    if($CppMode{$Version}==1
8444    or $MinGWMode{$Version}==1)
8445    {
8446        my $IPath = $TMP_DIR."/dump$Version.i";
8447        writeFile($IPath, $Content);
8448        return $IPath;
8449    }
8450
8451    return undef;
8452}
8453
8454sub getDump()
8455{
8456    if(not $GCC_PATH) {
8457        exitStatus("Error", "internal error - GCC path is not set");
8458    }
8459
8460    my @Headers = keys(%{$Registered_Headers{$Version}});
8461    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
8462
8463    my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
8464
8465    my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
8466    my $HeaderPath = $TmpHeaderPath;
8467
8468    # write tmp-header
8469    open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
8470    if(my $AddDefines = $Descriptor{$Version}{"Defines"})
8471    {
8472        $AddDefines=~s/\n\s+/\n  /g;
8473        print TMP_HEADER "\n  // add defines\n  ".$AddDefines."\n";
8474    }
8475    print TMP_HEADER "\n  // add includes\n";
8476    foreach my $HPath (@{$Include_Preamble{$Version}}) {
8477        print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
8478    }
8479    foreach my $HPath (@Headers)
8480    {
8481        if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
8482            print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
8483        }
8484    }
8485    close(TMP_HEADER);
8486
8487    if($ExtraInfo)
8488    { # extra information for other tools
8489        if($IncludeString) {
8490            writeFile($ExtraInfo."/include-string", $IncludeString);
8491        }
8492        writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version}));
8493        writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version}));
8494
8495        if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}}))
8496        {
8497            my $REDIR = "";
8498            foreach my $P1 (sort @Redirects) {
8499                $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n";
8500            }
8501            writeFile($ExtraInfo."/include-redirect", $REDIR);
8502        }
8503    }
8504
8505    if(not keys(%{$TargetHeaders{$Version}}))
8506    { # Target headers
8507        addTargetHeaders($Version);
8508    }
8509
8510    # clean memory
8511    %RecursiveIncludes = ();
8512    %Header_Include_Prefix = ();
8513    %Header_Includes = ();
8514
8515    # clean cache
8516    delete($Cache{"identifyHeader"});
8517    delete($Cache{"detect_header_includes"});
8518    delete($Cache{"selectSystemHeader"});
8519
8520    # preprocessing stage
8521    my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
8522    checkPreprocessedUnit($Pre);
8523
8524    if($ExtraInfo)
8525    { # extra information for other tools
8526        writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}})));
8527    }
8528
8529    # clean memory
8530    delete($Include_Neighbors{$Version});
8531    delete($PreprocessedHeaders{$Version});
8532
8533    if($COMMON_LANGUAGE{$Version} eq "C++") {
8534        checkCTags($Pre);
8535    }
8536
8537    if(my $PrePath = preChange($TmpHeaderPath, $IncludeString))
8538    { # try to correct the preprocessor output
8539        $HeaderPath = $PrePath;
8540    }
8541
8542    if($COMMON_LANGUAGE{$Version} eq "C++")
8543    { # add classes and namespaces to the dump
8544        my $CHdump = "-fdump-class-hierarchy -c";
8545        if($CppMode{$Version}==1
8546        or $MinGWMode{$Version}==1) {
8547            $CHdump .= " -fpreprocessed";
8548        }
8549        my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString);
8550        chdir($TMP_DIR);
8551        system($ClassHierarchyCmd." >null 2>&1");
8552        chdir($ORIG_DIR);
8553        if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
8554        {
8555            my $Content = readFile($ClassDump);
8556            foreach my $ClassInfo (split(/\n\n/, $Content))
8557            {
8558                if($ClassInfo=~/\AClass\s+(.+)\s*/i)
8559                {
8560                    my $CName = $1;
8561                    next if($CName=~/\A(__|_objc_|_opaque_)/);
8562                    $TUnit_NameSpaces{$Version}{$CName} = -1;
8563                    if($CName=~/\A[\w:]+\Z/)
8564                    { # classes
8565                        $TUnit_Classes{$Version}{$CName} = 1;
8566                    }
8567                    if($CName=~/(\w[\w:]*)::/)
8568                    { # namespaces
8569                        my $NS = $1;
8570                        if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
8571                            $TUnit_NameSpaces{$Version}{$NS} = 1;
8572                        }
8573                    }
8574                }
8575                elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
8576                { # read v-tables (advanced approach)
8577                    my ($CName, $VTable) = ($1, $2);
8578                    $ClassVTable_Content{$Version}{$CName} = $VTable;
8579                }
8580            }
8581            foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
8582            { # add user-defined namespaces
8583                $TUnit_NameSpaces{$Version}{$NS} = 1;
8584            }
8585            if($Debug)
8586            { # debug mode
8587                mkpath($DEBUG_PATH{$Version});
8588                copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
8589            }
8590            unlink($ClassDump);
8591        }
8592
8593        # add namespaces and classes
8594        if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
8595        { # GCC on all supported platforms does not include namespaces to the dump by default
8596            appendFile($HeaderPath, "\n  // add namespaces\n".$NS_Add);
8597        }
8598        # some GCC versions don't include class methods to the TU dump by default
8599        my ($AddClass, $ClassNum) = ("", 0);
8600        my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions
8601        foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
8602        {
8603            next if($C_Structure{$CName});
8604            next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
8605            next if($SkipTypes{$Version}{$CName});
8606            if(not $Force and $GCC_44
8607            and $OSgroup eq "linux")
8608            { # optimization for linux with GCC >= 4.4
8609              # disable this code by -force option
8610                if(index($CName, "::")!=-1)
8611                { # should be added by name space
8612                    next;
8613                }
8614            }
8615            else
8616            {
8617                if($CName=~/\A(.+)::[^:]+\Z/
8618                and $TUnit_Classes{$Version}{$1})
8619                { # classes inside other classes
8620                    next;
8621                }
8622            }
8623            if(defined $TUnit_Funcs{$Version}{$CName})
8624            { # the same name for a function and type
8625                next;
8626            }
8627            if(defined $TUnit_Vars{$Version}{$CName})
8628            { # the same name for a variable and type
8629                next;
8630            }
8631            $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
8632        }
8633        if($AddClass) {
8634            appendFile($HeaderPath, "\n  // add classes\n".$AddClass);
8635        }
8636    }
8637    writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
8638    # create TU dump
8639    my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
8640    if($CppMode{$Version}==1
8641    or $MinGWMode{$Version}==1) {
8642        $TUdump .= " -fpreprocessed";
8643    }
8644    my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString);
8645    writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
8646    chdir($TMP_DIR);
8647    system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
8648    my $Errors = "";
8649    if($?)
8650    { # failed to compile, but the TU dump still can be created
8651        if($Errors = readFile($TMP_DIR."/tu_errors"))
8652        { # try to recompile
8653          # FIXME: handle other errors and try to recompile
8654            if($CppMode{$Version}==1
8655            and index($Errors, "c99_")!=-1)
8656            { # disable c99 mode and try again
8657                $CppMode{$Version}=-1;
8658                printMsg("INFO", "Disabling C++ compatibility mode");
8659                resetLogging($Version);
8660                $TMP_DIR = tempdir(CLEANUP=>1);
8661                return getDump();
8662            }
8663            elsif($AutoPreambleMode{$Version}!=-1
8664            and my $AddHeaders = detectPreamble($Errors, $Version))
8665            { # add auto preamble headers and try again
8666                $AutoPreambleMode{$Version}=-1;
8667                my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
8668                foreach my $Num (0 .. $#Headers)
8669                {
8670                    my $Path = $Headers[$Num];
8671                    if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}}))
8672                    {
8673                        push_U($Include_Preamble{$Version}, $Path);
8674                        printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
8675                    }
8676                }
8677                resetLogging($Version);
8678                $TMP_DIR = tempdir(CLEANUP=>1);
8679                return getDump();
8680            }
8681            elsif($Cpp0xMode{$Version}!=-1
8682            and ($Errors=~/\Q-std=c++0x\E/
8683            or $Errors=~/is not a class or namespace/))
8684            { # c++0x: enum class
8685                if(check_gcc($GCC_PATH, "4.6"))
8686                {
8687                    $Cpp0xMode{$Version}=-1;
8688                    printMsg("INFO", "Enabling c++0x mode");
8689                    resetLogging($Version);
8690                    $TMP_DIR = tempdir(CLEANUP=>1);
8691                    $CompilerOptions{$Version} .= " -std=c++0x";
8692                    return getDump();
8693                }
8694                else {
8695                    printMsg("WARNING", "Probably c++0x construction detected");
8696                }
8697
8698            }
8699            elsif($MinGWMode{$Version}==1)
8700            { # disable MinGW mode and try again
8701                $MinGWMode{$Version}=-1;
8702                resetLogging($Version);
8703                $TMP_DIR = tempdir(CLEANUP=>1);
8704                return getDump();
8705            }
8706            writeLog($Version, $Errors);
8707        }
8708        else {
8709            writeLog($Version, "$!: $?\n");
8710        }
8711        printMsg("ERROR", "some errors occurred when compiling headers");
8712        printErrorLog($Version);
8713        $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
8714        writeLog($Version, "\n"); # new line
8715    }
8716    chdir($ORIG_DIR);
8717    unlink($TmpHeaderPath);
8718    unlink($HeaderPath);
8719
8720    if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
8721        return $TUs[0];
8722    }
8723    else
8724    {
8725        my $Msg = "can't compile header(s)";
8726        if($Errors=~/error trying to exec \W+cc1plus\W+/) {
8727            $Msg .= "\nDid you install G++?";
8728        }
8729        exitStatus("Cannot_Compile", $Msg);
8730    }
8731}
8732
8733sub cmd_file($)
8734{
8735    my $Path = $_[0];
8736    return "" if(not $Path or not -e $Path);
8737    if(my $CmdPath = get_CmdPath("file")) {
8738        return `$CmdPath -b \"$Path\"`;
8739    }
8740    return "";
8741}
8742
8743sub getIncString($$)
8744{
8745    my ($ArrRef, $Style) = @_;
8746    return "" if(not $ArrRef or $#{$ArrRef}<0);
8747    my $String = "";
8748    foreach (@{$ArrRef}) {
8749        $String .= " ".inc_opt($_, $Style);
8750    }
8751    return $String;
8752}
8753
8754sub getIncPaths(@)
8755{
8756    my @HeaderPaths = @_;
8757    my @IncPaths = @{$Add_Include_Paths{$Version}};
8758    if($INC_PATH_AUTODETECT{$Version})
8759    { # auto-detecting dependencies
8760        my %Includes = ();
8761        foreach my $HPath (@HeaderPaths)
8762        {
8763            foreach my $Dir (get_HeaderDeps($HPath, $Version))
8764            {
8765                if($Skip_Include_Paths{$Version}{$Dir}) {
8766                    next;
8767                }
8768                if($SystemRoot)
8769                {
8770                    if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
8771                        next;
8772                    }
8773                }
8774                $Includes{$Dir} = 1;
8775            }
8776        }
8777        foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
8778            push_U(\@IncPaths, $Dir);
8779        }
8780    }
8781    else
8782    { # user-defined paths
8783        @IncPaths = @{$Include_Paths{$Version}};
8784    }
8785    return \@IncPaths;
8786}
8787
8788sub push_U($@)
8789{ # push unique
8790    if(my $Array = shift @_)
8791    {
8792        if(@_)
8793        {
8794            my %Exist = map {$_=>1} @{$Array};
8795            foreach my $Elem (@_)
8796            {
8797                if(not defined $Exist{$Elem})
8798                {
8799                    push(@{$Array}, $Elem);
8800                    $Exist{$Elem} = 1;
8801                }
8802            }
8803        }
8804    }
8805}
8806
8807sub callPreprocessor($$$)
8808{
8809    my ($Path, $Inc, $LibVersion) = @_;
8810    return "" if(not $Path or not -f $Path);
8811    my $IncludeString=$Inc;
8812    if(not $Inc) {
8813        $IncludeString = getIncString(getIncPaths($Path), "GCC");
8814    }
8815    my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
8816    my $Out = $TMP_DIR."/preprocessed.h";
8817    system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
8818    return $Out;
8819}
8820
8821sub cmd_find($;$$$$)
8822{ # native "find" is much faster than File::Find (~6x)
8823  # also the File::Find doesn't support --maxdepth N option
8824  # so using the cross-platform wrapper for the native one
8825    my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_;
8826    return () if(not $Path or not -e $Path);
8827    if($OSgroup eq "windows")
8828    {
8829        my $DirCmd = get_CmdPath("dir");
8830        if(not $DirCmd) {
8831            exitStatus("Not_Found", "can't find \"dir\" command");
8832        }
8833        $Path = get_abs_path($Path);
8834        $Path = path_format($Path, $OSgroup);
8835        my $Cmd = $DirCmd." \"$Path\" /B /O";
8836        if($MaxDepth!=1) {
8837            $Cmd .= " /S";
8838        }
8839        if($Type eq "d") {
8840            $Cmd .= " /AD";
8841        }
8842        elsif($Type eq "f") {
8843            $Cmd .= " /A-D";
8844        }
8845        my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
8846        if($Name)
8847        {
8848            if(not $UseRegex)
8849            { # FIXME: how to search file names in MS shell?
8850              # wildcard to regexp
8851                $Name=~s/\*/.*/g;
8852                $Name='\A'.$Name.'\Z';
8853            }
8854            @Files = grep { /$Name/i } @Files;
8855        }
8856        my @AbsPaths = ();
8857        foreach my $File (@Files)
8858        {
8859            if(not is_abs($File)) {
8860                $File = join_P($Path, $File);
8861            }
8862            if($Type eq "f" and not -f $File)
8863            { # skip dirs
8864                next;
8865            }
8866            push(@AbsPaths, path_format($File, $OSgroup));
8867        }
8868        if($Type eq "d") {
8869            push(@AbsPaths, $Path);
8870        }
8871        return @AbsPaths;
8872    }
8873    else
8874    {
8875        my $FindCmd = get_CmdPath("find");
8876        if(not $FindCmd) {
8877            exitStatus("Not_Found", "can't find a \"find\" command");
8878        }
8879        $Path = get_abs_path($Path);
8880        if(-d $Path and -l $Path
8881        and $Path!~/\/\Z/)
8882        { # for directories that are symlinks
8883            $Path.="/";
8884        }
8885        my $Cmd = $FindCmd." \"$Path\"";
8886        if($MaxDepth) {
8887            $Cmd .= " -maxdepth $MaxDepth";
8888        }
8889        if($Type) {
8890            $Cmd .= " -type $Type";
8891        }
8892        if($Name and not $UseRegex)
8893        { # wildcards
8894            $Cmd .= " -name \"$Name\"";
8895        }
8896        my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8897        if($? and $!) {
8898            printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8899        }
8900        my @Files = split(/\n/, $Res);
8901        if($Name and $UseRegex)
8902        { # regex
8903            @Files = grep { /$Name/ } @Files;
8904        }
8905        return @Files;
8906    }
8907}
8908
8909sub unpackDump($)
8910{
8911    my $Path = $_[0];
8912    return "" if(not $Path or not -e $Path);
8913    $Path = get_abs_path($Path);
8914    $Path = path_format($Path, $OSgroup);
8915    my ($Dir, $FileName) = separate_path($Path);
8916    my $UnpackDir = $TMP_DIR."/unpack";
8917    rmtree($UnpackDir);
8918    mkpath($UnpackDir);
8919    if($FileName=~s/\Q.zip\E\Z//g)
8920    { # *.zip
8921        my $UnzipCmd = get_CmdPath("unzip");
8922        if(not $UnzipCmd) {
8923            exitStatus("Not_Found", "can't find \"unzip\" command");
8924        }
8925        chdir($UnpackDir);
8926        system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\"");
8927        if($?) {
8928            exitStatus("Error", "can't extract \'$Path\' ($?): $!");
8929        }
8930        chdir($ORIG_DIR);
8931        my @Contents = cmd_find($UnpackDir, "f");
8932        if(not @Contents) {
8933            exitStatus("Error", "can't extract \'$Path\'");
8934        }
8935        return $Contents[0];
8936    }
8937    elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g)
8938    { # *.tar.gz
8939        if($OSgroup eq "windows")
8940        { # -xvzf option is not implemented in tar.exe (2003)
8941          # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8942            my $TarCmd = get_CmdPath("tar");
8943            if(not $TarCmd) {
8944                exitStatus("Not_Found", "can't find \"tar\" command");
8945            }
8946            my $GzipCmd = get_CmdPath("gzip");
8947            if(not $GzipCmd) {
8948                exitStatus("Not_Found", "can't find \"gzip\" command");
8949            }
8950            chdir($UnpackDir);
8951            system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
8952            if($?) {
8953                exitStatus("Error", "can't extract \'$Path\'");
8954            }
8955            system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\"");
8956            if($?) {
8957                exitStatus("Error", "can't extract \'$Path\' ($?): $!");
8958            }
8959            chdir($ORIG_DIR);
8960            unlink($Dir."/".$FileName.".tar");
8961            my @Contents = cmd_find($UnpackDir, "f");
8962            if(not @Contents) {
8963                exitStatus("Error", "can't extract \'$Path\'");
8964            }
8965            return $Contents[0];
8966        }
8967        else
8968        { # Unix, Mac
8969            my $TarCmd = get_CmdPath("tar");
8970            if(not $TarCmd) {
8971                exitStatus("Not_Found", "can't find \"tar\" command");
8972            }
8973            chdir($UnpackDir);
8974            system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\"");
8975            if($?) {
8976                exitStatus("Error", "can't extract \'$Path\' ($?): $!");
8977            }
8978            chdir($ORIG_DIR);
8979            my @Contents = cmd_find($UnpackDir, "f");
8980            if(not @Contents) {
8981                exitStatus("Error", "can't extract \'$Path\'");
8982            }
8983            return $Contents[0];
8984        }
8985    }
8986}
8987
8988sub createArchive($$)
8989{
8990    my ($Path, $To) = @_;
8991    if(not $To) {
8992        $To = ".";
8993    }
8994    if(not $Path or not -e $Path
8995    or not -d $To) {
8996        return "";
8997    }
8998    my ($From, $Name) = separate_path($Path);
8999    if($OSgroup eq "windows")
9000    { # *.zip
9001        my $ZipCmd = get_CmdPath("zip");
9002        if(not $ZipCmd) {
9003            exitStatus("Not_Found", "can't find \"zip\"");
9004        }
9005        my $Pkg = $To."/".$Name.".zip";
9006        unlink($Pkg);
9007        chdir($To);
9008        system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
9009        if($?)
9010        { # cannot allocate memory (or other problems with "zip")
9011            unlink($Path);
9012            exitStatus("Error", "can't pack the ABI dump: ".$!);
9013        }
9014        chdir($ORIG_DIR);
9015        unlink($Path);
9016        return $Pkg;
9017    }
9018    else
9019    { # *.tar.gz
9020        my $TarCmd = get_CmdPath("tar");
9021        if(not $TarCmd) {
9022            exitStatus("Not_Found", "can't find \"tar\"");
9023        }
9024        my $GzipCmd = get_CmdPath("gzip");
9025        if(not $GzipCmd) {
9026            exitStatus("Not_Found", "can't find \"gzip\"");
9027        }
9028        my $Pkg = abs_path($To)."/".$Name.".tar.gz";
9029        unlink($Pkg);
9030        chdir($From);
9031        system($TarCmd, "-czf", $Pkg, $Name);
9032        if($?)
9033        { # cannot allocate memory (or other problems with "tar")
9034            unlink($Path);
9035            exitStatus("Error", "can't pack the ABI dump: ".$!);
9036        }
9037        chdir($ORIG_DIR);
9038        unlink($Path);
9039        return $To."/".$Name.".tar.gz";
9040    }
9041}
9042
9043sub is_header_file($)
9044{
9045    if($_[0]=~/\.($HEADER_EXT)\Z/i) {
9046        return $_[0];
9047    }
9048    return 0;
9049}
9050
9051sub is_not_header($)
9052{
9053    if($_[0]=~/\.\w+\Z/
9054    and $_[0]!~/\.($HEADER_EXT)\Z/i) {
9055        return 1;
9056    }
9057    return 0;
9058}
9059
9060sub is_header($$$)
9061{
9062    my ($Header, $UserDefined, $LibVersion) = @_;
9063    return 0 if(-d $Header);
9064    if(-f $Header) {
9065        $Header = get_abs_path($Header);
9066    }
9067    else
9068    {
9069        if(is_abs($Header))
9070        { # incorrect absolute path
9071            return 0;
9072        }
9073        if(my $HPath = identifyHeader($Header, $LibVersion)) {
9074            $Header = $HPath;
9075        }
9076        else
9077        { # can't find header
9078            return 0;
9079        }
9080    }
9081    if($Header=~/\.\w+\Z/)
9082    { # have an extension
9083        return is_header_file($Header);
9084    }
9085    else
9086    {
9087        if($UserDefined==2)
9088        { # specified on the command line
9089            if(cmd_file($Header)!~/HTML|XML/i) {
9090                return $Header;
9091            }
9092        }
9093        elsif($UserDefined)
9094        { # specified in the XML-descriptor
9095          # header file without an extension
9096            return $Header;
9097        }
9098        else
9099        {
9100            if(index($Header, "/include/")!=-1
9101            or cmd_file($Header)=~/C[\+]*\s+program/i)
9102            { # !~/HTML|XML|shared|dynamic/i
9103                return $Header;
9104            }
9105        }
9106    }
9107    return 0;
9108}
9109
9110sub addTargetHeaders($)
9111{
9112    my $LibVersion = $_[0];
9113    foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
9114    {
9115        my $RegDir = get_dirname($RegHeader);
9116        $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1;
9117
9118        if(not $INC_PATH_AUTODETECT{$LibVersion}) {
9119            detect_recursive_includes($RegHeader, $LibVersion);
9120        }
9121
9122        foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
9123        {
9124            my $Dir = get_dirname($RecInc);
9125
9126            if(familiarDirs($RegDir, $Dir)
9127            or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
9128            { # in the same directory or included by #include "..."
9129                $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1;
9130            }
9131        }
9132    }
9133}
9134
9135sub familiarDirs($$)
9136{
9137    my ($D1, $D2) = @_;
9138    if($D1 eq $D2) {
9139        return 1;
9140    }
9141
9142    my $U1 = index($D1, "/usr/");
9143    my $U2 = index($D2, "/usr/");
9144
9145    if($U1==0 and $U2!=0) {
9146        return 0;
9147    }
9148
9149    if($U2==0 and $U1!=0) {
9150        return 0;
9151    }
9152
9153    if(index($D2, $D1."/")==0) {
9154        return 1;
9155    }
9156
9157    # /usr/include/DIR
9158    # /home/user/DIR
9159
9160    my $DL = get_depth($D1);
9161
9162    my @Dirs1 = ($D1);
9163    while($DL - get_depth($D1)<=2
9164    and get_depth($D1)>=4
9165    and $D1=~s/[\/\\]+[^\/\\]*?\Z//) {
9166        push(@Dirs1, $D1);
9167    }
9168
9169    my @Dirs2 = ($D2);
9170    while(get_depth($D2)>=4
9171    and $D2=~s/[\/\\]+[^\/\\]*?\Z//) {
9172        push(@Dirs2, $D2);
9173    }
9174
9175    foreach my $P1 (@Dirs1)
9176    {
9177        foreach my $P2 (@Dirs2)
9178        {
9179
9180            if($P1 eq $P2) {
9181                return 1;
9182            }
9183        }
9184    }
9185    return 0;
9186}
9187
9188sub readHeaders($)
9189{
9190    $Version = $_[0];
9191    printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
9192    my $DumpPath = getDump();
9193    if($Debug)
9194    { # debug mode
9195        mkpath($DEBUG_PATH{$Version});
9196        copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
9197    }
9198    getInfo($DumpPath);
9199}
9200
9201sub prepareTypes($)
9202{
9203    my $LibVersion = $_[0];
9204    if(not checkDump($LibVersion, "2.0"))
9205    { # support for old ABI dumps
9206      # type names have been corrected in ACC 1.22 (dump 2.0 format)
9207        foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
9208        {
9209            my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
9210            if($TName=~/\A(\w+)::(\w+)/) {
9211                my ($P1, $P2) = ($1, $2);
9212                if($P1 eq $P2) {
9213                    $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
9214                }
9215                else {
9216                    $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
9217                }
9218            }
9219            $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
9220        }
9221    }
9222    if(not checkDump($LibVersion, "2.5"))
9223    { # support for old ABI dumps
9224      # V < 2.5: array size == "number of elements"
9225      # V >= 2.5: array size in bytes
9226        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
9227        {
9228            my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
9229            if($Type{"Type"} eq "Array")
9230            {
9231                if(my $Size = $Type{"Size"})
9232                { # array[N]
9233                    my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
9234                    $Size *= $Base{"Size"};
9235                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
9236                }
9237                else
9238                { # array[] is a pointer
9239                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
9240                }
9241            }
9242        }
9243    }
9244    my $V2 = ($LibVersion==1)?2:1;
9245    if(not checkDump($LibVersion, "2.7"))
9246    { # support for old ABI dumps
9247      # size of "method ptr" corrected in 2.7
9248        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
9249        {
9250            my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
9251            if($PureType{"Type"} eq "MethodPtr")
9252            {
9253                my %Type = get_Type($TypeId, $LibVersion);
9254                my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
9255                my %Type2 = get_Type($TypeId_2, $V2);
9256                if($Type{"Size"} ne $Type2{"Size"}) {
9257                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
9258                }
9259            }
9260        }
9261    }
9262}
9263
9264sub prepareSymbols($)
9265{
9266    my $LibVersion = $_[0];
9267
9268    if(not keys(%{$SymbolInfo{$LibVersion}}))
9269    { # check if input is valid
9270        if(not $ExtendedCheck and not $CheckObjectsOnly)
9271        {
9272            if($CheckHeadersOnly) {
9273                exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
9274            }
9275            else {
9276                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
9277            }
9278        }
9279    }
9280
9281    my $Remangle = 0;
9282    if(not checkDump(1, "2.10")
9283    or not checkDump(2, "2.10"))
9284    { # different formats
9285        $Remangle = 1;
9286    }
9287    if($CheckHeadersOnly)
9288    { # different languages
9289        if($UserLang)
9290        { # --lang=LANG for both versions
9291            if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
9292            or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
9293            {
9294                if($UserLang eq "C++")
9295                { # remangle symbols
9296                    $Remangle = 1;
9297                }
9298                elsif($UserLang eq "C")
9299                { # remove mangling
9300                    $Remangle = -1;
9301                }
9302            }
9303        }
9304    }
9305
9306    foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
9307    { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
9308        if(not checkDump($LibVersion, "2.13"))
9309        { # support for old ABI dumps
9310            if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
9311            {
9312                foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
9313                {
9314                    my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
9315                    my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
9316                    my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
9317                    if(defined $DVal and $DVal ne "")
9318                    {
9319                        if($TName eq "char") {
9320                            $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
9321                        }
9322                        elsif($TName eq "bool") {
9323                            $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
9324                        }
9325                    }
9326                }
9327            }
9328        }
9329        if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
9330        {
9331            if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
9332            and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
9333            and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this")
9334            { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
9335              # + support for old ABI dumps
9336                next;
9337            }
9338        }
9339        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
9340        my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
9341        my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
9342        my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
9343
9344        my $SRemangle = 0;
9345        if(not checkDump(1, "2.12")
9346        or not checkDump(2, "2.12"))
9347        { # support for old ABI dumps
9348            if($ShortName eq "operator>>")
9349            {
9350                if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
9351                { # corrected mangling of operator>>
9352                    $SRemangle = 1;
9353                }
9354            }
9355            if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
9356            {
9357                if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
9358                and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
9359                { # corrected mangling of const global data
9360                  # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
9361                  # and incorrectly mangled by old ACC versions
9362                    $SRemangle = 1;
9363                }
9364            }
9365        }
9366        if(not $CheckHeadersOnly)
9367        { # support for old ABI dumps
9368            if(not checkDump(1, "2.17")
9369            or not checkDump(2, "2.17"))
9370            {
9371                if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
9372                {
9373                    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
9374                    {
9375                        if(link_symbol($ShortName, $LibVersion, "-Deps"))
9376                        {
9377                            $MnglName = $ShortName;
9378                            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
9379                        }
9380                    }
9381                }
9382            }
9383        }
9384        if($Remangle==1 or $SRemangle==1)
9385        { # support for old ABI dumps: some symbols are not mangled in old dumps
9386          # mangle both sets of symbols (old and new)
9387          # NOTE: remangling all symbols by the same mangler
9388            if($MnglName=~/\A_ZN(V|)K/)
9389            { # mangling may be incorrect on old ABI dumps
9390              # because of absent "Const" attribute
9391                $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
9392            }
9393            if($MnglName=~/\A_ZN(K|)V/)
9394            { # mangling may be incorrect on old ABI dumps
9395              # because of absent "Volatile" attribute
9396                $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
9397            }
9398            if(($ClassID and $MnglName!~/\A(_Z|\?)/)
9399            or (not $ClassID and $CheckHeadersOnly)
9400            or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
9401            { # support for old ABI dumps, GCC >= 4.0
9402              # remangling all manually mangled symbols
9403                if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
9404                {
9405                    $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
9406                    $MangledNames{$LibVersion}{$MnglName} = 1;
9407                }
9408            }
9409        }
9410        elsif($Remangle==-1)
9411        { # remove mangling
9412            $MnglName = "";
9413            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
9414        }
9415        if(not $MnglName) {
9416            next;
9417        }
9418        if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
9419        { # NOTE: global data may enter here twice
9420            %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
9421
9422        }
9423        if(not checkDump($LibVersion, "2.6"))
9424        { # support for old dumps
9425          # add "Volatile" attribute
9426            if($MnglName=~/_Z(K|)V/) {
9427                $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
9428            }
9429        }
9430        # symbol and its symlink have same signatures
9431        if($SymVer{$LibVersion}{$MnglName}) {
9432            %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
9433        }
9434
9435        if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"})
9436        {
9437            %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
9438            if($SymVer{$LibVersion}{$Alias}) {
9439                %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
9440            }
9441        }
9442
9443        # clean memory
9444        delete($SymbolInfo{$LibVersion}{$InfoId});
9445    }
9446    if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
9447        translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
9448    }
9449    if($ExtendedCheck)
9450    { # --ext option
9451        addExtension($LibVersion);
9452    }
9453
9454    # clean memory
9455    delete($SymbolInfo{$LibVersion});
9456
9457    foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
9458    { # detect allocable classes with public exported constructors
9459      # or classes with auto-generated or inline-only constructors
9460      # and other temp info
9461        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
9462        {
9463            my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9464            if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
9465            and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
9466            { # Class() { ... } will not be exported
9467                if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
9468                {
9469                    if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
9470                        $AllocableClass{$LibVersion}{$ClassName} = 1;
9471                    }
9472                }
9473            }
9474            if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
9475            { # all imported class methods
9476                if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
9477                {
9478                    if($CheckHeadersOnly)
9479                    {
9480                        if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
9481                        or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
9482                        { # all symbols except non-virtual inline
9483                            $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
9484                        }
9485                    }
9486                    else {
9487                        $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
9488                    }
9489                }
9490                if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
9491                    $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
9492                }
9493            }
9494            $ClassNames{$LibVersion}{$ClassName} = 1;
9495        }
9496        if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
9497        {
9498            my %Base = get_BaseType($RetId, $LibVersion);
9499            if(defined $Base{"Type"}
9500            and $Base{"Type"}=~/Struct|Class/)
9501            {
9502                my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
9503                if($Name=~/<([^<>\s]+)>/)
9504                {
9505                    if(my $Tid = getTypeIdByName($1, $LibVersion)) {
9506                        $ReturnedClass{$LibVersion}{$Tid} = 1;
9507                    }
9508                }
9509                else {
9510                    $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
9511                }
9512            }
9513        }
9514        foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
9515        {
9516            my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
9517            if(get_PLevel($PId, $LibVersion)>=1)
9518            {
9519                if(my %Base = get_BaseType($PId, $LibVersion))
9520                {
9521                    if($Base{"Type"}=~/Struct|Class/)
9522                    {
9523                        $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
9524                        foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
9525                        { # mark all derived classes
9526                            $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
9527                        }
9528                    }
9529                }
9530            }
9531        }
9532
9533        # mapping {short name => symbols}
9534        $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
9535    }
9536    foreach my $MnglName (keys(%VTableClass))
9537    { # reconstruct attributes of v-tables
9538        if(index($MnglName, "_ZTV")==0)
9539        {
9540            if(my $ClassName = $VTableClass{$MnglName})
9541            {
9542                if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9543                {
9544                    $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
9545                    $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId;
9546                }
9547            }
9548        }
9549    }
9550
9551    # types
9552    foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
9553    {
9554        if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
9555        {
9556            if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
9557                $ClassNames{$LibVersion}{$TName} = 1;
9558            }
9559            if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
9560            {
9561                $ClassNames{$LibVersion}{$TName} = 1;
9562                foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
9563                {
9564                    if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
9565                        $ClassNames{$LibVersion}{$BName} = 1;
9566                    }
9567                }
9568            }
9569        }
9570    }
9571}
9572
9573sub getFirst($$)
9574{
9575    my ($Tid, $LibVersion) = @_;
9576    if(not $Tid) {
9577        return $Tid;
9578    }
9579
9580    if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"})
9581    {
9582        if($TName_Tid{$LibVersion}{$Name}) {
9583            return $TName_Tid{$LibVersion}{$Name};
9584        }
9585    }
9586
9587    return $Tid;
9588}
9589
9590sub register_SymbolUsage($$$)
9591{
9592    my ($InfoId, $UsedType, $LibVersion) = @_;
9593
9594    my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
9595    if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion))
9596    {
9597        register_TypeUsage($RTid, $UsedType, $LibVersion);
9598        $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid;
9599    }
9600    if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion))
9601    {
9602        register_TypeUsage($FCid, $UsedType, $LibVersion);
9603        $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid;
9604
9605        if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
9606        { # register "this" pointer
9607            register_TypeUsage($ThisId, $UsedType, $LibVersion);
9608        }
9609        if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion))
9610        { # register "this" pointer (const method)
9611            register_TypeUsage($ThisId_C, $UsedType, $LibVersion);
9612        }
9613    }
9614    foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
9615    {
9616        if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion))
9617        {
9618            register_TypeUsage($PTid, $UsedType, $LibVersion);
9619            $FuncInfo{"Param"}{$PPos}{"type"} = $PTid;
9620        }
9621    }
9622    foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
9623    {
9624        my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
9625        if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
9626            register_TypeUsage($TTid, $UsedType, $LibVersion);
9627        }
9628    }
9629}
9630
9631sub register_TypeUsage($$$)
9632{
9633    my ($TypeId, $UsedType, $LibVersion) = @_;
9634    if(not $TypeId) {
9635        return;
9636    }
9637    if($UsedType->{$TypeId})
9638    { # already registered
9639        return;
9640    }
9641
9642    my %TInfo = get_Type($TypeId, $LibVersion);
9643    if($TInfo{"Type"})
9644    {
9645        if(my $NS = $TInfo{"NameSpace"})
9646        {
9647            if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) {
9648                register_TypeUsage($NSTid, $UsedType, $LibVersion);
9649            }
9650        }
9651
9652        if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/)
9653        {
9654            $UsedType->{$TypeId} = 1;
9655            if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
9656            {
9657                foreach my $BaseId (keys(%{$TInfo{"Base"}})) {
9658                    register_TypeUsage($BaseId, $UsedType, $LibVersion);
9659                }
9660                foreach my $TPos (keys(%{$TInfo{"TParam"}}))
9661                {
9662                    my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
9663                    if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
9664                        register_TypeUsage($TTid, $UsedType, $LibVersion);
9665                    }
9666                }
9667            }
9668            foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
9669            {
9670                if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion))
9671                {
9672                    register_TypeUsage($MTid, $UsedType, $LibVersion);
9673                    $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid;
9674                }
9675            }
9676            if($TInfo{"Type"} eq "FuncPtr"
9677            or $TInfo{"Type"} eq "MethodPtr"
9678            or $TInfo{"Type"} eq "Func")
9679            {
9680                if(my $RTid = $TInfo{"Return"}) {
9681                    register_TypeUsage($RTid, $UsedType, $LibVersion);
9682                }
9683                foreach my $PPos (keys(%{$TInfo{"Param"}}))
9684                {
9685                    if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) {
9686                        register_TypeUsage($PTid, $UsedType, $LibVersion);
9687                    }
9688                }
9689            }
9690            if($TInfo{"Type"} eq "FieldPtr")
9691            {
9692                if(my $RTid = $TInfo{"Return"}) {
9693                    register_TypeUsage($RTid, $UsedType, $LibVersion);
9694                }
9695                if(my $CTid = $TInfo{"Class"}) {
9696                    register_TypeUsage($CTid, $UsedType, $LibVersion);
9697                }
9698            }
9699            if($TInfo{"Type"} eq "MethodPtr")
9700            {
9701                if(my $CTid = $TInfo{"Class"}) {
9702                    register_TypeUsage($CTid, $UsedType, $LibVersion);
9703                }
9704            }
9705        }
9706        elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
9707        {
9708            $UsedType->{$TypeId} = 1;
9709            if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion))
9710            {
9711                register_TypeUsage($BTid, $UsedType, $LibVersion);
9712                $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid;
9713            }
9714        }
9715        else
9716        { # Intrinsic, TemplateParam, TypeName, SizeOf, etc.
9717            $UsedType->{$TypeId} = 1;
9718        }
9719    }
9720}
9721
9722sub selectSymbol($$$$)
9723{ # select symbol to check or to dump
9724    my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
9725
9726    if($Level eq "Dump")
9727    {
9728        if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
9729        { # TODO: check if this symbol is from
9730          # base classes of other target symbols
9731            return 1;
9732        }
9733    }
9734
9735    if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
9736    { # stdc++ interfaces
9737        return 0;
9738    }
9739
9740    my $Target = 0;
9741    if(my $Header = $SInfo->{"Header"}) {
9742        $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
9743    }
9744    if($ExtendedCheck)
9745    {
9746        if(index($Symbol, "external_func_")==0) {
9747            $Target = 1;
9748        }
9749    }
9750    if($CheckHeadersOnly or $Level eq "Source")
9751    {
9752        if($Target)
9753        {
9754            if($Level eq "Dump")
9755            { # dumped
9756                if($BinaryOnly)
9757                {
9758                    if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
9759                        return 1;
9760                    }
9761                }
9762                else {
9763                    return 1;
9764                }
9765            }
9766            elsif($Level eq "Source")
9767            { # checked
9768                return 1;
9769            }
9770            elsif($Level eq "Binary")
9771            { # checked
9772                if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
9773                or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
9774                    return 1;
9775                }
9776            }
9777        }
9778    }
9779    else
9780    { # library is available
9781        if(link_symbol($Symbol, $LibVersion, "-Deps"))
9782        { # exported symbols
9783            return 1;
9784        }
9785        if($Level eq "Dump")
9786        { # dumped
9787            if($BinaryOnly)
9788            {
9789                if($SInfo->{"Data"})
9790                {
9791                    if($Target) {
9792                        return 1;
9793                    }
9794                }
9795            }
9796            else
9797            { # SrcBin
9798                if($Target) {
9799                    return 1;
9800                }
9801            }
9802        }
9803        elsif($Level eq "Source")
9804        { # checked
9805            if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
9806            or isInLineInst($Symbol, $SInfo, $LibVersion))
9807            { # skip LOCAL symbols
9808                if($Target) {
9809                    return 1;
9810                }
9811            }
9812        }
9813        elsif($Level eq "Binary")
9814        { # checked
9815            if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
9816            {
9817                if($Target) {
9818                    return 1;
9819                }
9820            }
9821        }
9822    }
9823    return 0;
9824}
9825
9826sub cleanDump($)
9827{ # clean data
9828    my $LibVersion = $_[0];
9829    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
9830    {
9831        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}}))
9832        {
9833            delete($SymbolInfo{$LibVersion}{$InfoId});
9834            next;
9835        }
9836        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
9837        if(not $MnglName)
9838        {
9839            delete($SymbolInfo{$LibVersion}{$InfoId});
9840            next;
9841        }
9842        my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
9843        if(not $ShortName)
9844        {
9845            delete($SymbolInfo{$LibVersion}{$InfoId});
9846            next;
9847        }
9848        if($MnglName eq $ShortName)
9849        { # remove duplicate data
9850            delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
9851        }
9852        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
9853            delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
9854        }
9855        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
9856            delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
9857        }
9858        delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"});
9859    }
9860    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
9861    {
9862        if(not keys(%{$TypeInfo{$LibVersion}{$Tid}}))
9863        {
9864            delete($TypeInfo{$LibVersion}{$Tid});
9865            next;
9866        }
9867        delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
9868        foreach my $Attr ("Header", "Line", "Size", "NameSpace")
9869        {
9870            if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
9871                delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
9872            }
9873        }
9874        if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
9875            delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
9876        }
9877    }
9878}
9879
9880sub selectType($$)
9881{
9882    my ($Tid, $LibVersion) = @_;
9883
9884    if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
9885    {
9886        if(defined $TypeInfo{$LibVersion}{$Dupl})
9887        {
9888            if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
9889            { # duplicate
9890                return 0;
9891            }
9892        }
9893    }
9894
9895    if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
9896    {
9897        if(not isBuiltIn($THeader))
9898        {
9899            if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
9900            {
9901                if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
9902                {
9903                    if(is_target_header($THeader, $LibVersion))
9904                    { # from target headers
9905                        if(not selfTypedef($Tid, $LibVersion)) {
9906                            return 1;
9907                        }
9908                    }
9909                }
9910            }
9911        }
9912    }
9913    return 0;
9914}
9915
9916sub remove_Unused($$)
9917{ # remove unused data types from the ABI dump
9918    my ($LibVersion, $Kind) = @_;
9919
9920    my %UsedType = ();
9921
9922    foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}}))
9923    {
9924        register_SymbolUsage($InfoId, \%UsedType, $LibVersion);
9925    }
9926    foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
9927    {
9928        if($UsedType{$Tid})
9929        { # All & Extended
9930            next;
9931        }
9932
9933        if($Kind eq "Extended")
9934        {
9935            if(selectType($Tid, $LibVersion))
9936            {
9937                my %Tree = ();
9938                register_TypeUsage($Tid, \%Tree, $LibVersion);
9939
9940                my $Tmpl = 0;
9941                foreach (sort {int($a)<=>int($b)} keys(%Tree))
9942                {
9943                    if(defined $TypeInfo{$LibVersion}{$_}{"Template"}
9944                    or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam")
9945                    {
9946                        $Tmpl = 1;
9947                        last;
9948                    }
9949                }
9950                if(not $Tmpl)
9951                {
9952                    foreach (keys(%Tree)) {
9953                        $UsedType{$_} = 1;
9954                    }
9955                }
9956            }
9957        }
9958    }
9959
9960    my %Delete = ();
9961
9962    foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
9963    { # remove unused types
9964        if($UsedType{$Tid})
9965        { # All & Extended
9966            next;
9967        }
9968
9969        if($Kind eq "Extra")
9970        {
9971            my %Tree = ();
9972            register_TypeUsage($Tid, \%Tree, $LibVersion);
9973
9974            foreach (sort {int($a)<=>int($b)} keys(%Tree))
9975            {
9976                if(defined $TypeInfo{$LibVersion}{$_}{"Template"}
9977                or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam")
9978                {
9979                    $Delete{$Tid} = 1;
9980                    last;
9981                }
9982            }
9983        }
9984        else
9985        {
9986            # remove type
9987            delete($TypeInfo{$LibVersion}{$Tid});
9988        }
9989    }
9990
9991    if($Kind eq "Extra")
9992    { # remove duplicates
9993        foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
9994        {
9995            if($UsedType{$Tid})
9996            { # All & Extended
9997                next;
9998            }
9999
10000            my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"};
10001
10002            if($TName_Tid{$LibVersion}{$Name} ne $Tid) {
10003                delete($TypeInfo{$LibVersion}{$Tid});
10004            }
10005        }
10006    }
10007
10008    foreach my $Tid (keys(%Delete))
10009    {
10010        delete($TypeInfo{$LibVersion}{$Tid});
10011    }
10012}
10013
10014sub check_Completeness($$)
10015{
10016    my ($Info, $LibVersion) = @_;
10017
10018    # data types
10019    if(defined $Info->{"Memb"})
10020    {
10021        foreach my $Pos (keys(%{$Info->{"Memb"}}))
10022        {
10023            if(defined $Info->{"Memb"}{$Pos}{"type"}) {
10024                check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion);
10025            }
10026        }
10027    }
10028    if(defined $Info->{"Base"})
10029    {
10030        foreach my $Bid (keys(%{$Info->{"Base"}})) {
10031            check_TypeInfo($Bid, $LibVersion);
10032        }
10033    }
10034    if(defined $Info->{"BaseType"}) {
10035        check_TypeInfo($Info->{"BaseType"}, $LibVersion);
10036    }
10037    if(defined $Info->{"TParam"})
10038    {
10039        foreach my $Pos (keys(%{$Info->{"TParam"}}))
10040        {
10041            my $TName = $Info->{"TParam"}{$Pos}{"name"};
10042            if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) {
10043                next;
10044            }
10045            if($TName eq "_BoolType") {
10046                next;
10047            }
10048            if($TName=~/\Asizeof\(/) {
10049                next;
10050            }
10051            if(my $Tid = $TName_Tid{$LibVersion}{$TName}) {
10052                check_TypeInfo($Tid, $LibVersion);
10053            }
10054            else
10055            {
10056                if(defined $Debug) {
10057                    printMsg("WARNING", "missed type $TName");
10058                }
10059            }
10060        }
10061    }
10062
10063    # symbols
10064    if(defined $Info->{"Param"})
10065    {
10066        foreach my $Pos (keys(%{$Info->{"Param"}}))
10067        {
10068            if(defined $Info->{"Param"}{$Pos}{"type"}) {
10069                check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion);
10070            }
10071        }
10072    }
10073    if(defined $Info->{"Return"}) {
10074        check_TypeInfo($Info->{"Return"}, $LibVersion);
10075    }
10076    if(defined $Info->{"Class"}) {
10077        check_TypeInfo($Info->{"Class"}, $LibVersion);
10078    }
10079}
10080
10081sub check_TypeInfo($$)
10082{
10083    my ($Tid, $LibVersion) = @_;
10084
10085    if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) {
10086        return;
10087    }
10088    $CheckedTypeInfo{$LibVersion}{$Tid} = 1;
10089
10090    if(defined $TypeInfo{$LibVersion}{$Tid})
10091    {
10092        if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) {
10093            printMsg("ERROR", "missed type name ($Tid)");
10094        }
10095        check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion);
10096    }
10097    else {
10098        printMsg("ERROR", "missed type id $Tid");
10099    }
10100}
10101
10102sub selfTypedef($$)
10103{
10104    my ($TypeId, $LibVersion) = @_;
10105    my %Type = get_Type($TypeId, $LibVersion);
10106    if($Type{"Type"} eq "Typedef")
10107    {
10108        my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
10109        if($Base{"Type"}=~/Class|Struct/)
10110        {
10111            if($Type{"Name"} eq $Base{"Name"}) {
10112                return 1;
10113            }
10114            elsif($Type{"Name"}=~/::(\w+)\Z/)
10115            {
10116                if($Type{"Name"} eq $Base{"Name"}."::".$1)
10117                { # QPointer<QWidget>::QPointer
10118                    return 1;
10119                }
10120            }
10121        }
10122    }
10123    return 0;
10124}
10125
10126sub addExtension($)
10127{
10128    my $LibVersion = $_[0];
10129    foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
10130    {
10131        if(selectType($Tid, $LibVersion))
10132        {
10133            my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"};
10134            $TName=~s/\A(struct|union|class|enum) //;
10135            my $Symbol = "external_func_".$TName;
10136
10137            %{$CompleteSignature{$LibVersion}{$Symbol}} = (
10138                "Header" => "extended.h",
10139                "ShortName" => $Symbol,
10140                "MnglName" => $Symbol,
10141                "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
10142            );
10143
10144            $ExtendedSymbols{$Symbol} = 1;
10145            $CheckedSymbols{"Binary"}{$Symbol} = 1;
10146            $CheckedSymbols{"Source"}{$Symbol} = 1;
10147        }
10148    }
10149    $ExtendedSymbols{"external_func_0"} = 1;
10150    $CheckedSymbols{"Binary"}{"external_func_0"} = 1;
10151    $CheckedSymbols{"Source"}{"external_func_0"} = 1;
10152}
10153
10154sub findMethod($$$)
10155{
10156    my ($VirtFunc, $ClassId, $LibVersion) = @_;
10157    foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
10158    {
10159        if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
10160            return $VirtMethodInClass;
10161        }
10162        elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
10163            return $VirtMethodInBaseClasses;
10164        }
10165    }
10166    return "";
10167}
10168
10169sub findMethod_Class($$$)
10170{
10171    my ($VirtFunc, $ClassId, $LibVersion) = @_;
10172    my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
10173    return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
10174    my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
10175    my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
10176    foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
10177    { # search for interface with the same parameters suffix (overridden)
10178        if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
10179        {
10180            if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
10181            {
10182                if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
10183                {
10184                    if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
10185                    or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
10186                    or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
10187                        return $Candidate;
10188                    }
10189                }
10190            }
10191            else
10192            {
10193                if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
10194                    return $Candidate;
10195                }
10196            }
10197        }
10198    }
10199    return "";
10200}
10201
10202sub registerVTable($)
10203{
10204    my $LibVersion = $_[0];
10205    foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
10206    {
10207        if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
10208        or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
10209        {
10210            my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
10211            next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
10212            if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
10213            and $Symbol=~/D2E/)
10214            { # pure virtual D2-destructors are marked as "virt" in the dump
10215              # virtual D2-destructors are NOT marked as "virt" in the dump
10216              # both destructors are not presented in the v-table
10217                next;
10218            }
10219            my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
10220            $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
10221        }
10222    }
10223}
10224
10225sub registerOverriding($)
10226{
10227    my $LibVersion = $_[0];
10228    my @Classes = keys(%{$VirtualTable{$LibVersion}});
10229    @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
10230    foreach my $ClassName (@Classes)
10231    {
10232        foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
10233        {
10234            if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
10235            { # pure virtuals
10236                next;
10237            }
10238            my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
10239            if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
10240            {
10241                if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
10242                or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
10243                { # both overridden virtual methods
10244                  # and implemented pure virtual methods
10245                    $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
10246                    $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
10247                    delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
10248                }
10249            }
10250        }
10251        if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
10252            delete($VirtualTable{$LibVersion}{$ClassName});
10253        }
10254    }
10255}
10256
10257sub setVirtFuncPositions($)
10258{
10259    my $LibVersion = $_[0];
10260    foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
10261    {
10262        my ($Num, $Rel) = (1, 0);
10263
10264        if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
10265        {
10266            if($UsedDump{$LibVersion}{"DWARF"}) {
10267                @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs;
10268            }
10269            else {
10270                @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs;
10271            }
10272            foreach my $VirtFunc (@Funcs)
10273            {
10274                if($UsedDump{$LibVersion}{"DWARF"}) {
10275                    $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"};
10276                }
10277                else {
10278                    $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++;
10279                }
10280
10281                # set relative positions
10282                if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
10283                and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
10284                { # relative position excluding added and removed virtual functions
10285                    if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
10286                    and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
10287                        $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++;
10288                    }
10289                }
10290            }
10291        }
10292    }
10293    foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
10294    {
10295        my $AbsNum = 1;
10296        foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
10297            $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++;
10298        }
10299    }
10300}
10301
10302sub get_sub_classes($$$)
10303{
10304    my ($ClassId, $LibVersion, $Recursive) = @_;
10305    return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
10306    my @Subs = ();
10307    foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
10308    {
10309        if($Recursive)
10310        {
10311            foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
10312                push(@Subs, $SubSubId);
10313            }
10314        }
10315        push(@Subs, $SubId);
10316    }
10317    return @Subs;
10318}
10319
10320sub get_base_classes($$$)
10321{
10322    my ($ClassId, $LibVersion, $Recursive) = @_;
10323    my %ClassType = get_Type($ClassId, $LibVersion);
10324    return () if(not defined $ClassType{"Base"});
10325    my @Bases = ();
10326    foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
10327    keys(%{$ClassType{"Base"}}))
10328    {
10329        if($Recursive)
10330        {
10331            foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
10332                push(@Bases, $SubBaseId);
10333            }
10334        }
10335        push(@Bases, $BaseId);
10336    }
10337    return @Bases;
10338}
10339
10340sub getVTable_Model($$)
10341{ # return an ordered list of v-table elements
10342    my ($ClassId, $LibVersion) = @_;
10343    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
10344    my @Elements = ();
10345    foreach my $BaseId (@Bases, $ClassId)
10346    {
10347        if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
10348        {
10349            if(defined $VirtualTable{$LibVersion}{$BName})
10350            {
10351                my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}});
10352                if($UsedDump{$LibVersion}{"DWARF"}) {
10353                    @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs;
10354                }
10355                else {
10356                    @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs;
10357                }
10358                foreach my $VFunc (@VFuncs) {
10359                    push(@Elements, $VFunc);
10360                }
10361            }
10362        }
10363    }
10364    return @Elements;
10365}
10366
10367sub getVShift($$)
10368{
10369    my ($ClassId, $LibVersion) = @_;
10370    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
10371    my $VShift = 0;
10372    foreach my $BaseId (@Bases)
10373    {
10374        if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
10375        {
10376            if(defined $VirtualTable{$LibVersion}{$BName}) {
10377                $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
10378            }
10379        }
10380    }
10381    return $VShift;
10382}
10383
10384sub getShift($$)
10385{
10386    my ($ClassId, $LibVersion) = @_;
10387    my @Bases = get_base_classes($ClassId, $LibVersion, 0);
10388    my $Shift = 0;
10389    foreach my $BaseId (@Bases)
10390    {
10391        if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
10392        {
10393            if($Size!=1)
10394            { # not empty base class
10395                $Shift+=$Size;
10396            }
10397        }
10398    }
10399    return $Shift;
10400}
10401
10402sub getVTable_Size($$)
10403{ # number of v-table elements
10404    my ($ClassName, $LibVersion) = @_;
10405    my $Size = 0;
10406    # three approaches
10407    if(not $Size)
10408    { # real size
10409        if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
10410            $Size = keys(%VTable);
10411        }
10412    }
10413    if(not $Size)
10414    { # shared library symbol size
10415        if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
10416            $Size /= $WORD_SIZE{$LibVersion};
10417        }
10418    }
10419    if(not $Size)
10420    { # model size
10421        if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
10422            $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
10423        }
10424    }
10425    return $Size;
10426}
10427
10428sub isCopyingClass($$)
10429{
10430    my ($TypeId, $LibVersion) = @_;
10431    return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
10432}
10433
10434sub isLeafClass($$)
10435{
10436    my ($ClassId, $LibVersion) = @_;
10437    return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
10438}
10439
10440sub havePubFields($)
10441{ # check structured type for public fields
10442    return isAccessible($_[0], {}, 0, -1);
10443}
10444
10445sub isAccessible($$$$)
10446{ # check interval in structured type for public fields
10447    my ($TypePtr, $Skip, $Start, $End) = @_;
10448    return 0 if(not $TypePtr);
10449    if($End==-1) {
10450        $End = keys(%{$TypePtr->{"Memb"}})-1;
10451    }
10452    foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
10453    {
10454        if($Skip and $Skip->{$MemPos})
10455        { # skip removed/added fields
10456            next;
10457        }
10458        if(int($MemPos)>=$Start and int($MemPos)<=$End)
10459        {
10460            if(isPublic($TypePtr, $MemPos)) {
10461                return ($MemPos+1);
10462            }
10463        }
10464    }
10465    return 0;
10466}
10467
10468sub isReserved($)
10469{ # reserved fields == private
10470    my $MName = $_[0];
10471    if($MName=~/reserved|padding|f_spare/i) {
10472        return 1;
10473    }
10474    if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
10475        return 1;
10476    }
10477    if($MName=~/(pad\d+)/i) {
10478        return 1;
10479    }
10480    return 0;
10481}
10482
10483sub isPublic($$)
10484{
10485    my ($TypePtr, $FieldPos) = @_;
10486    return 0 if(not $TypePtr);
10487    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
10488    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
10489    if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
10490    { # by name in C language
10491      # FIXME: add other methods to detect private members
10492        my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
10493        if($MName=~/priv|abidata|parent_object/i)
10494        { # C-styled private data
10495            return 0;
10496        }
10497        if(lc($MName) eq "abi")
10498        { # ABI information/reserved field
10499            return 0;
10500        }
10501        if(isReserved($MName))
10502        { # reserved fields
10503            return 0;
10504        }
10505        return 1;
10506    }
10507    elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
10508    { # by access in C++ language
10509        return 1;
10510    }
10511    return 0;
10512}
10513
10514sub getVTable_Real($$)
10515{
10516    my ($ClassName, $LibVersion) = @_;
10517    if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
10518    {
10519        my %Type = get_Type($ClassId, $LibVersion);
10520        if(defined $Type{"VTable"}) {
10521            return %{$Type{"VTable"}};
10522        }
10523    }
10524    return ();
10525}
10526
10527sub cmpVTables($)
10528{
10529    my $ClassName = $_[0];
10530    my $Res = cmpVTables_Real($ClassName, 1);
10531    if($Res==-1) {
10532        $Res = cmpVTables_Model($ClassName);
10533    }
10534    return $Res;
10535}
10536
10537sub cmpVTables_Model($)
10538{
10539    my $ClassName = $_[0];
10540    foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
10541    {
10542        if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
10543            return 1;
10544        }
10545    }
10546    return 0;
10547}
10548
10549sub cmpVTables_Real($$)
10550{
10551    my ($ClassName, $Strong) = @_;
10552    if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
10553        return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
10554    }
10555    my %VTable_Old = getVTable_Real($ClassName, 1);
10556    my %VTable_New = getVTable_Real($ClassName, 2);
10557    if(not %VTable_Old or not %VTable_New)
10558    { # old ABI dumps
10559        return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
10560    }
10561    my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
10562    foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
10563    {
10564        if(not defined $VTable_Old{$Offset})
10565        { # v-table v.1 < v-table v.2
10566            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
10567        }
10568        my $Entry1 = $VTable_Old{$Offset};
10569        if(not defined $VTable_New{$Offset})
10570        { # v-table v.1 > v-table v.2
10571            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
10572        }
10573        my $Entry2 = $VTable_New{$Offset};
10574        $Entry1 = simpleVEntry($Entry1);
10575        $Entry2 = simpleVEntry($Entry2);
10576        if($Entry1 ne $Entry2)
10577        { # register as changed
10578            if($Entry1=~/::([^:]+)\Z/)
10579            {
10580                my $M1 = $1;
10581                if($Entry2=~/::([^:]+)\Z/)
10582                {
10583                    my $M2 = $1;
10584                    if($M1 eq $M2)
10585                    { # overridden
10586                        next;
10587                    }
10588                }
10589            }
10590            if(differentDumps("G"))
10591            {
10592                if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
10593                {
10594                    # GCC 4.6.1: -0x00000000000000010
10595                    # GCC 4.7.0: -16
10596                    next;
10597                }
10598            }
10599            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
10600        }
10601    }
10602    return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
10603}
10604
10605sub mergeVTables($)
10606{ # merging v-tables without diagnostics
10607    my $Level = $_[0];
10608    foreach my $ClassName (keys(%{$VirtualTable{1}}))
10609    {
10610        if($VTableChanged_M{$ClassName})
10611        { # already registered
10612            next;
10613        }
10614        if(cmpVTables_Real($ClassName, 0)==1)
10615        {
10616            my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
10617            foreach my $Symbol (@Affected)
10618            {
10619                %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
10620                    "Type_Name"=>$ClassName,
10621                    "Target"=>$ClassName);
10622            }
10623        }
10624    }
10625}
10626
10627sub mergeBases($)
10628{
10629    my $Level = $_[0];
10630    foreach my $ClassName (keys(%{$ClassNames{1}}))
10631    { # detect added and removed virtual functions
10632        my $ClassId = $TName_Tid{1}{$ClassName};
10633        next if(not $ClassId);
10634        if(defined $VirtualTable{2}{$ClassName})
10635        {
10636            foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
10637            {
10638                if($TName_Tid{1}{$ClassName}
10639                and not defined $VirtualTable{1}{$ClassName}{$Symbol})
10640                { # added to v-table
10641                    if(defined $CompleteSignature{1}{$Symbol}
10642                    and $CompleteSignature{1}{$Symbol}{"Virt"})
10643                    { # override some method in v.1
10644                        next;
10645                    }
10646                    $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
10647                }
10648            }
10649        }
10650        if(defined $VirtualTable{1}{$ClassName})
10651        {
10652            foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
10653            {
10654                if($TName_Tid{2}{$ClassName}
10655                and not defined $VirtualTable{2}{$ClassName}{$Symbol})
10656                { # removed from v-table
10657                    if(defined $CompleteSignature{2}{$Symbol}
10658                    and $CompleteSignature{2}{$Symbol}{"Virt"})
10659                    { # override some method in v.2
10660                        next;
10661                    }
10662                    $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
10663                }
10664            }
10665        }
10666        if($Level eq "Binary")
10667        { # Binary-level
10668            my %Class_Type = get_Type($ClassId, 1);
10669            foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
10670            { # check replacements, including pure virtual methods
10671                my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
10672                foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
10673                {
10674                    my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
10675                    if($AddedPos==$RemovedPos)
10676                    {
10677                        $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
10678                        $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
10679                        last; # other methods will be reported as "added" or "removed"
10680                    }
10681                }
10682                if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
10683                {
10684                    if(lc($AddedVFunc) eq lc($RemovedVFunc))
10685                    { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
10686                        next;
10687                    }
10688                    my $ProblemType = "Virtual_Replacement";
10689                    my @Affected = ($RemovedVFunc);
10690                    if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10691                    { # pure methods
10692                        if(not isUsedClass($ClassId, 1, $Level))
10693                        { # not a parameter of some exported method
10694                            next;
10695                        }
10696                        $ProblemType = "Pure_Virtual_Replacement";
10697
10698                        # affected all methods (both virtual and non-virtual ones)
10699                        @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
10700                        push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
10701                    }
10702                    $VTableChanged_M{$ClassName}=1;
10703                    foreach my $AffectedInt (@Affected)
10704                    {
10705                        if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
10706                        { # affected exported methods only
10707                            next;
10708                        }
10709                        if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
10710                            next;
10711                        }
10712                        %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10713                            "Type_Name"=>$Class_Type{"Name"},
10714                            "Target"=>get_Signature($AddedVFunc, 2),
10715                            "Old_Value"=>get_Signature($RemovedVFunc, 1));
10716                    }
10717                }
10718            }
10719        }
10720    }
10721    if(not checkDump(1, "2.0")
10722    or not checkDump(2, "2.0"))
10723    { # support for old ABI dumps
10724      # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
10725        return;
10726    }
10727    foreach my $ClassName (sort keys(%{$ClassNames{1}}))
10728    {
10729        my $ClassId_Old = $TName_Tid{1}{$ClassName};
10730        next if(not $ClassId_Old);
10731        if(not isCreatable($ClassId_Old, 1))
10732        { # skip classes without public constructors (including auto-generated)
10733          # example: class has only a private exported or private inline constructor
10734            next;
10735        }
10736        if($ClassName=~/>/)
10737        { # skip affected template instances
10738            next;
10739        }
10740        my %Class_Old = get_Type($ClassId_Old, 1);
10741        my $ClassId_New = $TName_Tid{2}{$ClassName};
10742        if(not $ClassId_New) {
10743            next;
10744        }
10745        my %Class_New = get_Type($ClassId_New, 2);
10746        if($Class_New{"Type"}!~/Class|Struct/)
10747        { # became typedef
10748            if($Level eq "Binary") {
10749                next;
10750            }
10751            if($Level eq "Source")
10752            {
10753                %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
10754                if($Class_New{"Type"}!~/Class|Struct/) {
10755                    next;
10756                }
10757                $ClassId_New = $Class_New{"Tid"};
10758            }
10759        }
10760        my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
10761        my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
10762
10763        my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
10764        my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
10765
10766        my ($BNum1, $BNum2) = (1, 1);
10767        my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
10768        my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
10769        my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old;
10770        my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New;
10771        my $Shift_Old = getShift($ClassId_Old, 1);
10772        my $Shift_New = getShift($ClassId_New, 2);
10773        my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
10774        my ($Added, $Removed) = (0, 0);
10775        my @StableBases_Old = ();
10776        foreach my $BaseId (@Bases_Old)
10777        {
10778            my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
10779            if($BasePos_New{$Tr_Old{$BaseName}}) {
10780                push(@StableBases_Old, $BaseId);
10781            }
10782            elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
10783            and not $ShortBase_New{get_ShortClass($BaseId, 1)})
10784            { # removed base
10785              # excluding namespace::SomeClass to SomeClass renaming
10786                my $ProblemKind = "Removed_Base_Class";
10787                if($Level eq "Binary")
10788                { # Binary-level
10789                    if($Shift_Old ne $Shift_New)
10790                    { # affected fields
10791                        if(havePubFields(\%Class_Old)) {
10792                            $ProblemKind .= "_And_Shift";
10793                        }
10794                        elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
10795                            $ProblemKind .= "_And_Size";
10796                        }
10797                    }
10798                    if(keys(%{$VirtualTable_Model{1}{$BaseName}})
10799                    and cmpVTables($ClassName)==1)
10800                    { # affected v-table
10801                        $ProblemKind .= "_And_VTable";
10802                        $VTableChanged_M{$ClassName}=1;
10803                    }
10804                }
10805                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
10806                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
10807                {
10808                    if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
10809                    {
10810                        push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
10811                        if($ProblemKind=~/VTable/) {
10812                            $VTableChanged_M{$SubName}=1;
10813                        }
10814                    }
10815                }
10816                foreach my $Interface (@Affected)
10817                {
10818                    if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10819                        next;
10820                    }
10821                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
10822                        "Type_Name"=>$ClassName,
10823                        "Target"=>$BaseName,
10824                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
10825                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
10826                        "Shift"=>abs($Shift_New-$Shift_Old)  );
10827                }
10828                $Removed+=1;
10829            }
10830        }
10831        my @StableBases_New = ();
10832        foreach my $BaseId (@Bases_New)
10833        {
10834            my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
10835            if($BasePos_Old{$Tr_New{$BaseName}}) {
10836                push(@StableBases_New, $BaseId);
10837            }
10838            elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
10839            and not $ShortBase_Old{get_ShortClass($BaseId, 2)})
10840            { # added base
10841              # excluding namespace::SomeClass to SomeClass renaming
10842                my $ProblemKind = "Added_Base_Class";
10843                if($Level eq "Binary")
10844                { # Binary-level
10845                    if($Shift_Old ne $Shift_New)
10846                    { # affected fields
10847                        if(havePubFields(\%Class_Old)) {
10848                            $ProblemKind .= "_And_Shift";
10849                        }
10850                        elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
10851                            $ProblemKind .= "_And_Size";
10852                        }
10853                    }
10854                    if(keys(%{$VirtualTable_Model{2}{$BaseName}})
10855                    and cmpVTables($ClassName)==1)
10856                    { # affected v-table
10857                        $ProblemKind .= "_And_VTable";
10858                        $VTableChanged_M{$ClassName}=1;
10859                    }
10860                }
10861                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
10862                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
10863                {
10864                    if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
10865                    {
10866                        push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
10867                        if($ProblemKind=~/VTable/) {
10868                            $VTableChanged_M{$SubName}=1;
10869                        }
10870                    }
10871                }
10872                foreach my $Interface (@Affected)
10873                {
10874                    if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10875                        next;
10876                    }
10877                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
10878                        "Type_Name"=>$ClassName,
10879                        "Target"=>$BaseName,
10880                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
10881                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
10882                        "Shift"=>abs($Shift_New-$Shift_Old)  );
10883                }
10884                $Added+=1;
10885            }
10886        }
10887        if($Level eq "Binary")
10888        { # Binary-level
10889            ($BNum1, $BNum2) = (1, 1);
10890            my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
10891            my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
10892            foreach my $BaseId (@Bases_Old)
10893            {
10894                my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
10895                if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
10896                {
10897                    my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
10898                    my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
10899                    if($NewPos!=$OldPos)
10900                    { # changed position of the base class
10901                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
10902                        {
10903                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10904                                next;
10905                            }
10906                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
10907                                "Type_Name"=>$ClassName,
10908                                "Target"=>$BaseName,
10909                                "Old_Value"=>$OldPos-1,
10910                                "New_Value"=>$NewPos-1  );
10911                        }
10912                    }
10913                    if($Class_Old{"Base"}{$BaseId}{"virtual"}
10914                    and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
10915                    { # became non-virtual base
10916                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
10917                        {
10918                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10919                                next;
10920                            }
10921                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
10922                                "Type_Name"=>$ClassName,
10923                                "Target"=>$BaseName  );
10924                        }
10925                    }
10926                    elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
10927                    and $Class_New{"Base"}{$BaseNewId}{"virtual"})
10928                    { # became virtual base
10929                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
10930                        {
10931                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10932                                next;
10933                            }
10934                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
10935                                "Type_Name"=>$ClassName,
10936                                "Target"=>$BaseName  );
10937                        }
10938                    }
10939                }
10940            }
10941            # detect size changes in base classes
10942            if($Shift_Old!=$Shift_New)
10943            { # size of allocable class
10944                foreach my $BaseId (@StableBases_Old)
10945                { # search for changed base
10946                    my %BaseType = get_Type($BaseId, 1);
10947                    my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
10948                    my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
10949                    if($Size_Old ne $Size_New
10950                    and $Size_Old and $Size_New)
10951                    {
10952                        my $ProblemType = "";
10953                        if(isCopyingClass($BaseId, 1)) {
10954                            $ProblemType = "Size_Of_Copying_Class";
10955                        }
10956                        elsif($AllocableClass{1}{$BaseType{"Name"}})
10957                        {
10958                            if($Size_New>$Size_Old)
10959                            { # increased size
10960                                $ProblemType = "Size_Of_Allocable_Class_Increased";
10961                            }
10962                            else
10963                            { # decreased size
10964                                $ProblemType = "Size_Of_Allocable_Class_Decreased";
10965                                if(not havePubFields(\%Class_Old))
10966                                { # affected class has no public members
10967                                    next;
10968                                }
10969                            }
10970                        }
10971                        next if(not $ProblemType);
10972                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
10973                        { # base class size changes affecting current class
10974                            if(not symbolFilter($Interface, 1, "Affected", $Level)) {
10975                                next;
10976                            }
10977                            %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
10978                                "Type_Name"=>$BaseType{"Name"},
10979                                "Target"=>$BaseType{"Name"},
10980                                "Old_Size"=>$Size_Old*$BYTE_SIZE,
10981                                "New_Size"=>$Size_New*$BYTE_SIZE  );
10982                        }
10983                    }
10984                }
10985            }
10986            if(defined $VirtualTable_Model{1}{$ClassName}
10987            and cmpVTables_Real($ClassName, 1)==1
10988            and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
10989            { # compare virtual tables size in base classes
10990                my $VShift_Old = getVShift($ClassId_Old, 1);
10991                my $VShift_New = getVShift($ClassId_New, 2);
10992                if($VShift_Old ne $VShift_New)
10993                { # changes in the base class or changes in the list of base classes
10994                    my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
10995                    my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
10996                    ($BNum1, $BNum2) = (1, 1);
10997                    my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
10998                    foreach my $BaseId (@AllBases_Old)
10999                    {
11000                        my %BaseType = get_Type($BaseId, 1);
11001                        if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
11002                        { # lost base
11003                            next;
11004                        }
11005                        my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
11006                        my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
11007                        if($VSize_Old!=$VSize_New)
11008                        {
11009                            foreach my $Symbol (@VFunctions)
11010                            { # TODO: affected non-virtual methods?
11011                                if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
11012                                { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
11013                                    next;
11014                                }
11015                                if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
11016                                { # skip interfaces that have not changed the absolute virtual position
11017                                    next;
11018                                }
11019                                if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
11020                                    next;
11021                                }
11022                                $VTableChanged_M{$BaseType{"Name"}} = 1;
11023                                $VTableChanged_M{$ClassName} = 1;
11024                                foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
11025                                { # the reason of the layout change: added virtual functions
11026                                    next if($VirtualReplacement{$VirtFunc});
11027                                    my $ProblemType = "Added_Virtual_Method";
11028                                    if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
11029                                        $ProblemType = "Added_Pure_Virtual_Method";
11030                                    }
11031                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
11032                                        "Type_Name"=>$BaseType{"Name"},
11033                                        "Target"=>get_Signature($VirtFunc, 2)  );
11034                                }
11035                                foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
11036                                { # the reason of the layout change: removed virtual functions
11037                                    next if($VirtualReplacement{$VirtFunc});
11038                                    my $ProblemType = "Removed_Virtual_Method";
11039                                    if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
11040                                        $ProblemType = "Removed_Pure_Virtual_Method";
11041                                    }
11042                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
11043                                        "Type_Name"=>$BaseType{"Name"},
11044                                        "Target"=>get_Signature($VirtFunc, 1)  );
11045                                }
11046                            }
11047                        }
11048                    }
11049                }
11050            }
11051        }
11052    }
11053}
11054
11055sub isCreatable($$)
11056{
11057    my ($ClassId, $LibVersion) = @_;
11058    if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
11059    or isCopyingClass($ClassId, $LibVersion)) {
11060        return 1;
11061    }
11062    if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
11063    { # Fix for incomplete data: if this class has
11064      # a base class then it should also has a constructor
11065        return 1;
11066    }
11067    if($ReturnedClass{$LibVersion}{$ClassId})
11068    { # returned by some method of this class
11069      # or any other class
11070        return 1;
11071    }
11072    return 0;
11073}
11074
11075sub isUsedClass($$$)
11076{
11077    my ($ClassId, $LibVersion, $Level) = @_;
11078    if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
11079    { # parameter of some exported method
11080        return 1;
11081    }
11082    my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
11083    if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
11084    { # method from target class
11085        return 1;
11086    }
11087    return 0;
11088}
11089
11090sub mergeVirtualTables($$)
11091{ # check for changes in the virtual table
11092    my ($Interface, $Level) = @_;
11093    # affected methods:
11094    #  - virtual
11095    #  - pure-virtual
11096    #  - non-virtual
11097    if($CompleteSignature{1}{$Interface}{"Data"})
11098    { # global data is not affected
11099        return;
11100    }
11101    my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
11102    if(not $Class_Id) {
11103        return;
11104    }
11105    my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
11106    if(cmpVTables_Real($CName, 1)==0)
11107    { # no changes
11108        return;
11109    }
11110    $CheckedTypes{$Level}{$CName} = 1;
11111    if($Level eq "Binary")
11112    { # Binary-level
11113        if($CompleteSignature{1}{$Interface}{"PureVirt"}
11114        and not isUsedClass($Class_Id, 1, $Level))
11115        { # pure virtuals should not be affected
11116          # if there are no exported methods using this class
11117            return;
11118        }
11119    }
11120    foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
11121    {
11122        if(defined $VirtualTable{2}{$CName}{$Func}
11123        and defined $CompleteSignature{2}{$Func})
11124        {
11125            if(not $CompleteSignature{1}{$Func}{"PureVirt"}
11126            and $CompleteSignature{2}{$Func}{"PureVirt"})
11127            { # became pure virtual
11128                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
11129                    "Type_Name"=>$CName,
11130                    "Target"=>get_Signature_M($Func, 1)  );
11131                $VTableChanged_M{$CName} = 1;
11132            }
11133            elsif($CompleteSignature{1}{$Func}{"PureVirt"}
11134            and not $CompleteSignature{2}{$Func}{"PureVirt"})
11135            { # became non-pure virtual
11136                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
11137                    "Type_Name"=>$CName,
11138                    "Target"=>get_Signature_M($Func, 1)  );
11139                $VTableChanged_M{$CName} = 1;
11140            }
11141        }
11142    }
11143    if($Level eq "Binary")
11144    { # Binary-level
11145        # check virtual table structure
11146        foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
11147        {
11148            next if($Interface eq $AddedVFunc);
11149            next if($VirtualReplacement{$AddedVFunc});
11150            my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
11151            if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
11152            { # pure virtual methods affect all others (virtual and non-virtual)
11153                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
11154                    "Type_Name"=>$CName,
11155                    "Target"=>get_Signature($AddedVFunc, 2)  );
11156                $VTableChanged_M{$CName} = 1;
11157            }
11158            elsif(not defined $VirtualTable{1}{$CName}
11159            or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
11160            { # added virtual function at the end of v-table
11161                if(not keys(%{$VirtualTable_Model{1}{$CName}}))
11162                { # became polymorphous class, added v-table pointer
11163                    %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
11164                        "Type_Name"=>$CName,
11165                        "Target"=>get_Signature($AddedVFunc, 2)  );
11166                    $VTableChanged_M{$CName} = 1;
11167                }
11168                else
11169                {
11170                    my $VSize_Old = getVTable_Size($CName, 1);
11171                    my $VSize_New = getVTable_Size($CName, 2);
11172                    next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
11173                    if(isCopyingClass($Class_Id, 1))
11174                    { # class has no constructors and v-table will be copied by applications, this may affect all methods
11175                        my $ProblemType = "Added_Virtual_Method";
11176                        if(isLeafClass($Class_Id, 1)) {
11177                            $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
11178                        }
11179                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
11180                            "Type_Name"=>$CName,
11181                            "Target"=>get_Signature($AddedVFunc, 2)  );
11182                        $VTableChanged_M{$CName} = 1;
11183                    }
11184                    else
11185                    {
11186                        my $ProblemType = "Added_Virtual_Method";
11187                        if(isLeafClass($Class_Id, 1)) {
11188                            $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
11189                        }
11190                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
11191                            "Type_Name"=>$CName,
11192                            "Target"=>get_Signature($AddedVFunc, 2)  );
11193                        $VTableChanged_M{$CName} = 1;
11194                    }
11195                }
11196            }
11197            elsif($CompleteSignature{1}{$Interface}{"Virt"}
11198            or $CompleteSignature{1}{$Interface}{"PureVirt"})
11199            {
11200                if(defined $VirtualTable{1}{$CName}
11201                and defined $VirtualTable{2}{$CName})
11202                {
11203                    my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
11204                    my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
11205
11206                    if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
11207                    {
11208                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
11209                        foreach my $ASymbol (@Affected)
11210                        {
11211                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
11212                            {
11213                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
11214                                    next;
11215                                }
11216                            }
11217                            $CheckedSymbols{$Level}{$ASymbol} = 1;
11218                            %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
11219                                "Type_Name"=>$CName,
11220                                "Target"=>get_Signature($AddedVFunc, 2)  );
11221                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
11222                        }
11223                    }
11224                }
11225            }
11226            else {
11227                # safe
11228            }
11229        }
11230        foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
11231        {
11232            next if($VirtualReplacement{$RemovedVFunc});
11233            if($RemovedVFunc eq $Interface
11234            and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
11235            { # This case is for removed virtual methods
11236              # implemented in both versions of a library
11237                next;
11238            }
11239            if(not keys(%{$VirtualTable_Model{2}{$CName}}))
11240            { # became non-polymorphous class, removed v-table pointer
11241                %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
11242                    "Type_Name"=>$CName,
11243                    "Target"=>get_Signature($RemovedVFunc, 1)  );
11244                $VTableChanged_M{$CName} = 1;
11245            }
11246            elsif($CompleteSignature{1}{$Interface}{"Virt"}
11247            or $CompleteSignature{1}{$Interface}{"PureVirt"})
11248            {
11249                if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
11250                {
11251                    if(not defined $VirtualTable{1}{$CName}{$Interface}) {
11252                        next;
11253                    }
11254                    my $VPos_New = -1;
11255                    if(defined $VirtualTable{2}{$CName}{$Interface})
11256                    {
11257                        $VPos_New = $VirtualTable{2}{$CName}{$Interface};
11258                    }
11259                    else
11260                    {
11261                        if($Interface ne $RemovedVFunc) {
11262                            next;
11263                        }
11264                    }
11265                    my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
11266                    my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
11267                    if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
11268                    {
11269                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
11270                        foreach my $ASymbol (@Affected)
11271                        {
11272                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
11273                            {
11274                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
11275                                    next;
11276                                }
11277                            }
11278                            my $ProblemType = "Removed_Virtual_Method";
11279                            if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
11280                                $ProblemType = "Removed_Pure_Virtual_Method";
11281                            }
11282                            $CheckedSymbols{$Level}{$ASymbol} = 1;
11283                            %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
11284                                "Type_Name"=>$CName,
11285                                "Target"=>get_Signature($RemovedVFunc, 1)  );
11286                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
11287                        }
11288                    }
11289                }
11290            }
11291        }
11292    }
11293    else
11294    { # Source-level
11295        foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
11296        {
11297            next if($Interface eq $AddedVFunc);
11298            if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
11299            {
11300                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
11301                    "Type_Name"=>$CName,
11302                    "Target"=>get_Signature($AddedVFunc, 2)  );
11303            }
11304        }
11305        foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
11306        {
11307            if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
11308            {
11309                %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
11310                    "Type_Name"=>$CName,
11311                    "Target"=>get_Signature($RemovedVFunc, 1)  );
11312            }
11313        }
11314    }
11315}
11316
11317sub find_MemberPair_Pos_byName($$)
11318{
11319    my ($Member_Name, $Pair_Type) = @_;
11320    $Member_Name=~s/\A[_]+|[_]+\Z//g;
11321    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
11322    {
11323        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
11324        {
11325            my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
11326            $Name=~s/\A[_]+|[_]+\Z//g;
11327            if($Name eq $Member_Name) {
11328                return $MemberPair_Pos;
11329            }
11330        }
11331    }
11332    return "lost";
11333}
11334
11335sub find_MemberPair_Pos_byVal($$)
11336{
11337    my ($Member_Value, $Pair_Type) = @_;
11338    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
11339    {
11340        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
11341        and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
11342            return $MemberPair_Pos;
11343        }
11344    }
11345    return "lost";
11346}
11347
11348my %Severity_Val=(
11349    "High"=>3,
11350    "Medium"=>2,
11351    "Low"=>1,
11352    "Safe"=>-1
11353);
11354
11355sub cmpSeverities($$)
11356{
11357    my ($S1, $S2) = @_;
11358    if(not $S1) {
11359        return 0;
11360    }
11361    elsif(not $S2) {
11362        return 1;
11363    }
11364    return ($Severity_Val{$S1}>$Severity_Val{$S2});
11365}
11366
11367sub isRecurType($$$)
11368{
11369    foreach (@{$_[2]})
11370    {
11371        if( $_->{"T1"} eq $_[0]
11372        and $_->{"T2"} eq $_[1] )
11373        {
11374            return 1;
11375        }
11376    }
11377    return 0;
11378}
11379
11380sub pushType($$$)
11381{
11382    my %IDs = (
11383        "T1" => $_[0],
11384        "T2" => $_[1]
11385    );
11386    push(@{$_[2]}, \%IDs);
11387}
11388
11389sub isRenamed($$$$$)
11390{
11391    my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
11392    my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
11393    my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
11394    my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
11395    if(not defined $Type2->{"Memb"}{$MemPos}) {
11396        return "";
11397    }
11398    my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
11399    my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
11400
11401    my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
11402    my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
11403    if($MemberPair_Pos_Rev eq "lost")
11404    {
11405        if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
11406        { # base type match
11407            return $Pair_Name;
11408        }
11409        if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
11410        { # exact type match
11411            return $Pair_Name;
11412        }
11413        if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
11414        { # size match
11415            return $Pair_Name;
11416        }
11417        if(isReserved($Pair_Name))
11418        { # reserved fields
11419            return $Pair_Name;
11420        }
11421    }
11422    return "";
11423}
11424
11425sub isLastElem($$)
11426{
11427    my ($Pos, $TypeRef) = @_;
11428    my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
11429    if($Name=~/last|count|max|total/i)
11430    { # GST_LEVEL_COUNT, GST_RTSP_ELAST
11431        return 1;
11432    }
11433    elsif($Name=~/END|NLIMITS\Z/)
11434    { # __RLIMIT_NLIMITS
11435        return 1;
11436    }
11437    elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
11438    and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
11439    { # NImageFormats, NColorRoles
11440        return 1;
11441    }
11442    return 0;
11443}
11444
11445sub nonComparable($$)
11446{
11447    my ($T1, $T2) = @_;
11448
11449    my $N1 = $T1->{"Name"};
11450    my $N2 = $T2->{"Name"};
11451
11452    $N1=~s/\A(struct|union|enum) //;
11453    $N2=~s/\A(struct|union|enum) //;
11454
11455    if($N1 ne $N2
11456    and not isAnon($N1)
11457    and not isAnon($N2))
11458    { # different names
11459        if($T1->{"Type"} ne "Pointer"
11460        or $T2->{"Type"} ne "Pointer")
11461        { # compare base types
11462            return 1;
11463        }
11464        if($N1!~/\Avoid\s*\*/
11465        and $N2=~/\Avoid\s*\*/)
11466        {
11467            return 1;
11468        }
11469    }
11470    elsif($T1->{"Type"} ne $T2->{"Type"})
11471    { # different types
11472        if($T1->{"Type"} eq "Class"
11473        and $T2->{"Type"} eq "Struct")
11474        { # "class" to "struct"
11475            return 0;
11476        }
11477        elsif($T2->{"Type"} eq "Class"
11478        and $T1->{"Type"} eq "Struct")
11479        { # "struct" to "class"
11480            return 0;
11481        }
11482        else
11483        { # "class" to "enum"
11484          # "union" to "class"
11485          #  ...
11486            return 1;
11487        }
11488    }
11489    return 0;
11490}
11491
11492sub isOpaque($)
11493{
11494    my $T = $_[0];
11495    if(not defined $T->{"Memb"})
11496    {
11497        return 1;
11498    }
11499    return 0;
11500}
11501
11502sub removeVPtr($)
11503{ # support for old ABI dumps
11504    my $TPtr = $_[0];
11505    my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}});
11506    if($#Pos>=1)
11507    {
11508        foreach my $Pos (0 .. $#Pos-1)
11509        {
11510            %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}};
11511        }
11512        delete($TPtr->{"Memb"}{$#Pos});
11513    }
11514}
11515
11516sub mergeTypes($$$)
11517{
11518    my ($Type1_Id, $Type2_Id, $Level) = @_;
11519    return {} if(not $Type1_Id or not $Type2_Id);
11520
11521    if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
11522    { # already merged
11523        return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id};
11524    }
11525
11526    my %Type1 = get_Type($Type1_Id, 1);
11527    my %Type2 = get_Type($Type2_Id, 2);
11528    if(not $Type1{"Name"} or not $Type2{"Name"}) {
11529        return {};
11530    }
11531
11532    $CheckedTypes{$Level}{$Type1{"Name"}} = 1;
11533    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
11534    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
11535
11536    $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1;
11537
11538    my %SubProblems = ();
11539
11540    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
11541    {
11542        if($Type1_Pure{"Type"}=~/Struct|Union/
11543        and $Type2_Pure{"Type"}=~/Struct|Union/)
11544        {
11545            if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure))
11546            {
11547                %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=(
11548                    "Target"=>$Type1_Pure{"Name"},
11549                    "Type_Name"=>$Type1_Pure{"Name"}  );
11550
11551                return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems);
11552            }
11553        }
11554    }
11555
11556    if(not $Type1_Pure{"Size"}
11557    or not $Type2_Pure{"Size"})
11558    { # including a case when "class Class { ... };" changed to "class Class;"
11559        if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"}
11560        or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1)
11561        { # NOTE: template instances have no size
11562            return {};
11563        }
11564    }
11565    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes))
11566    { # skip recursive declarations
11567        return {};
11568    }
11569    return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
11570    return {} if($SkipTypes{1}{$Type1_Pure{"Name"}});
11571    return {} if($SkipTypes{1}{$Type1{"Name"}});
11572
11573    if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/)
11574    { # support for old ABI dumps
11575      # _vptr field added in 3.0
11576        if(not checkDump(1, "3.0") and checkDump(2, "3.0"))
11577        {
11578            if(defined $Type2_Pure{"Memb"}
11579            and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr")
11580            {
11581                if(keys(%{$Type2_Pure{"Memb"}})==1) {
11582                    delete($Type2_Pure{"Memb"}{0});
11583                }
11584                else {
11585                    removeVPtr(\%Type2_Pure);
11586                }
11587            }
11588        }
11589        if(checkDump(1, "3.0") and not checkDump(2, "3.0"))
11590        {
11591            if(defined $Type1_Pure{"Memb"}
11592            and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr")
11593            {
11594                if(keys(%{$Type1_Pure{"Memb"}})==1) {
11595                    delete($Type1_Pure{"Memb"}{0});
11596                }
11597                else {
11598                    removeVPtr(\%Type1_Pure);
11599                }
11600            }
11601        }
11602    }
11603
11604    my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
11605    my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
11606
11607    if(not $UseOldDumps and %Typedef_1 and %Typedef_2
11608    and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
11609    and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
11610    {
11611        my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
11612        my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
11613        if($Base_1{"Name"} ne $Base_2{"Name"})
11614        {
11615            if(differentDumps("G")
11616            or differentDumps("V"))
11617            { # different GCC versions or different dumps
11618                $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
11619                $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
11620                # std::__va_list and __va_list
11621                $Base_1{"Name"}=~s/\A(\w+::)+//;
11622                $Base_2{"Name"}=~s/\A(\w+::)+//;
11623                $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
11624                $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
11625            }
11626        }
11627        if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
11628        and $Base_1{"Name"} ne $Base_2{"Name"})
11629        {
11630            if($Level eq "Binary"
11631            and $Type1{"Size"} ne $Type2{"Size"})
11632            {
11633                %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
11634                    "Target"=>$Typedef_1{"Name"},
11635                    "Type_Name"=>$Typedef_1{"Name"},
11636                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11637                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE  );
11638            }
11639            my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1});
11640            my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2});
11641            if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"}))
11642            {
11643                if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level))
11644                {
11645                    %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=(
11646                        "Target"=>$Typedef_1{"Name"},
11647                        "Type_Name"=>$Typedef_1{"Name"},
11648                        "Old_Value"=>$Base_1{"Name"},
11649                        "New_Value"=>$Base_2{"Name"}  );
11650                }
11651                else
11652                {
11653                    %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
11654                        "Target"=>$Typedef_1{"Name"},
11655                        "Type_Name"=>$Typedef_1{"Name"},
11656                        "Old_Value"=>$Base_1{"Name"},
11657                        "New_Value"=>$Base_2{"Name"}  );
11658                }
11659            }
11660        }
11661    }
11662    if(nonComparable(\%Type1_Pure, \%Type2_Pure))
11663    { # different types (reported in detectTypeChange(...))
11664        my $TT1 = $Type1_Pure{"Type"};
11665        my $TT2 = $Type2_Pure{"Type"};
11666
11667        if($TT1 ne $TT2
11668        and $TT1!~/Intrinsic|Pointer|Ref|Typedef/)
11669        { # different type of the type
11670            my $Short1 = $Type1_Pure{"Name"};
11671            my $Short2 = $Type2_Pure{"Name"};
11672
11673            $Short1=~s/\A\Q$TT1\E //ig;
11674            $Short2=~s/\A\Q$TT2\E //ig;
11675
11676            if($Short1 eq $Short2)
11677            {
11678                %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
11679                    "Target"=>$Type1_Pure{"Name"},
11680                    "Type_Name"=>$Type1_Pure{"Name"},
11681                    "Old_Value"=>lc($Type1_Pure{"Type"}),
11682                    "New_Value"=>lc($Type2_Pure{"Type"})  );
11683            }
11684        }
11685        return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems);
11686    }
11687    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes);
11688    if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
11689    or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
11690    and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
11691    { # checking size
11692        if($Level eq "Binary"
11693        and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
11694        {
11695            my $ProblemKind = "DataType_Size";
11696            if($Type1_Pure{"Type"} eq "Class"
11697            and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
11698            {
11699                if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
11700                    $ProblemKind = "Size_Of_Copying_Class";
11701                }
11702                elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
11703                {
11704                    if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
11705                        $ProblemKind = "Size_Of_Allocable_Class_Increased";
11706                    }
11707                    else
11708                    {
11709                        # descreased size of allocable class
11710                        # it has no special effects
11711                    }
11712                }
11713            }
11714            %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
11715                "Target"=>$Type1_Pure{"Name"},
11716                "Type_Name"=>$Type1_Pure{"Name"},
11717                "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
11718                "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE);
11719        }
11720    }
11721    if(defined $Type1_Pure{"BaseType"}
11722    and defined $Type2_Pure{"BaseType"})
11723    { # checking base types
11724        my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level);
11725        foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems}))
11726        {
11727            foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) {
11728                $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation};
11729            }
11730        }
11731    }
11732    my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
11733    my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
11734    my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
11735    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
11736    { # detect removed and renamed fields
11737        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
11738        next if(not $Member_Name);
11739        my $MemberPair_Pos = (defined $Type2_Pure{"Memb"}{$Member_Pos} and $Type2_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type2_Pure);
11740        if($MemberPair_Pos eq "lost")
11741        {
11742            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
11743            {
11744                if(isUnnamed($Member_Name))
11745                { # support for old-version dumps
11746                  # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
11747                    if(not checkDump(2, "2.1")) {
11748                        next;
11749                    }
11750                }
11751                if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
11752                { # renamed
11753                    $RenamedField{$Member_Pos} = $RenamedTo;
11754                    $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name;
11755                }
11756                else
11757                { # removed
11758                    $RemovedField{$Member_Pos} = 1;
11759                }
11760            }
11761            elsif($Type1_Pure{"Type"} eq "Enum")
11762            {
11763                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
11764                next if($Member_Value1 eq "");
11765                $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
11766                if($MemberPair_Pos ne "lost")
11767                { # renamed
11768                    my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
11769                    my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
11770                    if($MemberPair_Pos_Rev eq "lost")
11771                    {
11772                        $RenamedField{$Member_Pos} = $RenamedTo;
11773                        $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name;
11774                    }
11775                    else {
11776                        $RemovedField{$Member_Pos} = 1;
11777                    }
11778                }
11779                else
11780                { # removed
11781                    $RemovedField{$Member_Pos} = 1;
11782                }
11783            }
11784        }
11785        else
11786        { # related
11787            $RelatedField{$Member_Pos} = $MemberPair_Pos;
11788            $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
11789        }
11790    }
11791    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11792    { # detect added fields
11793        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11794        next if(not $Member_Name);
11795        my $MemberPair_Pos = (defined $Type1_Pure{"Memb"}{$Member_Pos} and $Type1_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type1_Pure);
11796        if($MemberPair_Pos eq "lost")
11797        {
11798            if(isUnnamed($Member_Name))
11799            { # support for old-version dumps
11800            # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
11801                if(not checkDump(1, "2.1")) {
11802                    next;
11803                }
11804            }
11805            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
11806            {
11807                if(not $RenamedField_Rev{$Member_Pos})
11808                { # added
11809                    $AddedField{$Member_Pos}=1;
11810                }
11811            }
11812        }
11813    }
11814    if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11815    { # detect moved fields
11816        my (%RelPos, %RelPosName, %AbsPos) = ();
11817        my $Pos = 0;
11818        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
11819        { # relative positions in 1st version
11820            my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
11821            next if(not $Member_Name);
11822            if(not $RemovedField{$Member_Pos})
11823            { # old type without removed fields
11824                $RelPos{1}{$Member_Name} = $Pos;
11825                $RelPosName{1}{$Pos} = $Member_Name;
11826                $AbsPos{1}{$Pos++} = $Member_Pos;
11827            }
11828        }
11829        $Pos = 0;
11830        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11831        { # relative positions in 2nd version
11832            my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11833            next if(not $Member_Name);
11834            if(not $AddedField{$Member_Pos})
11835            { # new type without added fields
11836                $RelPos{2}{$Member_Name} = $Pos;
11837                $RelPosName{2}{$Pos} = $Member_Name;
11838                $AbsPos{2}{$Pos++} = $Member_Pos;
11839            }
11840        }
11841        foreach my $Member_Name (keys(%{$RelPos{1}}))
11842        {
11843            my $RPos1 = $RelPos{1}{$Member_Name};
11844            my $AbsPos1 = $NameToPosA{$Member_Name};
11845            my $Member_Name2 = $Member_Name;
11846            if(my $RenamedTo = $RenamedField{$AbsPos1})
11847            { # renamed
11848                $Member_Name2 = $RenamedTo;
11849            }
11850            my $RPos2 = $RelPos{2}{$Member_Name2};
11851            if($RPos2 ne "" and $RPos1 ne $RPos2)
11852            { # different relative positions
11853                my $AbsPos2 = $NameToPosB{$Member_Name2};
11854                if($AbsPos1 ne $AbsPos2)
11855                { # different absolute positions
11856                    my $ProblemType = "Moved_Field";
11857                    if(not isPublic(\%Type1_Pure, $AbsPos1))
11858                    { # may change layout and size of type
11859                        if($Level eq "Source") {
11860                            next;
11861                        }
11862                        $ProblemType = "Moved_Private_Field";
11863                    }
11864                    if($Level eq "Binary"
11865                    and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
11866                    { # affected size
11867                        my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
11868                        my $MovedAbsPos = $AbsPos{1}{$RPos2};
11869                        my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
11870                        if($MemSize1 ne $MemSize2) {
11871                            $ProblemType .= "_And_Size";
11872                        }
11873                    }
11874                    if($ProblemType eq "Moved_Private_Field") {
11875                        next;
11876                    }
11877                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
11878                        "Target"=>$Member_Name,
11879                        "Type_Name"=>$Type1_Pure{"Name"},
11880                        "Old_Value"=>$RPos1,
11881                        "New_Value"=>$RPos2 );
11882                }
11883            }
11884        }
11885    }
11886    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
11887    { # check older fields, public and private
11888        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
11889        next if(not $Member_Name);
11890        next if($Member_Name eq "_vptr");
11891        if(my $RenamedTo = $RenamedField{$Member_Pos})
11892        { # renamed
11893            if(defined $Constants{2}{$Member_Name})
11894            {
11895                if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo)
11896                { # define OLD NEW
11897                    next; # Safe
11898                }
11899            }
11900
11901            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
11902            {
11903                if(isPublic(\%Type1_Pure, $Member_Pos))
11904                {
11905                    %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
11906                        "Target"=>$Member_Name,
11907                        "Type_Name"=>$Type1_Pure{"Name"},
11908                        "Old_Value"=>$Member_Name,
11909                        "New_Value"=>$RenamedTo  );
11910                }
11911                elsif(isReserved($Member_Name))
11912                {
11913                    %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
11914                        "Target"=>$Member_Name,
11915                        "Type_Name"=>$Type1_Pure{"Name"},
11916                        "Old_Value"=>$Member_Name,
11917                        "New_Value"=>$RenamedTo  );
11918                }
11919            }
11920            elsif($Type1_Pure{"Type"} eq "Enum")
11921            {
11922                %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
11923                    "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
11924                    "Type_Name"=>$Type1_Pure{"Name"},
11925                    "Old_Value"=>$Member_Name,
11926                    "New_Value"=>$RenamedTo  );
11927            }
11928        }
11929        elsif($RemovedField{$Member_Pos})
11930        { # removed
11931            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11932            {
11933                my $ProblemType = "Removed_Field";
11934                if(not isPublic(\%Type1_Pure, $Member_Pos)
11935                or isUnnamed($Member_Name))
11936                {
11937                    if($Level eq "Source") {
11938                        next;
11939                    }
11940                    $ProblemType = "Removed_Private_Field";
11941                }
11942                if($Level eq "Binary"
11943                and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
11944                {
11945                    if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
11946                    { # affected fields
11947                        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}))
11948                        { # changed offset
11949                            $ProblemType .= "_And_Layout";
11950                        }
11951                    }
11952                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
11953                    { # affected size
11954                        $ProblemType .= "_And_Size";
11955                    }
11956                }
11957                if($ProblemType eq "Removed_Private_Field") {
11958                    next;
11959                }
11960                %{$SubProblems{$ProblemType}{$Member_Name}}=(
11961                    "Target"=>$Member_Name,
11962                    "Type_Name"=>$Type1_Pure{"Name"}  );
11963            }
11964            elsif($Type2_Pure{"Type"} eq "Union")
11965            {
11966                if($Level eq "Binary"
11967                and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
11968                {
11969                    %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
11970                        "Target"=>$Member_Name,
11971                        "Type_Name"=>$Type1_Pure{"Name"}  );
11972                }
11973                else
11974                {
11975                    %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
11976                        "Target"=>$Member_Name,
11977                        "Type_Name"=>$Type1_Pure{"Name"}  );
11978                }
11979            }
11980            elsif($Type1_Pure{"Type"} eq "Enum")
11981            {
11982                %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
11983                    "Target"=>$Member_Name,
11984                    "Type_Name"=>$Type1_Pure{"Name"},
11985                    "Old_Value"=>$Member_Name  );
11986            }
11987        }
11988        else
11989        { # changed
11990            my $MemberPair_Pos = $RelatedField{$Member_Pos};
11991            if($Type1_Pure{"Type"} eq "Enum")
11992            {
11993                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
11994                next if($Member_Value1 eq "");
11995                my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
11996                next if($Member_Value2 eq "");
11997                if($Member_Value1 ne $Member_Value2)
11998                {
11999                    my $ProblemType = "Enum_Member_Value";
12000                    if(isLastElem($Member_Pos, \%Type1_Pure)) {
12001                        $ProblemType = "Enum_Last_Member_Value";
12002                    }
12003                    if($SkipConstants{1}{$Member_Name}) {
12004                        $ProblemType = "Enum_Private_Member_Value";
12005                    }
12006                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
12007                        "Target"=>$Member_Name,
12008                        "Type_Name"=>$Type1_Pure{"Name"},
12009                        "Old_Value"=>$Member_Value1,
12010                        "New_Value"=>$Member_Value2  );
12011                }
12012            }
12013            elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
12014            {
12015                my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"};
12016                my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"};
12017
12018                if($Access1 ne "private"
12019                and $Access2 eq "private")
12020                {
12021                    %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=(
12022                        "Target"=>$Member_Name,
12023                        "Type_Name"=>$Type1_Pure{"Name"});
12024                }
12025                elsif($Access1 ne "protected"
12026                and $Access1 ne "private"
12027                and $Access2 eq "protected")
12028                {
12029                    %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=(
12030                        "Target"=>$Member_Name,
12031                        "Type_Name"=>$Type1_Pure{"Name"});
12032                }
12033
12034                my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
12035                my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
12036                my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
12037                if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
12038                    $SizeV1 = $BSize1;
12039                }
12040                my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
12041                if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
12042                    $SizeV2 = $BSize2;
12043                }
12044                my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
12045                my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
12046                if($Level eq "Binary"
12047                and $SizeV1 ne $SizeV2)
12048                {
12049                    if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
12050                    or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
12051                    { # field size change (including anon-structures and unions)
12052                      # - same types
12053                      # - unnamed types
12054                      # - bitfields
12055                        my $ProblemType = "Field_Size";
12056                        if(not isPublic(\%Type1_Pure, $Member_Pos)
12057                        or isUnnamed($Member_Name))
12058                        { # should not be accessed by applications, goes to "Low Severity"
12059                          # example: "abidata" members in GStreamer types
12060                            $ProblemType = "Private_".$ProblemType;
12061                        }
12062                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
12063                        { # check an effect
12064                            if($Type2_Pure{"Type"} ne "Union"
12065                            and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
12066                            { # public fields after the current
12067                                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}))
12068                                { # changed offset
12069                                    $ProblemType .= "_And_Layout";
12070                                }
12071                            }
12072                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
12073                                $ProblemType .= "_And_Type_Size";
12074                            }
12075                        }
12076                        if($ProblemType eq "Private_Field_Size")
12077                        { # private field size with no effect
12078                            $ProblemType = "";
12079                        }
12080                        if($ProblemType eq "Field_Size")
12081                        {
12082                            if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2)
12083                            { # Low severity
12084                                $ProblemType = "Struct_Field_Size_Increased";
12085                            }
12086                        }
12087                        if($ProblemType)
12088                        { # register a problem
12089                            %{$SubProblems{$ProblemType}{$Member_Name}}=(
12090                                "Target"=>$Member_Name,
12091                                "Type_Name"=>$Type1_Pure{"Name"},
12092                                "Old_Size"=>$SizeV1,
12093                                "New_Size"=>$SizeV2);
12094                        }
12095                    }
12096                }
12097                if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
12098                or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
12099                { # do NOT check bitfield type changes
12100                    next;
12101                }
12102                if(checkDump(1, "2.13") and checkDump(2, "2.13"))
12103                {
12104                    if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
12105                    and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
12106                    {
12107                        %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
12108                            "Target"=>$Member_Name,
12109                            "Type_Name"=>$Type1_Pure{"Name"});
12110                    }
12111                    elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
12112                    and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
12113                    {
12114                        %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=(
12115                            "Target"=>$Member_Name,
12116                            "Type_Name"=>$Type1_Pure{"Name"});
12117                    }
12118                }
12119                my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
12120                foreach my $ProblemType (keys(%Sub_SubChanges))
12121                {
12122                    my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"};
12123                    my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"};
12124
12125                    # quals
12126                    if($ProblemType eq "Field_Type"
12127                    or $ProblemType eq "Field_Type_And_Size"
12128                    or $ProblemType eq "Field_Type_Format")
12129                    {
12130                        if(checkDump(1, "2.6") and checkDump(2, "2.6"))
12131                        {
12132                            if(addedQual($Old_Value, $New_Value, "volatile")) {
12133                                %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}};
12134                            }
12135                            elsif(removedQual($Old_Value, $New_Value, "volatile")) {
12136                                %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}};
12137                            }
12138                        }
12139                        if(my $RA = addedQual($Old_Value, $New_Value, "const"))
12140                        {
12141                            if($RA==2) {
12142                                %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}};
12143                            }
12144                            else {
12145                                %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}};
12146                            }
12147                        }
12148                        elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
12149                        {
12150                            if($RR==2) {
12151                                %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}};
12152                            }
12153                            else {
12154                                %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}};
12155                            }
12156                        }
12157                    }
12158                }
12159
12160                if($Level eq "Source")
12161                {
12162                    foreach my $ProblemType (keys(%Sub_SubChanges))
12163                    {
12164                        my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"};
12165                        my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"};
12166
12167                        if($ProblemType eq "Field_Type")
12168                        {
12169                            if(cmpBTypes($Old_Value, $New_Value, 1, 2)) {
12170                                delete($Sub_SubChanges{$ProblemType});
12171                            }
12172                        }
12173                    }
12174                }
12175
12176                foreach my $ProblemType (keys(%Sub_SubChanges))
12177                {
12178                    my $ProblemType_Init = $ProblemType;
12179                    if($ProblemType eq "Field_Type_And_Size")
12180                    { # Binary
12181                        if(not isPublic(\%Type1_Pure, $Member_Pos)
12182                        or isUnnamed($Member_Name)) {
12183                            $ProblemType = "Private_".$ProblemType;
12184                        }
12185                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1}))
12186                        { # check an effect
12187                            if($Type2_Pure{"Type"} ne "Union"
12188                            and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
12189                            { # public fields after the current
12190                                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}))
12191                                { # changed offset
12192                                    $ProblemType .= "_And_Layout";
12193                                }
12194                            }
12195                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
12196                                $ProblemType .= "_And_Type_Size";
12197                            }
12198                        }
12199                    }
12200                    else
12201                    {
12202                        if(not isPublic(\%Type1_Pure, $Member_Pos)
12203                        or isUnnamed($Member_Name)) {
12204                            next;
12205                        }
12206                    }
12207                    if($ProblemType eq "Private_Field_Type_And_Size")
12208                    { # private field change with no effect
12209                        next;
12210                    }
12211                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
12212                        "Target"=>$Member_Name,
12213                        "Type_Name"=>$Type1_Pure{"Name"});
12214
12215                    foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}}))
12216                    { # other properties
12217                        $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr};
12218                    }
12219                }
12220                if(not isPublic(\%Type1_Pure, $Member_Pos))
12221                { # do NOT check internal type changes
12222                    next;
12223                }
12224                if($MemberType1_Id and $MemberType2_Id)
12225                { # checking member type changes
12226                    my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
12227
12228                    my %DupProblems = ();
12229
12230                    foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems}))
12231                    {
12232                        foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}}))
12233                        {
12234                            if(not defined $AllAffected)
12235                            {
12236                                if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) {
12237                                    next;
12238                                }
12239                            }
12240
12241                            my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
12242                            $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation};
12243
12244                            if(not defined $AllAffected)
12245                            {
12246                                $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1;
12247                            }
12248                        }
12249                    }
12250
12251                    %DupProblems = ();
12252                }
12253            }
12254        }
12255    }
12256    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
12257    { # checking added members, public and private
12258        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
12259        next if(not $Member_Name);
12260        next if($Member_Name eq "_vptr");
12261        if($AddedField{$Member_Pos})
12262        { # added
12263            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
12264            {
12265                my $ProblemType = "Added_Field";
12266                if(not isPublic(\%Type2_Pure, $Member_Pos)
12267                or isUnnamed($Member_Name))
12268                {
12269                    if($Level eq "Source") {
12270                        next;
12271                    }
12272                    $ProblemType = "Added_Private_Field";
12273                }
12274                if($Level eq "Binary"
12275                and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2}))
12276                {
12277                    if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
12278                    { # public fields after the current
12279                        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}))
12280                        { # changed offset
12281                            $ProblemType .= "_And_Layout";
12282                        }
12283                    }
12284                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
12285                        $ProblemType .= "_And_Size";
12286                    }
12287                }
12288                if($ProblemType eq "Added_Private_Field")
12289                { # skip added private fields
12290                    next;
12291                }
12292                %{$SubProblems{$ProblemType}{$Member_Name}}=(
12293                    "Target"=>$Member_Name,
12294                    "Type_Name"=>$Type1_Pure{"Name"});
12295            }
12296            elsif($Type2_Pure{"Type"} eq "Union")
12297            {
12298                if($Level eq "Binary"
12299                and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
12300                {
12301                    %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
12302                        "Target"=>$Member_Name,
12303                        "Type_Name"=>$Type1_Pure{"Name"});
12304                }
12305                else
12306                {
12307                    %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
12308                        "Target"=>$Member_Name,
12309                        "Type_Name"=>$Type1_Pure{"Name"});
12310                }
12311            }
12312            elsif($Type2_Pure{"Type"} eq "Enum")
12313            {
12314                my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
12315                next if($Member_Value eq "");
12316                %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
12317                    "Target"=>$Member_Name,
12318                    "Type_Name"=>$Type2_Pure{"Name"},
12319                    "New_Value"=>$Member_Value);
12320            }
12321        }
12322    }
12323
12324    pop(@RecurTypes);
12325    return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems);
12326}
12327
12328sub isUnnamed($) {
12329    return $_[0]=~/\Aunnamed\d+\Z/;
12330}
12331
12332sub get_ShortClass($$)
12333{
12334    my ($TypeId, $LibVersion) = @_;
12335    my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
12336    if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) {
12337        $TypeName = uncover_typedefs($TypeName, $LibVersion);
12338    }
12339    if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
12340        $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g;
12341    }
12342    return $TypeName;
12343}
12344
12345sub goToFirst($$$)
12346{
12347    my ($TypeId, $LibVersion, $Type_Type) = @_;
12348    return () if(not $TypeId);
12349    if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
12350        return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
12351    }
12352    return () if(not $TypeInfo{$LibVersion}{$TypeId});
12353    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
12354    return () if(not $Type{"Type"});
12355    if($Type{"Type"} ne $Type_Type)
12356    {
12357        return () if(not $Type{"BaseType"});
12358        %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type);
12359    }
12360    $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
12361    return %Type;
12362}
12363
12364my %TypeSpecAttributes = (
12365    "Const" => 1,
12366    "Volatile" => 1,
12367    "ConstVolatile" => 1,
12368    "Restrict" => 1,
12369    "Typedef" => 1
12370);
12371
12372sub get_PureType($$)
12373{
12374    my ($TypeId, $Info) = @_;
12375    if(not $TypeId or not $Info
12376    or not $Info->{$TypeId}) {
12377        return ();
12378    }
12379    if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
12380        return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
12381    }
12382    my %Type = %{$Info->{$TypeId}};
12383    return %Type if(not $Type{"BaseType"});
12384    if($TypeSpecAttributes{$Type{"Type"}}) {
12385        %Type = get_PureType($Type{"BaseType"}, $Info);
12386    }
12387    $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
12388    return %Type;
12389}
12390
12391sub get_PLevel($$)
12392{
12393    my ($TypeId, $LibVersion) = @_;
12394    return 0 if(not $TypeId);
12395    if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
12396        return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
12397    }
12398    return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
12399    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
12400    return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/);
12401    my $PLevel = 0;
12402    if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) {
12403        $PLevel += 1;
12404    }
12405    return $PLevel if(not $Type{"BaseType"});
12406    $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion);
12407    $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel;
12408    return $PLevel;
12409}
12410
12411sub get_BaseType($$)
12412{
12413    my ($TypeId, $LibVersion) = @_;
12414    return () if(not $TypeId);
12415    if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
12416        return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
12417    }
12418    return () if(not $TypeInfo{$LibVersion}{$TypeId});
12419    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
12420    return %Type if(not $Type{"BaseType"});
12421    %Type = get_BaseType($Type{"BaseType"}, $LibVersion);
12422    $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
12423    return %Type;
12424}
12425
12426sub get_BaseTypeQual($$)
12427{
12428    my ($TypeId, $LibVersion) = @_;
12429    return "" if(not $TypeId);
12430    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
12431    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
12432    return "" if(not $Type{"BaseType"});
12433    my $Qual = "";
12434    if($Type{"Type"} eq "Pointer") {
12435        $Qual .= "*";
12436    }
12437    elsif($Type{"Type"} eq "Ref") {
12438        $Qual .= "&";
12439    }
12440    elsif($Type{"Type"} eq "ConstVolatile") {
12441        $Qual .= "const volatile";
12442    }
12443    elsif($Type{"Type"} eq "Const"
12444    or $Type{"Type"} eq "Volatile"
12445    or $Type{"Type"} eq "Restrict") {
12446        $Qual .= lc($Type{"Type"});
12447    }
12448    my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion);
12449    return $BQual.$Qual;
12450}
12451
12452sub get_OneStep_BaseType($$)
12453{
12454    my ($TypeId, $Info) = @_;
12455    if(not $TypeId or not $Info
12456    or not $Info->{$TypeId}) {
12457        return ();
12458    }
12459    my %Type = %{$Info->{$TypeId}};
12460    return %Type if(not $Type{"BaseType"});
12461    if(my $BTid = $Type{"BaseType"})
12462    {
12463        if($Info->{$BTid}) {
12464            return %{$Info->{$BTid}};
12465        }
12466        else { # something is going wrong
12467            return ();
12468        }
12469    }
12470    else {
12471        return %Type;
12472    }
12473}
12474
12475sub get_Type($$)
12476{
12477    my ($TypeId, $LibVersion) = @_;
12478    return () if(not $TypeId);
12479    return () if(not $TypeInfo{$LibVersion}{$TypeId});
12480    return %{$TypeInfo{$LibVersion}{$TypeId}};
12481}
12482
12483sub isPrivateData($)
12484{ # non-public global data
12485    my $Symbol = $_[0];
12486    return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
12487}
12488
12489sub isInLineInst($$$) {
12490    return (isTemplateInstance(@_) and not isTemplateSpec(@_));
12491}
12492
12493sub isTemplateInstance($$$)
12494{
12495    my ($Symbol, $SInfo, $LibVersion) = @_;
12496    if($CheckObjectsOnly)
12497    {
12498        if($Symbol!~/\A(_Z|\?)/) {
12499            return 0;
12500        }
12501        if(my $Signature = $tr_name{$Symbol})
12502        {
12503            if(index($Signature,">")==-1) {
12504                return 0;
12505            }
12506            if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
12507            {
12508                if(index($ShortName,"<")!=-1
12509                and index($ShortName,">")!=-1) {
12510                    return 1;
12511                }
12512            }
12513        }
12514    }
12515    else
12516    {
12517        if(my $ClassId = $SInfo->{"Class"})
12518        {
12519            if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
12520            {
12521                if(index($ClassName,"<")!=-1) {
12522                    return 1;
12523                }
12524            }
12525        }
12526        if(my $ShortName = $SInfo->{"ShortName"})
12527        {
12528            if(index($ShortName,"<")!=-1
12529            and index($ShortName,">")!=-1) {
12530                return 1;
12531            }
12532        }
12533    }
12534    return 0;
12535}
12536
12537sub isTemplateSpec($$$)
12538{
12539    my ($Symbol, $SInfo, $LibVersion) = @_;
12540    if(my $ClassId = $SInfo->{"Class"})
12541    {
12542        if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
12543        { # class specialization
12544            return 1;
12545        }
12546        elsif($SInfo->{"Spec"})
12547        { # method specialization
12548            return 1;
12549        }
12550    }
12551    return 0;
12552}
12553
12554sub symbolFilter($$$$)
12555{ # some special cases when the symbol cannot be imported
12556    my ($Symbol, $LibVersion, $Type, $Level) = @_;
12557    if(isPrivateData($Symbol))
12558    { # non-public global data
12559        return 0;
12560    }
12561    if($CheckObjectsOnly) {
12562        return 0 if($Symbol=~/\A(_init|_fini)\Z/);
12563    }
12564    if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
12565    { # support for old ABI dumps in --headers-only mode
12566        foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
12567        {
12568            if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
12569            {
12570                my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
12571                if(not $PType or $PType eq "Unknown") {
12572                    return 0;
12573                }
12574            }
12575        }
12576    }
12577    if($Type=~/Affected/)
12578    {
12579        my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
12580        if($SkipSymbols{$LibVersion}{$Symbol})
12581        { # user defined symbols to ignore
12582            return 0;
12583        }
12584        my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
12585        if(not $NameSpace and $ClassId)
12586        { # class methods have no "NameSpace" attribute
12587            $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
12588        }
12589        if($NameSpace)
12590        { # user defined namespaces to ignore
12591            if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
12592                return 0;
12593            }
12594            foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
12595            { # nested namespaces
12596                if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
12597                    return 0;
12598                }
12599            }
12600        }
12601        if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
12602        {
12603            if(my $Skip = skipHeader($Header, $LibVersion))
12604            { # --skip-headers or <skip_headers> (not <skip_including>)
12605                if($Skip==1) {
12606                    return 0;
12607                }
12608            }
12609        }
12610        if($SymbolsListPath and not $SymbolsList{$Symbol})
12611        { # user defined symbols
12612            return 0;
12613        }
12614        if($SkipSymbolsListPath and $SkipSymbolsList{$Symbol})
12615        { # user defined symbols
12616            return 0;
12617        }
12618        if($AppPath and not $SymbolsList_App{$Symbol})
12619        { # user defined symbols (in application)
12620            return 0;
12621        }
12622        if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
12623        { # non-target symbols
12624            return 0;
12625        }
12626        if($Level eq "Binary")
12627        {
12628            if($CheckObjectsOnly)
12629            {
12630                if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
12631                    return 0;
12632                }
12633            }
12634            else
12635            {
12636                if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
12637                or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
12638                {
12639                    if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
12640                    { # inline virtual methods
12641                        if($Type=~/InlineVirt/) {
12642                            return 1;
12643                        }
12644                        my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
12645                        if(not $Allocable)
12646                        { # check bases
12647                            foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
12648                            {
12649                                if(not isCopyingClass($DCId, $LibVersion))
12650                                { # exists a derived class without default c-tor
12651                                    $Allocable=1;
12652                                    last;
12653                                }
12654                            }
12655                        }
12656                        if(not $Allocable) {
12657                            return 0;
12658                        }
12659                    }
12660                    else
12661                    { # inline non-virtual methods
12662                        return 0;
12663                    }
12664                }
12665            }
12666        }
12667    }
12668    return 1;
12669}
12670
12671sub mergeImpl()
12672{
12673    my $DiffCmd = get_CmdPath("diff");
12674    if(not $DiffCmd) {
12675        exitStatus("Not_Found", "can't find \"diff\"");
12676    }
12677    foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
12678    { # implementation changes
12679        next if($CompleteSignature{1}{$Interface}{"Private"});
12680        next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
12681        next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
12682        if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
12683            next;
12684        }
12685        my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
12686        next if(not $Impl1);
12687        my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
12688        next if(not $Impl2);
12689        if($Impl1 ne $Impl2)
12690        {
12691            writeFile("$TMP_DIR/impl1", $Impl1);
12692            writeFile("$TMP_DIR/impl2", $Impl2);
12693            my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
12694            $Diff=~s/(---|\+\+\+).+\n//g;
12695            $Diff=~s/[ ]{3,}/ /g;
12696            $Diff=~s/\n\@\@/\n \n\@\@/g;
12697            unlink("$TMP_DIR/impl1");
12698            unlink("$TMP_DIR/impl2");
12699            %{$CompatProblems_Impl{$Interface}}=(
12700                "Diff" => get_CodeView($Diff)  );
12701        }
12702    }
12703
12704    # clean memory
12705    %Interface_Impl = ();
12706}
12707
12708sub canonifyImpl($)
12709{
12710    my $FuncBody=  $_[0];
12711    return "" if(not $FuncBody);
12712    $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
12713    $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
12714    $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
12715    $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
12716    while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
12717    $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
12718    $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
12719    $FuncBody=~s/\.L\d+/.L/g;
12720    $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
12721    $FuncBody=~s/[\n]{2,}/\n/g;
12722    return $FuncBody;
12723}
12724
12725sub get_CodeView($)
12726{
12727    my $Code = $_[0];
12728    my $View = "";
12729    foreach my $Line (split(/\n/, $Code))
12730    {
12731        if($Line=~s/\A(\+|-)/$1 /g)
12732        { # bold line
12733            $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
12734        }
12735        else {
12736            $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
12737        }
12738    }
12739    return "<table class='code_view'>$View</table>\n";
12740}
12741
12742sub getImplementations($$)
12743{
12744    my ($LibVersion, $Path) = @_;
12745    return if(not $LibVersion or not -e $Path);
12746    if($OSgroup eq "macos")
12747    {
12748        my $OtoolCmd = get_CmdPath("otool");
12749        if(not $OtoolCmd) {
12750            exitStatus("Not_Found", "can't find \"otool\"");
12751        }
12752        my $CurInterface = "";
12753        foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
12754        {
12755            if($Line=~/\A\s*_(\w+)\s*:/i) {
12756                $CurInterface = $1;
12757            }
12758            elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
12759                $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
12760            }
12761        }
12762    }
12763    else
12764    {
12765        my $ObjdumpCmd = get_CmdPath("objdump");
12766        if(not $ObjdumpCmd) {
12767            exitStatus("Not_Found", "can't find \"objdump\"");
12768        }
12769        my $CurInterface = "";
12770        foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
12771        {
12772            if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
12773                $CurInterface = $1;
12774            }
12775            else
12776            { # x86:    51fa:(\t)89 e5               (\t)mov    %esp,%ebp
12777              # arm:    5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
12778                if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
12779                    $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
12780                }
12781            }
12782        }
12783    }
12784}
12785
12786sub detectAdded($)
12787{
12788    my $Level = $_[0];
12789    foreach my $Symbol (keys(%{$Symbol_Library{2}}))
12790    {
12791        if(link_symbol($Symbol, 1, "+Deps"))
12792        { # linker can find a new symbol
12793          # in the old-version library
12794          # So, it's not a new symbol
12795            next;
12796        }
12797        if(my $VSym = $SymVer{2}{$Symbol}
12798        and index($Symbol,"\@")==-1) {
12799            next;
12800        }
12801        $AddedInt{$Level}{$Symbol} = 1;
12802    }
12803}
12804
12805sub detectRemoved($)
12806{
12807    my $Level = $_[0];
12808    foreach my $Symbol (keys(%{$Symbol_Library{1}}))
12809    {
12810        if($CheckObjectsOnly) {
12811            $CheckedSymbols{"Binary"}{$Symbol} = 1;
12812        }
12813        if(link_symbol($Symbol, 2, "+Deps"))
12814        { # linker can find an old symbol
12815          # in the new-version library
12816            next;
12817        }
12818        if(my $VSym = $SymVer{1}{$Symbol}
12819        and index($Symbol,"\@")==-1) {
12820            next;
12821        }
12822        $RemovedInt{$Level}{$Symbol} = 1;
12823    }
12824}
12825
12826sub mergeLibs($)
12827{
12828    my $Level = $_[0];
12829    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
12830    { # checking added symbols
12831        next if($CompleteSignature{2}{$Symbol}{"Private"});
12832        next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
12833        next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level));
12834        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
12835    }
12836    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
12837    { # checking removed symbols
12838        next if($CompleteSignature{1}{$Symbol}{"Private"});
12839        next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
12840        if(index($Symbol, "_ZTV")==0)
12841        { # skip v-tables for templates, that should not be imported by applications
12842            next if($tr_name{$Symbol}=~/</);
12843            if(my $CName = $VTableClass{$Symbol})
12844            {
12845                if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
12846                { # vtables for "private" classes
12847                  # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
12848                    next;
12849                }
12850            }
12851        }
12852        else {
12853            next if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level));
12854        }
12855        if($CompleteSignature{1}{$Symbol}{"PureVirt"})
12856        { # symbols for pure virtual methods cannot be called by clients
12857            next;
12858        }
12859        %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
12860    }
12861}
12862
12863sub checkDump($$)
12864{
12865    my ($LibVersion, $V) = @_;
12866    if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
12867        return $Cache{"checkDump"}{$LibVersion}{$V};
12868    }
12869    return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
12870}
12871
12872sub detectAdded_H($)
12873{
12874    my $Level = $_[0];
12875    foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
12876    {
12877        if($Level eq "Source")
12878        { # remove symbol version
12879            my ($SN, $SS, $SV) = separate_symbol($Symbol);
12880            $Symbol=$SN;
12881
12882            if($CompleteSignature{2}{$Symbol}{"Artificial"})
12883            { # skip artificial constructors
12884                next;
12885            }
12886        }
12887        if(not $CompleteSignature{2}{$Symbol}{"Header"}
12888        or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
12889            next;
12890        }
12891        if($ExtendedSymbols{$Symbol}) {
12892            next;
12893        }
12894        if(not defined $CompleteSignature{1}{$Symbol}
12895        or not $CompleteSignature{1}{$Symbol}{"MnglName"})
12896        {
12897            if($UsedDump{2}{"SrcBin"})
12898            {
12899                if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
12900                { # support for old and different (!) ABI dumps
12901                    if(not $CompleteSignature{2}{$Symbol}{"Virt"}
12902                    and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
12903                    {
12904                        if($CheckHeadersOnly)
12905                        {
12906                            if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
12907                            {
12908                                if($Lang eq "C")
12909                                { # support for old ABI dumps: missed extern "C" functions
12910                                    next;
12911                                }
12912                            }
12913                        }
12914                        else
12915                        {
12916                            if(not link_symbol($Symbol, 2, "-Deps"))
12917                            { # skip added inline symbols and const global data
12918                                next;
12919                            }
12920                        }
12921                    }
12922                }
12923            }
12924            $AddedInt{$Level}{$Symbol} = 1;
12925        }
12926    }
12927}
12928
12929sub detectRemoved_H($)
12930{
12931    my $Level = $_[0];
12932    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12933    {
12934        if($Level eq "Source")
12935        { # remove symbol version
12936            my ($SN, $SS, $SV) = separate_symbol($Symbol);
12937            $Symbol=$SN;
12938        }
12939        if(not $CompleteSignature{1}{$Symbol}{"Header"}
12940        or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
12941            next;
12942        }
12943        if($ExtendedSymbols{$Symbol}) {
12944            next;
12945        }
12946        if(not defined $CompleteSignature{2}{$Symbol}
12947        or not $CompleteSignature{2}{$Symbol}{"MnglName"})
12948        {
12949            if($UsedDump{1}{"SrcBin"})
12950            {
12951                if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
12952                { # support for old and different (!) ABI dumps
12953                    if(not $CompleteSignature{1}{$Symbol}{"Virt"}
12954                    and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
12955                    {
12956                        if($CheckHeadersOnly)
12957                        { # skip all removed symbols
12958                            if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
12959                            {
12960                                if($Lang eq "C")
12961                                { # support for old ABI dumps: missed extern "C" functions
12962                                    next;
12963                                }
12964                            }
12965                        }
12966                        else
12967                        {
12968                            if(not link_symbol($Symbol, 1, "-Deps"))
12969                            { # skip removed inline symbols
12970                                next;
12971                            }
12972                        }
12973                    }
12974                }
12975            }
12976            if(not checkDump(1, "2.15"))
12977            {
12978                if($Symbol=~/_IT_E\Z/)
12979                { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
12980                    next;
12981                }
12982            }
12983            if(not $CompleteSignature{1}{$Symbol}{"Class"})
12984            {
12985                if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
12986                {
12987                    if(defined $Constants{2}{$Short})
12988                    {
12989                        my $Val = $Constants{2}{$Short}{"Value"};
12990                        if(defined $Func_ShortName{2}{$Val})
12991                        { # old name defined to new
12992                            next;
12993                        }
12994                    }
12995                }
12996
12997            }
12998            $RemovedInt{$Level}{$Symbol} = 1;
12999            if($Level eq "Source")
13000            { # search for a source-compatible equivalent
13001                setAlternative($Symbol, $Level);
13002            }
13003        }
13004    }
13005}
13006
13007sub mergeHeaders($)
13008{
13009    my $Level = $_[0];
13010    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
13011    { # checking added symbols
13012        next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
13013        next if($CompleteSignature{2}{$Symbol}{"Private"});
13014        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
13015        if($Level eq "Binary")
13016        {
13017            if($CompleteSignature{2}{$Symbol}{"InLine"})
13018            {
13019                if(not $CompleteSignature{2}{$Symbol}{"Virt"})
13020                { # skip inline non-virtual functions
13021                    next;
13022                }
13023            }
13024        }
13025        else
13026        { # Source
13027            if($SourceAlternative_B{$Symbol}) {
13028                next;
13029            }
13030        }
13031        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
13032    }
13033    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
13034    { # checking removed symbols
13035        next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
13036        next if($CompleteSignature{1}{$Symbol}{"Private"});
13037        next if(not symbolFilter($Symbol, 1, "Affected", $Level));
13038        if($Level eq "Binary")
13039        {
13040            if($CompleteSignature{1}{$Symbol}{"InLine"})
13041            {
13042                if(not $CompleteSignature{1}{$Symbol}{"Virt"})
13043                { # skip inline non-virtual functions
13044                    next;
13045                }
13046            }
13047        }
13048        else
13049        { # Source
13050            if(my $Alt = $SourceAlternative{$Symbol})
13051            {
13052                if(defined $CompleteSignature{1}{$Alt}
13053                and $CompleteSignature{1}{$Symbol}{"Const"})
13054                {
13055                    my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
13056                    %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=(
13057                        "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
13058                        "Target"=>get_Signature($Alt, 1));
13059                }
13060                else
13061                { # do NOT show removed symbol
13062                    next;
13063                }
13064            }
13065        }
13066        %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
13067    }
13068}
13069
13070sub addParamNames($)
13071{
13072    my $LibraryVersion = $_[0];
13073    return if(not keys(%AddIntParams));
13074    my $SecondVersion = $LibraryVersion==1?2:1;
13075    foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
13076    {
13077        next if(not keys(%{$AddIntParams{$Interface}}));
13078        foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
13079        { # add absent parameter names
13080            my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
13081            if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
13082            { # names from the external file
13083                if(defined $CompleteSignature{$SecondVersion}{$Interface}
13084                and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
13085                {
13086                    if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
13087                        $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
13088                    }
13089                }
13090                else {
13091                    $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
13092                }
13093            }
13094        }
13095    }
13096}
13097
13098sub detectChangedTypedefs()
13099{ # detect changed typedefs to show
13100  # correct function signatures
13101    foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
13102    {
13103        next if(not $Typedef);
13104        my $BName1 = $Typedef_BaseName{1}{$Typedef};
13105        if(not $BName1 or isAnon($BName1)) {
13106            next;
13107        }
13108        my $BName2 = $Typedef_BaseName{2}{$Typedef};
13109        if(not $BName2 or isAnon($BName2)) {
13110            next;
13111        }
13112        if($BName1 ne $BName2) {
13113            $ChangedTypedef{$Typedef} = 1;
13114        }
13115    }
13116}
13117
13118sub get_symbol_suffix($$)
13119{
13120    my ($Symbol, $Full) = @_;
13121    my ($SN, $SO, $SV) = separate_symbol($Symbol);
13122    $Symbol=$SN; # remove version
13123    my $Signature = $tr_name{$Symbol};
13124    my $Suffix = substr($Signature, find_center($Signature, "("));
13125    if(not $Full) {
13126        $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
13127    }
13128    return $Suffix;
13129}
13130
13131sub get_symbol_prefix($$)
13132{
13133    my ($Symbol, $LibVersion) = @_;
13134    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
13135    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
13136    { # methods
13137        $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
13138    }
13139    return $ShortName;
13140}
13141
13142sub setAlternative($)
13143{
13144    my $Symbol = $_[0];
13145    my $PSymbol = $Symbol;
13146    if(not defined $CompleteSignature{2}{$PSymbol}
13147    or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
13148    and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
13149    { # search for a pair
13150        if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
13151        {
13152            if($CompleteSignature{1}{$PSymbol}{"Data"})
13153            {
13154                if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
13155                or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
13156                {
13157                    if(defined $CompleteSignature{2}{$PSymbol}
13158                    and $CompleteSignature{2}{$PSymbol}{"MnglName"})
13159                    {
13160                        $SourceAlternative{$Symbol} = $PSymbol;
13161                        $SourceAlternative_B{$PSymbol} = $Symbol;
13162                        if(not defined $CompleteSignature{1}{$PSymbol}
13163                        or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
13164                            $SourceReplacement{$Symbol} = $PSymbol;
13165                        }
13166                    }
13167                }
13168            }
13169            else
13170            {
13171                foreach my $Sp ("KV", "VK", "K", "V")
13172                {
13173                    if($PSymbol=~s/\A_ZN$Sp/_ZN/
13174                    or $PSymbol=~s/\A_ZN/_ZN$Sp/)
13175                    {
13176                        if(defined $CompleteSignature{2}{$PSymbol}
13177                        and $CompleteSignature{2}{$PSymbol}{"MnglName"})
13178                        {
13179                            $SourceAlternative{$Symbol} = $PSymbol;
13180                            $SourceAlternative_B{$PSymbol} = $Symbol;
13181                            if(not defined $CompleteSignature{1}{$PSymbol}
13182                            or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
13183                                $SourceReplacement{$Symbol} = $PSymbol;
13184                            }
13185                        }
13186                    }
13187                    $PSymbol = $Symbol;
13188                }
13189            }
13190        }
13191    }
13192    return "";
13193}
13194
13195sub getSymKind($$)
13196{
13197    my ($Symbol, $LibVersion) = @_;
13198    if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
13199    {
13200        return "Global_Data";
13201    }
13202    elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
13203    {
13204        return "Method";
13205    }
13206    return "Function";
13207}
13208
13209sub mergeSymbols($)
13210{
13211    my $Level = $_[0];
13212    my %SubProblems = ();
13213
13214    mergeBases($Level);
13215
13216    my %AddedOverloads = ();
13217    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
13218    { # check all added exported symbols
13219        if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
13220            next;
13221        }
13222        if(defined $CompleteSignature{1}{$Symbol}
13223        and $CompleteSignature{1}{$Symbol}{"Header"})
13224        { # double-check added symbol
13225            next;
13226        }
13227        if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
13228            next;
13229        }
13230        if($Symbol=~/\A(_Z|\?)/)
13231        { # C++
13232            $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
13233        }
13234        if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
13235        { # register virtual overridings
13236            my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
13237            my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
13238            if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
13239            and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
13240            {
13241                if($TName_Tid{1}{$AffectedClass_Name})
13242                { # class should exist in previous version
13243                    if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
13244                    { # old v-table is NOT copied by old applications
13245                        %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
13246                            "Type_Name"=>$AffectedClass_Name,
13247                            "Target"=>get_Signature($Symbol, 2),
13248                            "Old_Value"=>get_Signature($OverriddenMethod, 2),
13249                            "New_Value"=>get_Signature($Symbol, 2));
13250                    }
13251                }
13252            }
13253        }
13254    }
13255    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
13256    { # check all removed exported symbols
13257        if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
13258            next;
13259        }
13260        if(defined $CompleteSignature{2}{$Symbol}
13261        and $CompleteSignature{2}{$Symbol}{"Header"})
13262        { # double-check removed symbol
13263            next;
13264        }
13265        if($CompleteSignature{1}{$Symbol}{"Private"})
13266        { # skip private methods
13267            next;
13268        }
13269        if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
13270            next;
13271        }
13272        $CheckedSymbols{$Level}{$Symbol} = 1;
13273        if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
13274        { # register virtual overridings
13275            my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
13276            my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
13277            if(defined $CompleteSignature{2}{$OverriddenMethod}
13278            and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
13279            {
13280                if($TName_Tid{2}{$AffectedClass_Name})
13281                { # class should exist in newer version
13282                    if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
13283                    { # old v-table is NOT copied by old applications
13284                        %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
13285                            "Type_Name"=>$AffectedClass_Name,
13286                            "Target"=>get_Signature($OverriddenMethod, 1),
13287                            "Old_Value"=>get_Signature($Symbol, 1),
13288                            "New_Value"=>get_Signature($OverriddenMethod, 1));
13289                    }
13290                }
13291            }
13292        }
13293        if($Level eq "Binary"
13294        and $OSgroup eq "windows")
13295        { # register the reason of symbol name change
13296            if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
13297            {
13298                if($AddedInt{$Level}{$NewSym})
13299                {
13300                    if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
13301                    {
13302                        if($CompleteSignature{2}{$NewSym}{"Static"})
13303                        {
13304                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
13305                                "Target"=>$tr_name{$Symbol},
13306                                "Old_Value"=>$Symbol,
13307                                "New_Value"=>$NewSym  );
13308                        }
13309                        else
13310                        {
13311                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=(
13312                                "Target"=>$tr_name{$Symbol},
13313                                "Old_Value"=>$Symbol,
13314                                "New_Value"=>$NewSym  );
13315                        }
13316                    }
13317                    if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
13318                    {
13319                        if($CompleteSignature{2}{$NewSym}{"Virt"})
13320                        {
13321                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
13322                                "Target"=>$tr_name{$Symbol},
13323                                "Old_Value"=>$Symbol,
13324                                "New_Value"=>$NewSym  );
13325                        }
13326                        else
13327                        {
13328                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=(
13329                                "Target"=>$tr_name{$Symbol},
13330                                "Old_Value"=>$Symbol,
13331                                "New_Value"=>$NewSym  );
13332                        }
13333                    }
13334                    my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
13335                    my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
13336                    my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
13337                    my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
13338                    if($RTName1 ne $RTName2)
13339                    {
13340                        my $ProblemType = "Symbol_Changed_Return";
13341                        if($CompleteSignature{1}{$Symbol}{"Data"}) {
13342                            $ProblemType = "Global_Data_Symbol_Changed_Type";
13343                        }
13344                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
13345                            "Target"=>$tr_name{$Symbol},
13346                            "Old_Type"=>$RTName1,
13347                            "New_Type"=>$RTName2,
13348                            "Old_Value"=>$Symbol,
13349                            "New_Value"=>$NewSym  );
13350                    }
13351                }
13352            }
13353        }
13354        if($Symbol=~/\A(_Z|\?)/)
13355        { # C++
13356            my $Prefix = get_symbol_prefix($Symbol, 1);
13357            if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
13358            and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
13359            { # changed signature: params, "const"-qualifier
13360                my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
13361                if($CompleteSignature{1}{$Symbol}{"Constructor"})
13362                {
13363                    if($Symbol=~/(C[1-2][EI])/)
13364                    {
13365                        my $CtorType = $1;
13366                        $NewSym=~s/(C[1-2][EI])/$CtorType/g;
13367                    }
13368                }
13369                elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
13370                {
13371                    if($Symbol=~/(D[0-2][EI])/)
13372                    {
13373                        my $DtorType = $1;
13374                        $NewSym=~s/(D[0-2][EI])/$DtorType/g;
13375                    }
13376                }
13377                my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
13378                my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
13379                if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
13380                { # from the same class and namespace
13381                    if($CompleteSignature{1}{$Symbol}{"Const"}
13382                    and not $CompleteSignature{2}{$NewSym}{"Const"})
13383                    { # "const" to non-"const"
13384                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=(
13385                            "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
13386                            "Target"=>$tr_name{$Symbol},
13387                            "New_Signature"=>get_Signature($NewSym, 2),
13388                            "Old_Value"=>$Symbol,
13389                            "New_Value"=>$NewSym  );
13390                    }
13391                    elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
13392                    and $CompleteSignature{2}{$NewSym}{"Const"})
13393                    { # non-"const" to "const"
13394                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
13395                            "Target"=>$tr_name{$Symbol},
13396                            "New_Signature"=>get_Signature($NewSym, 2),
13397                            "Old_Value"=>$Symbol,
13398                            "New_Value"=>$NewSym  );
13399                    }
13400                    if($CompleteSignature{1}{$Symbol}{"Volatile"}
13401                    and not $CompleteSignature{2}{$NewSym}{"Volatile"})
13402                    { # "volatile" to non-"volatile"
13403
13404                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=(
13405                            "Target"=>$tr_name{$Symbol},
13406                            "New_Signature"=>get_Signature($NewSym, 2),
13407                            "Old_Value"=>$Symbol,
13408                            "New_Value"=>$NewSym  );
13409                    }
13410                    elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
13411                    and $CompleteSignature{2}{$NewSym}{"Volatile"})
13412                    { # non-"volatile" to "volatile"
13413                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
13414                            "Target"=>$tr_name{$Symbol},
13415                            "New_Signature"=>get_Signature($NewSym, 2),
13416                            "Old_Value"=>$Symbol,
13417                            "New_Value"=>$NewSym  );
13418                    }
13419                    if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
13420                    { # params list
13421                        %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
13422                            "Target"=>$tr_name{$Symbol},
13423                            "New_Signature"=>get_Signature($NewSym, 2),
13424                            "Old_Value"=>$Symbol,
13425                            "New_Value"=>$NewSym  );
13426                    }
13427                }
13428            }
13429        }
13430    }
13431    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
13432    { # checking symbols
13433        $CurrentSymbol = $Symbol;
13434
13435        my ($SN, $SS, $SV) = separate_symbol($Symbol);
13436        if($Level eq "Source")
13437        { # remove symbol version
13438            $Symbol=$SN;
13439        }
13440        else
13441        { # Binary
13442            if(not $SV)
13443            { # symbol without version
13444                if(my $VSym = $SymVer{1}{$Symbol})
13445                { # the symbol is linked with versioned symbol
13446                    if($CompleteSignature{2}{$VSym}{"MnglName"})
13447                    { # show report for symbol@ver only
13448                        next;
13449                    }
13450                    elsif(not link_symbol($VSym, 2, "-Deps"))
13451                    { # changed version: sym@v1 to sym@v2
13452                      # do NOT show report for symbol
13453                        next;
13454                    }
13455                }
13456            }
13457        }
13458        my $PSymbol = $Symbol;
13459        if($Level eq "Source"
13460        and my $S = $SourceReplacement{$Symbol})
13461        { # take a source-compatible replacement function
13462            $PSymbol = $S;
13463        }
13464        if($CompleteSignature{1}{$Symbol}{"Private"})
13465        { # private symbols
13466            next;
13467        }
13468        if(not defined $CompleteSignature{1}{$Symbol}
13469        or not defined $CompleteSignature{2}{$PSymbol})
13470        { # no info
13471            next;
13472        }
13473        if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
13474        or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
13475        { # no mangled name
13476            next;
13477        }
13478        if(not $CompleteSignature{1}{$Symbol}{"Header"}
13479        or not $CompleteSignature{2}{$PSymbol}{"Header"})
13480        { # without a header
13481            next;
13482        }
13483
13484        if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
13485        and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
13486        { # became pure
13487            next;
13488        }
13489        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
13490        and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
13491        { # became non-pure
13492            next;
13493        }
13494
13495        if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
13496        { # exported, target, inline virtual and pure virtual
13497            next;
13498        }
13499        if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
13500        { # exported, target, inline virtual and pure virtual
13501            next;
13502        }
13503
13504        if(checkDump(1, "2.13") and checkDump(2, "2.13"))
13505        {
13506            if($CompleteSignature{1}{$Symbol}{"Data"}
13507            and $CompleteSignature{2}{$PSymbol}{"Data"})
13508            {
13509                my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
13510                my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
13511                if(defined $Value1)
13512                {
13513                    $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
13514                    if(defined $Value2)
13515                    {
13516                        $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
13517                        if($Value1 ne $Value2)
13518                        {
13519                            %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
13520                                "Old_Value"=>$Value1,
13521                                "New_Value"=>$Value2,
13522                                "Target"=>get_Signature($Symbol, 1)  );
13523                        }
13524                    }
13525                }
13526            }
13527        }
13528
13529        if($CompleteSignature{2}{$PSymbol}{"Private"})
13530        {
13531            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
13532                "Target"=>get_Signature_M($PSymbol, 2)  );
13533        }
13534        elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
13535        and $CompleteSignature{2}{$PSymbol}{"Protected"})
13536        {
13537            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
13538                "Target"=>get_Signature_M($PSymbol, 2)  );
13539        }
13540        elsif($CompleteSignature{1}{$Symbol}{"Protected"}
13541        and not $CompleteSignature{2}{$PSymbol}{"Protected"})
13542        {
13543            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
13544                "Target"=>get_Signature_M($PSymbol, 2)  );
13545        }
13546
13547        # checking virtual table
13548        mergeVirtualTables($Symbol, $Level);
13549
13550        if($COMPILE_ERRORS)
13551        { # if some errors occurred at the compiling stage
13552          # then some false positives can be skipped here
13553            if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
13554            and not $GlobalDataObject{2}{$Symbol})
13555            { # missed information about parameters in newer version
13556                next;
13557            }
13558            if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
13559            and not $CompleteSignature{2}{$PSymbol}{"Data"})
13560            { # missed information about parameters in older version
13561                next;
13562            }
13563        }
13564        my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
13565        # checking attributes
13566        if($CompleteSignature{2}{$PSymbol}{"Static"}
13567        and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
13568        {
13569            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
13570                "Target"=>get_Signature($Symbol, 1)
13571            );
13572        }
13573        elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
13574        and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
13575        {
13576            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=(
13577                "Target"=>get_Signature($Symbol, 1)
13578            );
13579        }
13580        if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
13581        or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
13582        { # relative position of virtual and pure virtual methods
13583            if($Level eq "Binary")
13584            {
13585                if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
13586                and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
13587                { # top-level virtual methods only
13588                    my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
13589                    my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
13590                    if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
13591                    and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
13592                    { # check the absolute position of virtual method (including added and removed methods)
13593                        my %Class_Type = get_Type($Class_Id, 1);
13594                        my $ProblemType = "Virtual_Method_Position";
13595                        if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
13596                            $ProblemType = "Pure_Virtual_Method_Position";
13597                        }
13598                        if(isUsedClass($Class_Id, 1, $Level))
13599                        {
13600                            my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
13601                            foreach my $ASymbol (@Affected)
13602                            {
13603                                if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
13604                                    next;
13605                                }
13606                                %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
13607                                    "Type_Name"=>$Class_Type{"Name"},
13608                                    "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
13609                                    "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
13610                                    "Target"=>get_Signature($Symbol, 1));
13611                            }
13612                            $VTableChanged_M{$Class_Type{"Name"}} = 1;
13613                        }
13614                    }
13615                }
13616            }
13617        }
13618        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
13619        or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
13620        { # do NOT check type changes in pure virtuals
13621            next;
13622        }
13623        $CheckedSymbols{$Level}{$Symbol} = 1;
13624        if($Symbol=~/\A(_Z|\?)/
13625        or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
13626        { # C/C++: changes in parameters
13627            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
13628            { # checking parameters
13629                mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1);
13630            }
13631        }
13632        else
13633        { # C: added/removed parameters
13634            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
13635            { # checking added parameters
13636                my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
13637                my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
13638                last if($PType2_Name eq "...");
13639                my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
13640                my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
13641                my $ParamPos_Prev = "-1";
13642                if($PName=~/\Ap\d+\Z/i)
13643                { # added unnamed parameter ( pN )
13644                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
13645                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
13646                    if($#Positions1==-1 or $#Positions2>$#Positions1) {
13647                        $ParamPos_Prev = "lost";
13648                    }
13649                }
13650                else {
13651                    $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
13652                }
13653                if($ParamPos_Prev eq "lost")
13654                {
13655                    if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
13656                    {
13657                        my $ProblemType = "Added_Parameter";
13658                        if($PName=~/\Ap\d+\Z/) {
13659                            $ProblemType = "Added_Unnamed_Parameter";
13660                        }
13661                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
13662                            "Target"=>$PName,
13663                            "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13664                            "Param_Type"=>$PType2_Name,
13665                            "New_Signature"=>get_Signature($Symbol, 2)  );
13666                    }
13667                    else
13668                    {
13669                        my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
13670                        my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
13671                        my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
13672                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
13673                        and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
13674                        {
13675                            if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
13676                            {
13677                                %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
13678                                    "Target"=>$PName_Old,
13679                                    "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13680                                    "Param_Type"=>$PType2_Name,
13681                                    "Old_Value"=>$PName_Old,
13682                                    "New_Value"=>$PName,
13683                                    "New_Signature"=>get_Signature($Symbol, 2)  );
13684                            }
13685                        }
13686                        else
13687                        {
13688                            my $ProblemType = "Added_Middle_Parameter";
13689                            if($PName=~/\Ap\d+\Z/) {
13690                                $ProblemType = "Added_Middle_Unnamed_Parameter";
13691                            }
13692                            %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
13693                                "Target"=>$PName,
13694                                "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13695                                "Param_Type"=>$PType2_Name,
13696                                "New_Signature"=>get_Signature($Symbol, 2)  );
13697                        }
13698                    }
13699                }
13700            }
13701            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
13702            { # check relevant parameters
13703                my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
13704                my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
13705                # FIXME: find relevant parameter by name
13706                if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
13707                {
13708                    my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
13709                    my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
13710                    if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
13711                    or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
13712                        mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0);
13713                    }
13714                }
13715            }
13716            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
13717            { # checking removed parameters
13718                my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
13719                my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
13720                last if($PType1_Name eq "...");
13721                my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
13722                my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
13723                my $ParamPos_New = "-1";
13724                if($PName=~/\Ap\d+\Z/i)
13725                { # removed unnamed parameter ( pN )
13726                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
13727                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
13728                    if($#Positions2==-1 or $#Positions2<$#Positions1) {
13729                        $ParamPos_New = "lost";
13730                    }
13731                }
13732                else {
13733                    $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2);
13734                }
13735                if($ParamPos_New eq "lost")
13736                {
13737                    if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
13738                    {
13739                        my $ProblemType = "Removed_Parameter";
13740                        if($PName=~/\Ap\d+\Z/) {
13741                            $ProblemType = "Removed_Unnamed_Parameter";
13742                        }
13743                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
13744                            "Target"=>$PName,
13745                            "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13746                            "Param_Type"=>$PType1_Name,
13747                            "New_Signature"=>get_Signature($Symbol, 2)  );
13748                    }
13749                    elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
13750                    {
13751                        my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
13752                        my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
13753                        my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
13754                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
13755                        and find_ParamPair_Pos_byName($PName_New, $Symbol, 1) eq "lost")
13756                        {
13757                            if($PName_New!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
13758                            {
13759                                %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
13760                                    "Target"=>$PName,
13761                                    "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13762                                    "Param_Type"=>$PType1_Name,
13763                                    "Old_Value"=>$PName,
13764                                    "New_Value"=>$PName_New,
13765                                    "New_Signature"=>get_Signature($Symbol, 2)  );
13766                            }
13767                        }
13768                        else
13769                        {
13770                            my $ProblemType = "Removed_Middle_Parameter";
13771                            if($PName=~/\Ap\d+\Z/) {
13772                                $ProblemType = "Removed_Middle_Unnamed_Parameter";
13773                            }
13774                            %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
13775                                "Target"=>$PName,
13776                                "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2),
13777                                "Param_Type"=>$PType1_Name,
13778                                "New_Signature"=>get_Signature($Symbol, 2)  );
13779                        }
13780                    }
13781                }
13782            }
13783        }
13784        # checking return type
13785        my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
13786        my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
13787        my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
13788
13789        foreach my $SubProblemType (keys(%RC_SubProblems))
13790        {
13791            my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"};
13792            my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"};
13793            my %ProblemTypes = ();
13794
13795            if($CompleteSignature{1}{$Symbol}{"Data"})
13796            {
13797                if($SubProblemType eq "Return_Type_And_Size") {
13798                    $ProblemTypes{"Global_Data_Type_And_Size"} = 1;
13799                }
13800                elsif($SubProblemType eq "Return_Type_Format") {
13801                    $ProblemTypes{"Global_Data_Type_Format"} = 1;
13802                }
13803                else {
13804                    $ProblemTypes{"Global_Data_Type"} = 1;
13805                }
13806
13807                # quals
13808                if($SubProblemType eq "Return_Type"
13809                or $SubProblemType eq "Return_Type_And_Size"
13810                or $SubProblemType eq "Return_Type_Format")
13811                {
13812                    if(my $RR = removedQual($Old_Value, $New_Value, "const"))
13813                    { # const to non-const
13814                        if($RR==2) {
13815                            $ProblemTypes{"Global_Data_Removed_Const"} = 1;
13816                        }
13817                        else {
13818                            $ProblemTypes{"Global_Data_Became_Non_Const"} = 1;
13819                        }
13820                        $ProblemTypes{"Global_Data_Type"} = 1;
13821                    }
13822                    elsif(my $RA = addedQual($Old_Value, $New_Value, "const"))
13823                    { # non-const to const
13824                        if($RA==2) {
13825                            $ProblemTypes{"Global_Data_Added_Const"} = 1;
13826                        }
13827                        else {
13828                            $ProblemTypes{"Global_Data_Became_Const"} = 1;
13829                        }
13830                        $ProblemTypes{"Global_Data_Type"} = 1;
13831                    }
13832                }
13833            }
13834            else
13835            {
13836                # quals
13837                if($SubProblemType eq "Return_Type"
13838                or $SubProblemType eq "Return_Type_And_Size"
13839                or $SubProblemType eq "Return_Type_Format")
13840                {
13841                    if(checkDump(1, "2.6") and checkDump(2, "2.6"))
13842                    {
13843                        if(addedQual($Old_Value, $New_Value, "volatile"))
13844                        {
13845                            $ProblemTypes{"Return_Value_Became_Volatile"} = 1;
13846                            if($Level ne "Source"
13847                            or not cmpBTypes($Old_Value, $New_Value, 1, 2)) {
13848                                $ProblemTypes{"Return_Type"} = 1;
13849                            }
13850                        }
13851                    }
13852                    if(my $RA = addedQual($Old_Value, $New_Value, "const"))
13853                    {
13854                        if($RA==2) {
13855                            $ProblemTypes{"Return_Type_Added_Const"} = 1;
13856                        }
13857                        else {
13858                            $ProblemTypes{"Return_Type_Became_Const"} = 1;
13859                        }
13860                        if($Level ne "Source"
13861                        or not cmpBTypes($Old_Value, $New_Value, 1, 2)) {
13862                            $ProblemTypes{"Return_Type"} = 1;
13863                        }
13864                    }
13865                }
13866            }
13867            if($Level eq "Binary"
13868            and not $CompleteSignature{1}{$Symbol}{"Data"})
13869            {
13870                my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13871                if($Arch1 eq "unknown" or $Arch2 eq "unknown")
13872                { # if one of the architectures is unknown
13873                    # then set other arhitecture to unknown too
13874                    ($Arch1, $Arch2) = ("unknown", "unknown");
13875                }
13876                my (%Conv1, %Conv2) = ();
13877                if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"})
13878                {
13879                    %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
13880                    %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
13881                }
13882                else
13883                {
13884                    %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13885                    %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13886                }
13887
13888                if($SubProblemType eq "Return_Type_Became_Void")
13889                {
13890                    if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
13891                    { # parameters stack has been affected
13892                        if($Conv1{"Method"} eq "stack") {
13893                            $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1;
13894                        }
13895                        elsif($Conv1{"Hidden"}) {
13896                            $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1;
13897                        }
13898                    }
13899                }
13900                elsif($SubProblemType eq "Return_Type_From_Void")
13901                {
13902                    if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
13903                    { # parameters stack has been affected
13904                        if($Conv2{"Method"} eq "stack") {
13905                            $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1;
13906                        }
13907                        elsif($Conv2{"Hidden"}) {
13908                            $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1;
13909                        }
13910                    }
13911                }
13912                elsif($SubProblemType eq "Return_Type"
13913                or $SubProblemType eq "Return_Type_And_Size"
13914                or $SubProblemType eq "Return_Type_Format")
13915                {
13916                    if($Conv1{"Method"} ne $Conv2{"Method"})
13917                    {
13918                        if($Conv1{"Method"} eq "stack")
13919                        { # returns in a register instead of a hidden first parameter
13920                            $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1;
13921                        }
13922                        else {
13923                            $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1;
13924                        }
13925                    }
13926                    else
13927                    {
13928                        if($Conv1{"Method"} eq "reg")
13929                        {
13930                            if($Conv1{"Registers"} ne $Conv2{"Registers"})
13931                            {
13932                                if($Conv1{"Hidden"}) {
13933                                    $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1;
13934                                }
13935                                elsif($Conv2{"Hidden"}) {
13936                                    $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1;
13937                                }
13938                                else {
13939                                    $ProblemTypes{"Return_Type_And_Register"} = 1;
13940                                }
13941                            }
13942                        }
13943                    }
13944                }
13945            }
13946
13947            if(not keys(%ProblemTypes))
13948            { # default
13949                $ProblemTypes{$SubProblemType} = 1;
13950            }
13951
13952            foreach my $ProblemType (keys(%ProblemTypes))
13953            { # additional
13954                $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType};
13955            }
13956        }
13957        if($ReturnType1_Id and $ReturnType2_Id)
13958        {
13959            @RecurTypes = ();
13960            my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
13961
13962            my $AddProblems = {};
13963
13964            if($CompleteSignature{1}{$Symbol}{"Data"})
13965            {
13966                if($Level eq "Binary")
13967                {
13968                    if(get_PLevel($ReturnType1_Id, 1)==0)
13969                    {
13970                        foreach my $SubProblemType (keys(%{$Sub_SubProblems}))
13971                        { # add "Global_Data_Size" problem
13972                            my $New_Value = $Sub_SubProblems->{$SubProblemType}{"New_Value"};
13973                            my $Old_Value = $Sub_SubProblems->{$SubProblemType}{"Old_Value"};
13974                            if($SubProblemType eq "DataType_Size")
13975                            { # add a new problem
13976                                $AddProblems->{"Global_Data_Size"} = $Sub_SubProblems->{$SubProblemType};
13977                            }
13978                        }
13979                    }
13980                    if(not defined $AddProblems->{"Global_Data_Size"})
13981                    {
13982                        if(defined $GlobalDataObject{1}{$Symbol}
13983                        and defined $GlobalDataObject{2}{$Symbol})
13984                        {
13985                            my $Old_Size = $GlobalDataObject{1}{$Symbol};
13986                            my $New_Size = $GlobalDataObject{2}{$Symbol};
13987                            if($Old_Size!=$New_Size)
13988                            {
13989                                $AddProblems->{"Global_Data_Size"}{"retval"} = {
13990                                    "Old_Size"=>$Old_Size*$BYTE_SIZE,
13991                                    "New_Size"=>$New_Size*$BYTE_SIZE };
13992                            }
13993                        }
13994                    }
13995                }
13996            }
13997
13998            foreach my $SubProblemType (keys(%{$AddProblems}))
13999            {
14000                foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}}))
14001                {
14002                    my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
14003                    $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation};
14004                }
14005            }
14006
14007            foreach my $SubProblemType (keys(%{$Sub_SubProblems}))
14008            {
14009                foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}}))
14010                {
14011                    my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
14012                    $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation};
14013                }
14014            }
14015        }
14016
14017        # checking object type
14018        my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
14019        my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
14020        if($ObjTId1 and $ObjTId2
14021        and not $CompleteSignature{1}{$Symbol}{"Static"})
14022        {
14023            my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
14024            my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
14025            if($ThisPtr1_Id and $ThisPtr2_Id)
14026            {
14027                @RecurTypes = ();
14028                my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
14029                foreach my $SubProblemType (keys(%{$Sub_SubProblems}))
14030                {
14031                    foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}}))
14032                    {
14033                        my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
14034                        $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation};
14035                    }
14036                }
14037            }
14038        }
14039    }
14040    if($Level eq "Binary") {
14041        mergeVTables($Level);
14042    }
14043    foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
14044        $CheckedSymbols{$Level}{$Symbol} = 1;
14045    }
14046}
14047
14048sub rmQuals($$)
14049{
14050    my ($Value, $Qual) = @_;
14051    if(not $Qual) {
14052        return $Value;
14053    }
14054    if($Qual eq "all")
14055    { # all quals
14056        $Qual = "const|volatile|restrict";
14057    }
14058    while($Value=~s/\b$Qual\b//) {
14059        $Value = formatName($Value, "T");
14060    }
14061    return $Value;
14062}
14063
14064sub cmpBTypes($$$$)
14065{
14066    my ($T1, $T2, $V1, $V2) = @_;
14067    $T1 = uncover_typedefs($T1, $V1);
14068    $T2 = uncover_typedefs($T2, $V2);
14069    return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
14070}
14071
14072sub addedQual($$$)
14073{
14074    my ($Old_Value, $New_Value, $Qual) = @_;
14075    return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual);
14076}
14077
14078sub removedQual($$$)
14079{
14080    my ($Old_Value, $New_Value, $Qual) = @_;
14081    return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual);
14082}
14083
14084sub removedQual_I($$$$$)
14085{
14086    my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
14087    $Old_Value = uncover_typedefs($Old_Value, $V1);
14088    $New_Value = uncover_typedefs($New_Value, $V2);
14089    if($Old_Value eq $New_Value)
14090    { # equal types
14091        return 0;
14092    }
14093    if($Old_Value!~/\b$Qual\b/)
14094    { # without a qual
14095        return 0;
14096    }
14097    elsif($New_Value!~/\b$Qual\b/)
14098    { # became non-qual
14099        return 1;
14100    }
14101    else
14102    {
14103        my @BQ1 = getQualModel($Old_Value, $Qual);
14104        my @BQ2 = getQualModel($New_Value, $Qual);
14105        foreach (0 .. $#BQ1)
14106        { # removed qual
14107            if($BQ1[$_]==1
14108            and $BQ2[$_]!=1)
14109            {
14110                return 2;
14111            }
14112        }
14113    }
14114    return 0;
14115}
14116
14117sub getQualModel($$)
14118{
14119    my ($Value, $Qual) = @_;
14120    if(not $Qual) {
14121        return $Value;
14122    }
14123
14124    # cleaning
14125    while($Value=~/(\w+)/ and $1 ne $Qual) {
14126        $Value=~s/\b$1\b//g;
14127    }
14128    $Value=~s/[^\*\&\w]+//g;
14129
14130    # modeling
14131    # int*const*const == 011
14132    # int**const == 001
14133    my @Model = ();
14134    my @Elems = split(/[\*\&]/, $Value);
14135    if(not @Elems) {
14136        return (0);
14137    }
14138    foreach (@Elems)
14139    {
14140        if($_ eq $Qual) {
14141            push(@Model, 1);
14142        }
14143        else {
14144            push(@Model, 0);
14145        }
14146    }
14147
14148    return @Model;
14149}
14150
14151my %StringTypes = map {$_=>1} (
14152    "char*",
14153    "char const*"
14154);
14155
14156my %CharTypes = map {$_=>1} (
14157    "char",
14158    "char const"
14159);
14160
14161sub showVal($$$)
14162{
14163    my ($Value, $TypeId, $LibVersion) = @_;
14164    my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
14165    my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
14166    if(substr($Value, 0, 2) eq "_Z")
14167    {
14168        if(my $Unmangled = $tr_name{$Value}) {
14169            return $Unmangled;
14170        }
14171    }
14172    elsif(defined $StringTypes{$TName} or $TName=~/string/i)
14173    { # strings
14174        return "\"$Value\"";
14175    }
14176    elsif(defined $CharTypes{$TName})
14177    { # characters
14178        return "\'$Value\'";
14179    }
14180    if($Value eq "")
14181    { # other
14182        return "\'\'";
14183    }
14184    return $Value;
14185}
14186
14187sub getRegs($$$)
14188{
14189    my ($LibVersion, $Symbol, $Pos) = @_;
14190
14191    if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"})
14192    {
14193        my %Regs = ();
14194        foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}}))
14195        {
14196            if($Elem=~/\A$Pos([\.\+]|\Z)/) {
14197                $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1;
14198            }
14199        }
14200
14201        return join(", ", sort keys(%Regs));
14202    }
14203
14204    return undef;
14205}
14206
14207sub mergeParameters($$$$$$)
14208{
14209    my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_;
14210    if(not $Symbol) {
14211        return;
14212    }
14213    my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
14214    my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
14215    my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
14216    my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
14217    if(not $PType1_Id
14218    or not $PType2_Id) {
14219        return;
14220    }
14221
14222    if($Symbol=~/\A(_Z|\?)/)
14223    { # do not merge "this"
14224        if($PName1 eq "this" or $PName2 eq "this") {
14225            return;
14226        }
14227    }
14228
14229    my %Type1 = get_Type($PType1_Id, 1);
14230    my %Type2 = get_Type($PType2_Id, 2);
14231    my %BaseType1 = get_BaseType($PType1_Id, 1);
14232    my %BaseType2 = get_BaseType($PType2_Id, 2);
14233    my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
14234
14235    if($Level eq "Binary")
14236    {
14237        if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
14238        { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
14239            if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
14240            and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
14241            {
14242                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
14243                    "Target"=>$PName1,
14244                    "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1)  );
14245            }
14246            elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
14247            and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
14248            {
14249                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
14250                    "Target"=>$PName1,
14251                    "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1)  );
14252            }
14253        }
14254
14255        if(defined $UsedDump{1}{"DWARF"}
14256        and defined $UsedDump{2}{"DWARF"})
14257        {
14258            if(checkDump(1, "3.0") and checkDump(2, "3.0"))
14259            {
14260                my $Old_Regs = getRegs(1, $Symbol, $ParamPos1);
14261                my $New_Regs = getRegs(2, $PSymbol, $ParamPos2);
14262                if($Old_Regs and $New_Regs)
14263                {
14264                    if($Old_Regs ne $New_Regs)
14265                    {
14266                        %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=(
14267                            "Target"=>$PName1,
14268                            "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14269                            "Old_Value"=>$Old_Regs,
14270                            "New_Value"=>$New_Regs  );
14271                    }
14272                }
14273                elsif($Old_Regs and not $New_Regs)
14274                {
14275                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=(
14276                        "Target"=>$PName1,
14277                        "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14278                        "Old_Value"=>$Old_Regs  );
14279                }
14280                elsif(not $Old_Regs and $New_Regs)
14281                {
14282                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=(
14283                        "Target"=>$PName1,
14284                        "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14285                        "New_Value"=>$New_Regs  );
14286                }
14287                if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne ""
14288                and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "")
14289                {
14290                    if($Old_Offset ne $New_Offset)
14291                    {
14292                        my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"};
14293                        my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"};
14294
14295                        $Old_Offset = $Old_Offset - $Start1;
14296                        $New_Offset = $New_Offset - $Start2;
14297
14298                        if($Old_Offset ne $New_Offset)
14299                        {
14300                            %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=(
14301                                "Target"=>$PName1,
14302                                "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14303                                "Old_Value"=>$Old_Offset,
14304                                "New_Value"=>$New_Offset  );
14305                        }
14306                    }
14307                }
14308            }
14309        }
14310    }
14311    if(checkDump(1, "2.0") and checkDump(2, "2.0")
14312    and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1")
14313    { # "default" attribute added in ACC 1.22 (dump 2.0 format)
14314      # broken in 3.1, fixed in 3.2
14315        my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
14316        my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
14317        if(not checkDump(1, "2.13")
14318        and checkDump(2, "2.13"))
14319        { # support for old ABI dumps
14320            if(defined $Value_Old and defined $Value_New)
14321            {
14322                if($Type1{"Name"} eq "bool"
14323                and $Value_Old eq "false" and $Value_New eq "0")
14324                { # int class::method ( bool p = 0 );
14325                  # old ABI dumps: "false"
14326                  # new ABI dumps: "0"
14327                    $Value_Old = "0";
14328                }
14329            }
14330        }
14331        if(not checkDump(1, "2.18")
14332        and checkDump(2, "2.18"))
14333        { # support for old ABI dumps
14334            if(not defined $Value_Old
14335            and substr($Value_New, 0, 2) eq "_Z") {
14336                $Value_Old = $Value_New;
14337            }
14338        }
14339        if(defined $Value_Old)
14340        {
14341            $Value_Old = showVal($Value_Old, $PType1_Id, 1);
14342            if(defined $Value_New)
14343            {
14344                $Value_New = showVal($Value_New, $PType2_Id, 2);
14345                if($Value_Old ne $Value_New)
14346                { # FIXME: how to distinguish "0" and 0 (NULL)
14347                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
14348                        "Target"=>$PName1,
14349                        "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14350                        "Old_Value"=>$Value_Old,
14351                        "New_Value"=>$Value_New  );
14352                }
14353            }
14354            else
14355            {
14356                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
14357                    "Target"=>$PName1,
14358                    "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14359                    "Old_Value"=>$Value_Old  );
14360            }
14361        }
14362        elsif(defined $Value_New)
14363        {
14364            $Value_New = showVal($Value_New, $PType2_Id, 2);
14365            %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
14366                "Target"=>$PName1,
14367                "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14368                "New_Value"=>$Value_New  );
14369        }
14370    }
14371
14372    if($ChkRnmd)
14373    {
14374        if($PName1 and $PName2 and $PName1 ne $PName2
14375        and $PType1_Id!=-1 and $PType2_Id!=-1
14376        and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
14377        { # except unnamed "..." value list (Id=-1)
14378            %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
14379                "Target"=>$PName1,
14380                "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14381                "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
14382                "Old_Value"=>$PName1,
14383                "New_Value"=>$PName2,
14384                "New_Signature"=>get_Signature($Symbol, 2)  );
14385        }
14386    }
14387
14388    # checking type change (replace)
14389    my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
14390
14391    foreach my $SubProblemType (keys(%SubProblems))
14392    { # add new problems, remove false alarms
14393        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
14394        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
14395
14396        # quals
14397        if($SubProblemType eq "Parameter_Type"
14398        or $SubProblemType eq "Parameter_Type_And_Size"
14399        or $SubProblemType eq "Parameter_Type_Format")
14400        {
14401            if(checkDump(1, "2.6") and checkDump(2, "2.6"))
14402            {
14403                if(addedQual($Old_Value, $New_Value, "restrict")) {
14404                    %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
14405                }
14406                elsif(removedQual($Old_Value, $New_Value, "restrict")) {
14407                    %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}};
14408                }
14409            }
14410            if(checkDump(1, "2.6") and checkDump(2, "2.6"))
14411            {
14412                if(removedQual($Old_Value, $New_Value, "volatile")) {
14413                    %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}};
14414                }
14415            }
14416            if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
14417            and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
14418            { # int to "int const"
14419                delete($SubProblems{$SubProblemType});
14420            }
14421            elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
14422            and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
14423            { # "int const" to int
14424                delete($SubProblems{$SubProblemType});
14425            }
14426            elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
14427            { # "const" to non-"const"
14428                if($RR==2) {
14429                    %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}};
14430                }
14431                else {
14432                    %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}};
14433                }
14434            }
14435        }
14436    }
14437
14438    if($Level eq "Source")
14439    {
14440        foreach my $SubProblemType (keys(%SubProblems))
14441        {
14442            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
14443            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
14444
14445            if($SubProblemType eq "Parameter_Type")
14446            {
14447                if(cmpBTypes($Old_Value, $New_Value, 1, 2)) {
14448                    delete($SubProblems{$SubProblemType});
14449                }
14450            }
14451        }
14452    }
14453
14454    foreach my $SubProblemType (keys(%SubProblems))
14455    { # modify/register problems
14456        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
14457        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
14458        my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
14459        my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
14460
14461        my $NewProblemType = $SubProblemType;
14462        if($Old_Value eq "..." and $New_Value ne "...")
14463        { # change from "..." to "int"
14464            if($ParamPos1==0)
14465            { # ISO C requires a named argument before "..."
14466                next;
14467            }
14468            $NewProblemType = "Parameter_Became_Non_VaList";
14469        }
14470        elsif($New_Value eq "..." and $Old_Value ne "...")
14471        { # change from "int" to "..."
14472            if($ParamPos2==0)
14473            { # ISO C requires a named argument before "..."
14474                next;
14475            }
14476            $NewProblemType = "Parameter_Became_VaList";
14477        }
14478        elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
14479        or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
14480        {
14481            my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14482            if($Arch1 eq "unknown"
14483            or $Arch2 eq "unknown")
14484            { # if one of the architectures is unknown
14485              # then set other arhitecture to unknown too
14486                ($Arch1, $Arch2) = ("unknown", "unknown");
14487            }
14488            my (%Conv1, %Conv2) = ();
14489            if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"})
14490            { # real
14491                %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
14492                %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
14493            }
14494            else
14495            { # model
14496                %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
14497                %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
14498            }
14499            if($Conv1{"Method"} eq $Conv2{"Method"})
14500            {
14501                if($Conv1{"Method"} eq "stack")
14502                {
14503                    if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
14504                        $NewProblemType = "Parameter_Type_And_Stack";
14505                    }
14506                }
14507                elsif($Conv1{"Method"} eq "reg")
14508                {
14509                    if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
14510                        $NewProblemType = "Parameter_Type_And_Register";
14511                    }
14512                }
14513            }
14514            else
14515            {
14516                if($Conv1{"Method"} eq "stack") {
14517                    $NewProblemType = "Parameter_Type_From_Stack_To_Register";
14518                }
14519                elsif($Conv1{"Method"} eq "register") {
14520                    $NewProblemType = "Parameter_Type_From_Register_To_Stack";
14521                }
14522            }
14523            $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
14524            $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
14525        }
14526        %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
14527            "Target"=>$PName1,
14528            "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1),
14529            "New_Signature"=>get_Signature($Symbol, 2) );
14530        @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
14531    }
14532
14533    @RecurTypes = ();
14534
14535    # checking type definition changes
14536    my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level);
14537    foreach my $SubProblemType (keys(%{$Sub_SubProblems}))
14538    {
14539        foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}}))
14540        {
14541            my $NewProblemType = $SubProblemType;
14542            if($SubProblemType eq "DataType_Size")
14543            {
14544                if($Type1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
14545                { # stack has been affected
14546                    $NewProblemType = "DataType_Size_And_Stack";
14547                }
14548            }
14549            my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
14550            $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation};
14551        }
14552    }
14553}
14554
14555sub find_ParamPair_Pos_byName($$$)
14556{
14557    my ($Name, $Symbol, $LibVersion) = @_;
14558    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
14559    {
14560        next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
14561        if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
14562        {
14563            return $ParamPos;
14564        }
14565    }
14566    return "lost";
14567}
14568
14569sub find_ParamPair_Pos_byTypeAndPos($$$$$)
14570{
14571    my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
14572    my @Positions = ();
14573    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
14574    {
14575        next if($Order eq "backward" and $ParamPos>$MediumPos);
14576        next if($Order eq "forward" and $ParamPos<$MediumPos);
14577        next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
14578        my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
14579        if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
14580            push(@Positions, $ParamPos);
14581        }
14582    }
14583    return @Positions;
14584}
14585
14586sub getTypeIdByName($$)
14587{
14588    my ($TypeName, $LibVersion) = @_;
14589    return $TName_Tid{$LibVersion}{formatName($TypeName, "T")};
14590}
14591
14592sub diffTypes($$$)
14593{
14594    if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) {
14595        return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]};
14596    }
14597    if(isRecurType($_[0], $_[1], \@RecurTypes_Diff))
14598    { # skip recursive declarations
14599        return 0;
14600    }
14601
14602    pushType($_[0], $_[1], \@RecurTypes_Diff);
14603    my $Diff = diffTypes_I(@_);
14604    pop(@RecurTypes_Diff);
14605
14606    return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff);
14607}
14608
14609sub diffTypes_I($$$)
14610{
14611    my ($Type1_Id, $Type2_Id, $Level) = @_;
14612
14613    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
14614    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
14615
14616    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
14617    { # equal types
14618        return 0;
14619    }
14620    if($Type1_Pure{"Name"} eq "void")
14621    { # from void* to something
14622        return 0;
14623    }
14624    if($Type1_Pure{"Name"}=~/\*/
14625    or $Type2_Pure{"Name"}=~/\*/)
14626    { # compared in detectTypeChange()
14627        return 0;
14628    }
14629
14630    my %FloatType = map {$_=>1} (
14631        "float",
14632        "double",
14633        "long double"
14634    );
14635
14636    my $T1 = $Type1_Pure{"Type"};
14637    my $T2 = $Type2_Pure{"Type"};
14638
14639    if($T1 eq "Struct"
14640    and $T2 eq "Class")
14641    { # compare as data structures
14642        $T2 = "Struct";
14643    }
14644
14645    if($T1 eq "Class"
14646    and $T2 eq "Struct")
14647    { # compare as data structures
14648        $T1 = "Struct";
14649    }
14650
14651    if($T1 ne $T2)
14652    { # different types
14653        if($T1 eq "Intrinsic"
14654        and $T2 eq "Enum")
14655        { # "int" to "enum"
14656            return 0;
14657        }
14658        elsif($T2 eq "Intrinsic"
14659        and $T1 eq "Enum")
14660        { # "enum" to "int"
14661            return 0;
14662        }
14663        else
14664        { # union to struct
14665          #  ...
14666            return 1;
14667        }
14668    }
14669    else
14670    {
14671        if($T1 eq "Intrinsic")
14672        {
14673            if($FloatType{$Type1_Pure{"Name"}}
14674            or $FloatType{$Type2_Pure{"Name"}})
14675            { # "float" to "double"
14676              # "float" to "int"
14677                if($Level eq "Source")
14678                { # Safe
14679                    return 0;
14680                }
14681                else {
14682                    return 1;
14683                }
14684            }
14685        }
14686        elsif($T1=~/Class|Struct|Union|Enum/)
14687        {
14688            my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
14689            my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
14690            if(not @Membs1
14691            or not @Membs2)
14692            { # private
14693                return 0;
14694            }
14695            if($#Membs1!=$#Membs2)
14696            { # different number of elements
14697                return 1;
14698            }
14699            if($T1 eq "Enum")
14700            {
14701                foreach my $Pos (@Membs1)
14702                { # compare elements by name and value
14703                    if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
14704                    or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
14705                    { # different names
14706                        return 1;
14707                    }
14708                }
14709            }
14710            else
14711            {
14712                foreach my $Pos (@Membs1)
14713                {
14714                    if($Level eq "Source")
14715                    {
14716                        if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
14717                        { # different names
14718                            return 1;
14719                        }
14720                    }
14721
14722                    my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}};
14723                    my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}};
14724
14725                    if($MT1{"Name"} ne $MT2{"Name"}
14726                    or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"}))
14727                    {
14728                        my $PL1 = get_PLevel($MT1{"Tid"}, 1);
14729                        my $PL2 = get_PLevel($MT2{"Tid"}, 2);
14730
14731                        if($PL1 ne $PL2)
14732                        { # different pointer level
14733                            return 1;
14734                        }
14735
14736                        # compare base types
14737                        my %BT1 = get_BaseType($MT1{"Tid"}, 1);
14738                        my %BT2 = get_BaseType($MT2{"Tid"}, 2);
14739
14740                        if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level))
14741                        { # different types
14742                            return 1;
14743                        }
14744                    }
14745                }
14746            }
14747        }
14748        else
14749        {
14750            # TODO: arrays, etc.
14751        }
14752    }
14753    return 0;
14754}
14755
14756sub detectTypeChange($$$$)
14757{
14758    my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
14759    if(not $Type1_Id or not $Type2_Id) {
14760        return ();
14761    }
14762    my %LocalProblems = ();
14763    my %Type1 = get_Type($Type1_Id, 1);
14764    my %Type2 = get_Type($Type2_Id, 2);
14765    my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
14766    my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
14767    my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
14768    my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2);
14769
14770    my $Type1_PLevel = get_PLevel($Type1_Id, 1);
14771    my $Type2_PLevel = get_PLevel($Type2_Id, 2);
14772    return () if(not $Type1{"Name"} or not $Type2{"Name"});
14773    return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
14774    return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
14775    if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
14776    and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
14777    and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
14778    { # base type change
14779        if($Type1{"Name"} eq $Type2{"Name"})
14780        {
14781            if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
14782            { # will be reported in mergeTypes() as typedef problem
14783                return ();
14784            }
14785            my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
14786            my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
14787            if(%Typedef_1 and %Typedef_2)
14788            {
14789                if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
14790                and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
14791                { # const Typedef
14792                    return ();
14793                }
14794            }
14795        }
14796        if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
14797        {
14798            if($Level eq "Binary"
14799            and $Type1_Base{"Size"} and $Type2_Base{"Size"}
14800            and $Type1_Base{"Size"} ne $Type2_Base{"Size"})
14801            {
14802                %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
14803                    "Old_Value"=>$Type1_Base{"Name"},
14804                    "New_Value"=>$Type2_Base{"Name"},
14805                    "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
14806                    "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE);
14807            }
14808            else
14809            {
14810                if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
14811                { # format change
14812                    %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
14813                        "Old_Value"=>$Type1_Base{"Name"},
14814                        "New_Value"=>$Type2_Base{"Name"},
14815                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
14816                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE);
14817                }
14818                elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
14819                {
14820                    %{$LocalProblems{$Prefix."_BaseType"}}=(
14821                        "Old_Value"=>$Type1_Base{"Name"},
14822                        "New_Value"=>$Type2_Base{"Name"},
14823                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
14824                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE);
14825                }
14826            }
14827        }
14828    }
14829    elsif($Type1{"Name"} ne $Type2{"Name"})
14830    { # type change
14831        if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
14832        {
14833            if($Prefix eq "Return"
14834            and $Type1_Pure{"Name"} eq "void")
14835            {
14836                %{$LocalProblems{"Return_Type_From_Void"}}=(
14837                    "New_Value"=>$Type2{"Name"},
14838                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE);
14839            }
14840            elsif($Prefix eq "Return"
14841            and $Type2_Pure{"Name"} eq "void")
14842            {
14843                %{$LocalProblems{"Return_Type_Became_Void"}}=(
14844                    "Old_Value"=>$Type1{"Name"},
14845                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE);
14846            }
14847            else
14848            {
14849                if($Level eq "Binary"
14850                and $Type1{"Size"} and $Type2{"Size"}
14851                and $Type1{"Size"} ne $Type2{"Size"})
14852                {
14853                    %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
14854                        "Old_Value"=>$Type1{"Name"},
14855                        "New_Value"=>$Type2{"Name"},
14856                        "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
14857                        "New_Size"=>$Type2{"Size"}*$BYTE_SIZE);
14858                }
14859                else
14860                {
14861                    if(diffTypes($Type1_Id, $Type2_Id, $Level))
14862                    { # format change
14863                        %{$LocalProblems{$Prefix."_Type_Format"}}=(
14864                            "Old_Value"=>$Type1{"Name"},
14865                            "New_Value"=>$Type2{"Name"},
14866                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
14867                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE);
14868                    }
14869                    elsif(tNameLock($Type1_Id, $Type2_Id))
14870                    { # FIXME: correct this condition
14871                        %{$LocalProblems{$Prefix."_Type"}}=(
14872                            "Old_Value"=>$Type1{"Name"},
14873                            "New_Value"=>$Type2{"Name"},
14874                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
14875                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE);
14876                    }
14877                }
14878            }
14879        }
14880    }
14881    if($Type1_PLevel!=$Type2_PLevel)
14882    {
14883        if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
14884        and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
14885        {
14886            if($Level eq "Source")
14887            {
14888                %{$LocalProblems{$Prefix."_PointerLevel"}}=(
14889                    "Old_Value"=>$Type1_PLevel,
14890                    "New_Value"=>$Type2_PLevel);
14891            }
14892            else
14893            {
14894                if($Type2_PLevel>$Type1_PLevel)
14895                {
14896                    %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
14897                        "Old_Value"=>$Type1_PLevel,
14898                        "New_Value"=>$Type2_PLevel);
14899                }
14900                else
14901                {
14902                    %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
14903                        "Old_Value"=>$Type1_PLevel,
14904                        "New_Value"=>$Type2_PLevel);
14905                }
14906            }
14907        }
14908    }
14909    if($Type1_Pure{"Type"} eq "Array"
14910    and $Type1_Pure{"BaseType"})
14911    { # base_type[N] -> base_type[N]
14912      # base_type: older_structure -> typedef to newer_structure
14913        my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
14914        foreach my $SubProblemType (keys(%SubProblems))
14915        {
14916            $SubProblemType=~s/_Type/_BaseType/g;
14917            next if(defined $LocalProblems{$SubProblemType});
14918            foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
14919                $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
14920            }
14921        }
14922    }
14923    return %LocalProblems;
14924}
14925
14926sub tNameLock($$)
14927{
14928    my ($Tid1, $Tid2) = @_;
14929    my $Changed = 0;
14930    if(differentDumps("G"))
14931    { # different GCC versions
14932        $Changed = 1;
14933    }
14934    elsif(differentDumps("V"))
14935    { # different versions of ABI dumps
14936        if(not checkDump(1, "2.20")
14937        or not checkDump(2, "2.20"))
14938        { # latest names update
14939          # 2.6: added restrict qualifier
14940          # 2.13: added missed typedefs to qualified types
14941          # 2.20: prefix for struct, union and enum types
14942            $Changed = 1;
14943        }
14944    }
14945
14946    my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
14947    my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
14948
14949    if($Changed)
14950    { # different formats
14951        if($UseOldDumps)
14952        { # old dumps
14953            return 0;
14954        }
14955
14956        my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
14957        my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
14958
14959        my %Base1 = get_Type($Tid1, 1);
14960        while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
14961            %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
14962        }
14963        my %Base2 = get_Type($Tid2, 2);
14964        while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
14965            %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
14966        }
14967        my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
14968        my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
14969        if($BName1 eq $BName2)
14970        { # equal base types
14971            return 0;
14972        }
14973
14974        if(not checkDump(1, "2.13")
14975        or not checkDump(2, "2.13"))
14976        { # broken array names in ABI dumps < 2.13
14977            if($TT1 eq "Array"
14978            and $TT2 eq "Array") {
14979                return 0;
14980            }
14981        }
14982
14983        if(not checkDump(1, "2.6")
14984        or not checkDump(2, "2.6"))
14985        { # added restrict attribute in 2.6
14986            if($TN1!~/\brestrict\b/
14987            and $TN2=~/\brestrict\b/) {
14988                return 0;
14989            }
14990        }
14991
14992        if(not checkDump(1, "2.20")
14993        or not checkDump(2, "2.20"))
14994        { # added restrict attribute in 2.6
14995            if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/
14996            or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
14997                return 0;
14998            }
14999        }
15000    }
15001    else
15002    {
15003        # typedef struct {...} type_t
15004        # typedef struct type_t {...} type_t
15005        if(index($TN1, " ".$TN2)!=-1)
15006        {
15007            if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) {
15008                return 0;
15009            }
15010        }
15011        if(index($TN2, " ".$TN1)!=-1)
15012        {
15013            if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
15014                return 0;
15015            }
15016        }
15017    }
15018    return 1;
15019}
15020
15021sub differentDumps($)
15022{
15023    my $Check = $_[0];
15024    if(defined $Cache{"differentDumps"}{$Check}) {
15025        return $Cache{"differentDumps"}{$Check};
15026    }
15027    if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
15028    {
15029        if($Check eq "G")
15030        {
15031            if(getGccVersion(1) ne getGccVersion(2))
15032            { # different GCC versions
15033                return ($Cache{"differentDumps"}{$Check}=1);
15034            }
15035        }
15036        if($Check eq "V")
15037        {
15038            if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
15039            formatVersion($UsedDump{2}{"V"}, 2))!=0)
15040            { # different dump versions (skip micro version)
15041                return ($Cache{"differentDumps"}{$Check}=1);
15042            }
15043        }
15044    }
15045    return ($Cache{"differentDumps"}{$Check}=0);
15046}
15047
15048sub formatVersion($$)
15049{ # cut off version digits
15050    my ($V, $Digits) = @_;
15051    my @Elems = split(/\./, $V);
15052    return join(".", splice(@Elems, 0, $Digits));
15053}
15054
15055sub htmlSpecChars($)
15056{
15057    my $Str = $_[0];
15058    if(not $Str) {
15059        return $Str;
15060    }
15061    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
15062    $Str=~s/</&lt;/g;
15063    $Str=~s/\-\>/&#45;&gt;/g; # &minus;
15064    $Str=~s/>/&gt;/g;
15065    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
15066    $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g;
15067    $Str=~s/ /&#160;/g; # &nbsp;
15068    $Str=~s/\@SP\@/ /g;
15069    $Str=~s/\n/<br\/>/g;
15070    $Str=~s/\"/&quot;/g;
15071    $Str=~s/\'/&#39;/g;
15072    return $Str;
15073}
15074
15075sub xmlSpecChars($)
15076{
15077    my $Str = $_[0];
15078    if(not $Str) {
15079        return $Str;
15080    }
15081
15082    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
15083    $Str=~s/</&lt;/g;
15084    $Str=~s/>/&gt;/g;
15085
15086    $Str=~s/\"/&quot;/g;
15087    $Str=~s/\'/&#39;/g;
15088
15089    return $Str;
15090}
15091
15092sub xmlSpecChars_R($)
15093{
15094    my $Str = $_[0];
15095    if(not $Str) {
15096        return $Str;
15097    }
15098
15099    $Str=~s/&amp;/&/g;
15100    $Str=~s/&lt;/</g;
15101    $Str=~s/&gt;/>/g;
15102
15103    $Str=~s/&quot;/"/g;
15104    $Str=~s/&#39;/'/g;
15105
15106    return $Str;
15107}
15108
15109sub black_name($)
15110{
15111    my $Name = $_[0];
15112    return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
15113}
15114
15115sub highLight_Signature($)
15116{
15117    my $Signature = $_[0];
15118    return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
15119}
15120
15121sub highLight_Signature_Italic_Color($)
15122{
15123    my $Signature = $_[0];
15124    return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
15125}
15126
15127sub separate_symbol($)
15128{
15129    my $Symbol = $_[0];
15130    my ($Name, $Spec, $Ver) = ($Symbol, "", "");
15131    if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
15132        ($Name, $Spec, $Ver) = ($1, $2, $3);
15133    }
15134    return ($Name, $Spec, $Ver);
15135}
15136
15137sub cut_f_attrs($)
15138{
15139    if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
15140        return $2;
15141    }
15142    return "";
15143}
15144
15145sub highLight_Signature_PPos_Italic($$$$$)
15146{
15147    my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
15148    $Param_Pos = "" if(not defined $Param_Pos);
15149    if($CheckObjectsOnly) {
15150        $ItalicParams=$ColorParams=0;
15151    }
15152    my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
15153    my $Return = "";
15154    if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
15155        $Return = $2;
15156    }
15157    my $SCenter = find_center($Signature, "(");
15158    if(not $SCenter)
15159    { # global data
15160        $Signature = htmlSpecChars($Signature);
15161        $Signature=~s!(\[data\])!<span class='attr'>$1</span>!g;
15162        $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
15163        if($Return and $ShowReturn) {
15164            $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
15165        }
15166        return $Signature;
15167    }
15168    my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
15169    $Begin.=" " if($Begin!~/ \Z/);
15170    $End = cut_f_attrs($Signature);
15171    my @Parts = ();
15172    my ($Short, $Params) = split_Signature($Signature);
15173    my @SParts = separate_Params($Params, 1, 1);
15174    foreach my $Pos (0 .. $#SParts)
15175    {
15176        my $Part = $SParts[$Pos];
15177        $Part=~s/\A\s+|\s+\Z//g;
15178        my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
15179        if($Part=~/\([\*]+(\w+)\)/i) {
15180            $ParamName = $1;#func-ptr
15181        }
15182        elsif($Part=~/(\w+)[\,\)]*\Z/i) {
15183            $ParamName = $1;
15184        }
15185        if(not $ParamName)
15186        {
15187            push(@Parts, $Part_Styled);
15188            next;
15189        }
15190        if($ItalicParams and not $TName_Tid{1}{$Part}
15191        and not $TName_Tid{2}{$Part})
15192        {
15193            my $Style = "param";
15194            if($Param_Pos ne ""
15195            and $Pos==$Param_Pos) {
15196                $Style = "focus_p";
15197            }
15198            elsif($ColorParams) {
15199                $Style = "color_p";
15200            }
15201            $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
15202        }
15203        $Part_Styled=~s/,(\w)/, $1/g;
15204        push(@Parts, $Part_Styled);
15205    }
15206    if(@Parts)
15207    {
15208        foreach my $Num (0 .. $#Parts)
15209        {
15210            if($Num==$#Parts)
15211            { # add ")" to the last parameter
15212                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
15213            }
15214            elsif(length($Parts[$Num])<=45) {
15215                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
15216            }
15217        }
15218        $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
15219    }
15220    else {
15221        $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
15222    }
15223    if($Return and $ShowReturn) {
15224        $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
15225    }
15226    $Signature=~s!\[\]![&#160;]!g;
15227    $Signature=~s!operator=!operator&#160;=!g;
15228    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='attr'>$1</span>!g;
15229    if($SymbolVersion) {
15230        $Signature .= "<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>";
15231    }
15232    return $Signature;
15233}
15234
15235sub split_Signature($)
15236{
15237    my $Signature = $_[0];
15238    if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
15239    {
15240        $Signature=~s/\A\Q$ShortName\E\(//g;
15241        cut_f_attrs($Signature);
15242        $Signature=~s/\)\Z//;
15243        return ($ShortName, $Signature);
15244    }
15245
15246    # error
15247    return ($Signature, "");
15248}
15249
15250sub separate_Params($$$)
15251{
15252    my ($Params, $Comma, $Sp) = @_;
15253    my @Parts = ();
15254    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
15255    my $Part = 0;
15256    foreach my $Pos (0 .. length($Params) - 1)
15257    {
15258        my $S = substr($Params, $Pos, 1);
15259        if(defined $B{$S}) {
15260            $B{$S} += 1;
15261        }
15262        if($S eq "," and
15263        $B{"("}==$B{")"} and $B{"<"}==$B{">"})
15264        {
15265            if($Comma)
15266            { # include comma
15267                $Parts[$Part] .= $S;
15268            }
15269            $Part += 1;
15270        }
15271        else {
15272            $Parts[$Part] .= $S;
15273        }
15274    }
15275    if(not $Sp)
15276    { # remove spaces
15277        foreach (@Parts)
15278        {
15279            s/\A //g;
15280            s/ \Z//g;
15281        }
15282    }
15283    return @Parts;
15284}
15285
15286sub find_center($$)
15287{
15288    my ($Sign, $Target) = @_;
15289    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
15290    my $Center = 0;
15291    if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
15292    { # operators
15293        $Center+=length($1);
15294    }
15295    foreach my $Pos (0 .. length($Sign)-1)
15296    {
15297        my $S = substr($Sign, $Pos, 1);
15298        if($S eq $Target)
15299        {
15300            if($B{"("}==$B{")"}
15301            and $B{"<"}==$B{">"}) {
15302                return $Center;
15303            }
15304        }
15305        if(defined $B{$S}) {
15306            $B{$S}+=1;
15307        }
15308        $Center+=1;
15309    }
15310    return 0;
15311}
15312
15313sub appendFile($$)
15314{
15315    my ($Path, $Content) = @_;
15316    return if(not $Path);
15317    if(my $Dir = get_dirname($Path)) {
15318        mkpath($Dir);
15319    }
15320    open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
15321    print FILE $Content;
15322    close(FILE);
15323}
15324
15325sub writeFile($$)
15326{
15327    my ($Path, $Content) = @_;
15328    return if(not $Path);
15329    if(my $Dir = get_dirname($Path)) {
15330        mkpath($Dir);
15331    }
15332    open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
15333    print FILE $Content;
15334    close(FILE);
15335}
15336
15337sub readFile($)
15338{
15339    my $Path = $_[0];
15340    return "" if(not $Path or not -f $Path);
15341    open(FILE, $Path);
15342    local $/ = undef;
15343    my $Content = <FILE>;
15344    close(FILE);
15345    if($Path!~/\.(tu|class|abi)\Z/) {
15346        $Content=~s/\r/\n/g;
15347    }
15348    return $Content;
15349}
15350
15351sub get_filename($)
15352{ # much faster than basename() from File::Basename module
15353    if(defined $Cache{"get_filename"}{$_[0]}) {
15354        return $Cache{"get_filename"}{$_[0]};
15355    }
15356    if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
15357        return ($Cache{"get_filename"}{$_[0]}=$1);
15358    }
15359    return ($Cache{"get_filename"}{$_[0]}="");
15360}
15361
15362sub get_dirname($)
15363{ # much faster than dirname() from File::Basename module
15364    if(defined $Cache{"get_dirname"}{$_[0]}) {
15365        return $Cache{"get_dirname"}{$_[0]};
15366    }
15367    if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
15368        return ($Cache{"get_dirname"}{$_[0]}=$1);
15369    }
15370    return ($Cache{"get_dirname"}{$_[0]}="");
15371}
15372
15373sub separate_path($) {
15374    return (get_dirname($_[0]), get_filename($_[0]));
15375}
15376
15377sub esc($)
15378{
15379    my $Str = $_[0];
15380    $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
15381    return $Str;
15382}
15383
15384sub readLineNum($$)
15385{
15386    my ($Path, $Num) = @_;
15387    return "" if(not $Path or not -f $Path);
15388    open(FILE, $Path);
15389    foreach (1 ... $Num) {
15390        <FILE>;
15391    }
15392    my $Line = <FILE>;
15393    close(FILE);
15394    return $Line;
15395}
15396
15397sub readAttributes($$)
15398{
15399    my ($Path, $Num) = @_;
15400    return () if(not $Path or not -f $Path);
15401    my %Attributes = ();
15402    if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
15403    {
15404        foreach my $AttrVal (split(/;/, $1))
15405        {
15406            if($AttrVal=~/(.+):(.+)/)
15407            {
15408                my ($Name, $Value) = ($1, $2);
15409                $Attributes{$Name} = $Value;
15410            }
15411        }
15412    }
15413    return \%Attributes;
15414}
15415
15416sub is_abs($) {
15417    return ($_[0]=~/\A(\/|\w+:[\/\\])/);
15418}
15419
15420sub get_abs_path($)
15421{ # abs_path() should NOT be called for absolute inputs
15422  # because it can change them
15423    my $Path = $_[0];
15424    if(not is_abs($Path)) {
15425        $Path = abs_path($Path);
15426    }
15427    return $Path;
15428}
15429
15430sub get_OSgroup()
15431{
15432    my $N = $Config{"osname"};
15433    if($N=~/macos|darwin|rhapsody/i) {
15434        return "macos";
15435    }
15436    elsif($N=~/freebsd|openbsd|netbsd/i) {
15437        return "bsd";
15438    }
15439    elsif($N=~/haiku|beos/i) {
15440        return "beos";
15441    }
15442    elsif($N=~/symbian|epoc/i) {
15443        return "symbian";
15444    }
15445    elsif($N=~/win/i) {
15446        return "windows";
15447    }
15448    else {
15449        return $N;
15450    }
15451}
15452
15453sub getGccVersion($)
15454{
15455    my $LibVersion = $_[0];
15456    if($GCC_VERSION{$LibVersion})
15457    { # dump version
15458        return $GCC_VERSION{$LibVersion};
15459    }
15460    elsif($UsedDump{$LibVersion}{"V"})
15461    { # old-version dumps
15462        return "unknown";
15463    }
15464    my $GccVersion = get_dumpversion($GCC_PATH); # host version
15465    if(not $GccVersion) {
15466        return "unknown";
15467    }
15468    return $GccVersion;
15469}
15470
15471sub showArch($)
15472{
15473    my $Arch = $_[0];
15474    if($Arch eq "arm"
15475    or $Arch eq "mips") {
15476        return uc($Arch);
15477    }
15478    return $Arch;
15479}
15480
15481sub getArch($)
15482{
15483    my $LibVersion = $_[0];
15484    if($CPU_ARCH{$LibVersion})
15485    { # dump version
15486        return $CPU_ARCH{$LibVersion};
15487    }
15488    elsif($UsedDump{$LibVersion}{"V"})
15489    { # old-version dumps
15490        return "unknown";
15491    }
15492    if(defined $Cache{"getArch"}{$LibVersion}) {
15493        return $Cache{"getArch"}{$LibVersion};
15494    }
15495    my $Arch = get_dumpmachine($GCC_PATH); # host version
15496    if(not $Arch) {
15497        return "unknown";
15498    }
15499    if($Arch=~/\A([\w]{3,})(-|\Z)/) {
15500        $Arch = $1;
15501    }
15502    $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/i);
15503    $Arch = "x86_64" if($Arch=~/\Aamd64\Z/i);
15504    if($OSgroup eq "windows")
15505    {
15506        $Arch = "x86" if($Arch=~/win32|mingw32/i);
15507        $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
15508    }
15509    $Cache{"getArch"}{$LibVersion} = $Arch;
15510    return $Arch;
15511}
15512
15513sub get_Report_Header($)
15514{
15515    my $Level = $_[0];
15516    my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
15517    if(getArch(1) ne getArch(2)
15518    or getArch(1) eq "unknown"
15519    or $Level eq "Source")
15520    { # don't show architecture in the header
15521        $ArchInfo="";
15522    }
15523    my $Report_Header = "<h1><span class='nowrap'>";
15524    if($Level eq "Source") {
15525        $Report_Header .= "Source compatibility";
15526    }
15527    elsif($Level eq "Binary") {
15528        $Report_Header .= "Binary compatibility";
15529    }
15530    else {
15531        $Report_Header .= "API compatibility";
15532    }
15533    $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
15534    $Report_Header .= " <span class='nowrap'>&#160;between <span style='color:Red;'>".$Descriptor{1}{"Version"}."</span> and <span style='color:Red;'>".$Descriptor{2}{"Version"}."</span> versions$ArchInfo</span>";
15535    if($AppPath) {
15536        $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
15537    }
15538    $Report_Header .= "</h1>\n";
15539    return $Report_Header;
15540}
15541
15542sub get_SourceInfo()
15543{
15544    my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", "");
15545    if(not $CheckObjectsOnly)
15546    {
15547        if(my @Headers = keys(%{$Registered_Headers{1}}))
15548        {
15549            $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".($#Headers+1).")</h2><hr/>\n";
15550            $CheckedHeaders .= "<div class='h_list'>\n";
15551            foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers)
15552            {
15553                my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
15554                my $Name = get_filename($Identity);
15555                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
15556                $CheckedHeaders .= $Name.$Comment."<br/>\n";
15557            }
15558            $CheckedHeaders .= "</div>\n";
15559            $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
15560        }
15561
15562        if(my @Sources = keys(%{$Registered_Sources{1}}))
15563        {
15564            $CheckedSources = "<a name='Sources'></a><h2>Source Files (".($#Sources+1).")</h2><hr/>\n";
15565            $CheckedSources .= "<div class='h_list'>\n";
15566            foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources)
15567            {
15568                my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"};
15569                my $Name = get_filename($Identity);
15570                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
15571                $CheckedSources .= $Name.$Comment."<br/>\n";
15572            }
15573            $CheckedSources .= "</div>\n";
15574            $CheckedSources .= "<br/>$TOP_REF<br/>\n";
15575        }
15576    }
15577    if(not $CheckHeadersOnly)
15578    {
15579        $CheckedLibs = "<a name='Libs'></a><h2>".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
15580        $CheckedLibs .= "<div class='lib_list'>\n";
15581        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
15582        {
15583            $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
15584            $CheckedLibs .= $Library."<br/>\n";
15585        }
15586        $CheckedLibs .= "</div>\n";
15587        $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
15588    }
15589    return $CheckedHeaders.$CheckedSources.$CheckedLibs;
15590}
15591
15592sub get_ObjTitle()
15593{
15594    if(defined $UsedDump{1}{"DWARF"}) {
15595        return "Objects";
15596    }
15597    else {
15598        return ucfirst($SLIB_TYPE)." Libraries";
15599    }
15600}
15601
15602sub get_TypeProblems_Count($$$)
15603{
15604    my ($TypeChanges, $TargetPriority, $Level) = @_;
15605    my $Type_Problems_Count = 0;
15606    foreach my $Type_Name (sort keys(%{$TypeChanges}))
15607    {
15608        my %Kinds_Target = ();
15609        foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
15610        {
15611            foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
15612            {
15613                my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
15614                my $Priority = $CompatRules{$Level}{$Kind}{"Severity"};
15615                next if($Priority ne $TargetPriority);
15616                if($Kinds_Target{$Kind}{$Target}) {
15617                    next;
15618                }
15619                if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
15620                { # select a problem with the highest priority
15621                    next;
15622                }
15623                $Kinds_Target{$Kind}{$Target} = 1;
15624                $Type_Problems_Count += 1;
15625            }
15626        }
15627    }
15628    return $Type_Problems_Count;
15629}
15630
15631sub get_Summary($)
15632{
15633    my $Level = $_[0];
15634    my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
15635    $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);
15636    %{$RESULT{$Level}} = (
15637        "Problems"=>0,
15638        "Warnings"=>0,
15639        "Affected"=>0 );
15640    # check rules
15641    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
15642    {
15643        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
15644        {
15645            if(not defined $CompatRules{$Level}{$Kind})
15646            { # unknown rule
15647                if(not $UnknownRules{$Level}{$Kind})
15648                { # only one warning
15649                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
15650                    $UnknownRules{$Level}{$Kind}=1;
15651                }
15652                delete($CompatProblems{$Level}{$Interface}{$Kind});
15653            }
15654        }
15655    }
15656    foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}}))
15657    {
15658        foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
15659        {
15660            if(not defined $CompatRules{$Level}{$Kind})
15661            { # unknown rule
15662                if(not $UnknownRules{$Level}{$Kind})
15663                { # only one warning
15664                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
15665                    $UnknownRules{$Level}{$Kind}=1;
15666                }
15667                delete($CompatProblems_Constants{$Level}{$Constant}{$Kind});
15668            }
15669        }
15670    }
15671    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
15672    {
15673        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
15674        {
15675            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
15676            {
15677                foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
15678                {
15679                    my $Priority = $CompatRules{$Level}{$Kind}{"Severity"};
15680                    if($Kind eq "Added_Symbol") {
15681                        $Added += 1;
15682                    }
15683                    elsif($Kind eq "Removed_Symbol")
15684                    {
15685                        $Removed += 1;
15686                        $TotalAffected{$Level}{$Interface} = $Priority;
15687                    }
15688                    else
15689                    {
15690                        if($Priority eq "Safe") {
15691                            $I_Other += 1;
15692                        }
15693                        elsif($Priority eq "High") {
15694                            $I_Problems_High += 1;
15695                        }
15696                        elsif($Priority eq "Medium") {
15697                            $I_Problems_Medium += 1;
15698                        }
15699                        elsif($Priority eq "Low") {
15700                            $I_Problems_Low += 1;
15701                        }
15702                        if(($Priority ne "Low" or $StrictCompat)
15703                        and $Priority ne "Safe") {
15704                            $TotalAffected{$Level}{$Interface} = $Priority;
15705                        }
15706                    }
15707                }
15708            }
15709        }
15710    }
15711    my %TypeChanges = ();
15712    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
15713    {
15714        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
15715        {
15716            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15717            {
15718                foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
15719                {
15720                    my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15721                    my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15722                    my $Priority = $CompatRules{$Level}{$Kind}{"Severity"};
15723                    my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target};
15724
15725                    if($MaxSeverity and $Severity_Val{$MaxSeverity}>$Severity_Val{$Priority})
15726                    { # select a problem with the highest priority
15727                        next;
15728                    }
15729
15730                    if(($Priority ne "Low" or $StrictCompat)
15731                    and $Priority ne "Safe")
15732                    {
15733                        if(defined $TotalAffected{$Level}{$Interface})
15734                        {
15735                            if($Severity_Val{$Priority}>$Severity_Val{$TotalAffected{$Level}{$Interface}}) {
15736                                $TotalAffected{$Level}{$Interface} = $Priority;
15737                            }
15738                        }
15739                        else {
15740                            $TotalAffected{$Level}{$Interface} = $Priority;
15741                        }
15742                    }
15743
15744                    $TypeChanges{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location};
15745
15746                    if($MaxSeverity)
15747                    {
15748                        if($Severity_Val{$Priority}>$Severity_Val{$MaxSeverity}) {
15749                            $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Priority;
15750                        }
15751                    }
15752                    else {
15753                        $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Priority;
15754                    }
15755                }
15756            }
15757        }
15758    }
15759
15760    $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
15761    $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
15762    $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
15763    $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
15764
15765    %TypeChanges = (); # free memory
15766
15767    if($CheckObjectsOnly)
15768    { # only removed exported symbols
15769        $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
15770    }
15771    else
15772    { # changed and removed public symbols
15773        my $SCount = keys(%{$CheckedSymbols{$Level}});
15774        if($ExtendedCheck)
15775        { # don't count external_func_0 for constants
15776            $SCount-=1;
15777        }
15778        if($SCount)
15779        {
15780            my %Weight = (
15781                "High" => 100,
15782                "Medium" => 50,
15783                "Low" => 25
15784            );
15785            foreach (keys(%{$TotalAffected{$Level}})) {
15786                $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
15787            }
15788            $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
15789        }
15790        else {
15791            $RESULT{$Level}{"Affected"} = 0;
15792        }
15793    }
15794    $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
15795    if($RESULT{$Level}{"Affected"}>=100) {
15796        $RESULT{$Level}{"Affected"} = 100;
15797    }
15798
15799    $RESULT{$Level}{"Problems"} += $Removed;
15800    $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
15801    $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
15802    if($StrictCompat) {
15803        $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
15804    }
15805    else {
15806        $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
15807    }
15808
15809    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
15810    {
15811        foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
15812        {
15813            my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
15814            if($Severity eq "Safe")
15815            {
15816                $C_Other+=1;
15817            }
15818            elsif($Severity eq "Low")
15819            {
15820                $C_Problems_Low+=1;
15821            }
15822        }
15823    }
15824
15825    if($C_Problems_Low)
15826    {
15827        if($StrictCompat) {
15828            $RESULT{$Level}{"Problems"} += $C_Problems_Low;
15829        }
15830        else {
15831            $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
15832        }
15833    }
15834    if($CheckImpl and $Level eq "Binary")
15835    {
15836        if($StrictCompat) {
15837            $RESULT{$Level}{"Problems"} += keys(%CompatProblems_Impl);
15838        }
15839        else {
15840            $RESULT{$Level}{"Warnings"} += keys(%CompatProblems_Impl);
15841        }
15842    }
15843    if($RESULT{$Level}{"Problems"}
15844    and $RESULT{$Level}{"Affected"}) {
15845        $RESULT{$Level}{"Verdict"} = "incompatible";
15846    }
15847    else {
15848        $RESULT{$Level}{"Verdict"} = "compatible";
15849    }
15850
15851    my $TotalTypes = keys(%{$CheckedTypes{$Level}});
15852    if(not $TotalTypes)
15853    { # list all the types
15854        $TotalTypes = keys(%{$TName_Tid{1}});
15855    }
15856
15857    my ($Arch1, $Arch2) = (getArch(1), getArch(2));
15858    my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
15859
15860    my ($TestInfo, $TestResults, $Problem_Summary) = ();
15861
15862    if($ReportFormat eq "xml")
15863    { # XML
15864        # test info
15865        $TestInfo .= "  <library>$TargetLibraryName</library>\n";
15866        $TestInfo .= "  <version1>\n";
15867        $TestInfo .= "    <number>".$Descriptor{1}{"Version"}."</number>\n";
15868        $TestInfo .= "    <architecture>$Arch1</architecture>\n";
15869        $TestInfo .= "    <gcc>$GccV1</gcc>\n";
15870        $TestInfo .= "  </version1>\n";
15871
15872        $TestInfo .= "  <version2>\n";
15873        $TestInfo .= "    <number>".$Descriptor{2}{"Version"}."</number>\n";
15874        $TestInfo .= "    <architecture>$Arch2</architecture>\n";
15875        $TestInfo .= "    <gcc>$GccV2</gcc>\n";
15876        $TestInfo .= "  </version2>\n";
15877        $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
15878
15879        # test results
15880        if(my @Headers = keys(%{$Registered_Headers{1}}))
15881        {
15882            $TestResults .= "  <headers>\n";
15883            foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers)
15884            {
15885                my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
15886                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
15887                $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
15888            }
15889            $TestResults .= "  </headers>\n";
15890        }
15891
15892        if(my @Sources = keys(%{$Registered_Sources{1}}))
15893        {
15894            $TestResults .= "  <sources>\n";
15895            foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources)
15896            {
15897                my $Identity = $Registered_Sources{1}{$Name}{"Identity"};
15898                my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
15899                $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
15900            }
15901            $TestResults .= "  </sources>\n";
15902        }
15903
15904        $TestResults .= "  <libs>\n";
15905        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
15906        {
15907            $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
15908            $TestResults .= "    <name>$Library</name>\n";
15909        }
15910        $TestResults .= "  </libs>\n";
15911
15912        $TestResults .= "  <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
15913        $TestResults .= "  <types>".$TotalTypes."</types>\n";
15914
15915        $TestResults .= "  <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
15916        $TestResults .= "  <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
15917        $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
15918
15919        # problem summary
15920        $Problem_Summary .= "  <added_symbols>".$Added."</added_symbols>\n";
15921        $Problem_Summary .= "  <removed_symbols>".$Removed."</removed_symbols>\n";
15922
15923        $Problem_Summary .= "  <problems_with_types>\n";
15924        $Problem_Summary .= "    <high>$T_Problems_High</high>\n";
15925        $Problem_Summary .= "    <medium>$T_Problems_Medium</medium>\n";
15926        $Problem_Summary .= "    <low>$T_Problems_Low</low>\n";
15927        $Problem_Summary .= "    <safe>$T_Other</safe>\n";
15928        $Problem_Summary .= "  </problems_with_types>\n";
15929
15930        $Problem_Summary .= "  <problems_with_symbols>\n";
15931        $Problem_Summary .= "    <high>$I_Problems_High</high>\n";
15932        $Problem_Summary .= "    <medium>$I_Problems_Medium</medium>\n";
15933        $Problem_Summary .= "    <low>$I_Problems_Low</low>\n";
15934        $Problem_Summary .= "    <safe>$I_Other</safe>\n";
15935        $Problem_Summary .= "  </problems_with_symbols>\n";
15936
15937        $Problem_Summary .= "  <problems_with_constants>\n";
15938        $Problem_Summary .= "    <low>$C_Problems_Low</low>\n";
15939        $Problem_Summary .= "  </problems_with_constants>\n";
15940        if($CheckImpl and $Level eq "Binary")
15941        {
15942            $Problem_Summary .= "  <impl>\n";
15943            $Problem_Summary .= "    <low>".keys(%CompatProblems_Impl)."</low>\n";
15944            $Problem_Summary .= "  </impl>\n";
15945        }
15946        $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
15947
15948        return ($TestInfo.$TestResults.$Problem_Summary, "");
15949    }
15950    else
15951    { # HTML
15952        # test info
15953        $TestInfo = "<h2>Test Info</h2><hr/>\n";
15954        $TestInfo .= "<table class='summary'>\n";
15955        $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
15956
15957        my (@VInf1, @VInf2, $AddTestInfo) = ();
15958        if($Arch1 ne "unknown"
15959        and $Arch2 ne "unknown")
15960        { # CPU arch
15961            if($Arch1 eq $Arch2)
15962            { # go to the separate section
15963                $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
15964            }
15965            else
15966            { # go to the version number
15967                push(@VInf1, showArch($Arch1));
15968                push(@VInf2, showArch($Arch2));
15969            }
15970        }
15971        if($GccV1 ne "unknown"
15972        and $GccV2 ne "unknown"
15973        and $OStarget ne "windows")
15974        { # GCC version
15975            if($GccV1 eq $GccV2)
15976            { # go to the separate section
15977                $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
15978            }
15979            else
15980            { # go to the version number
15981                push(@VInf1, "gcc ".$GccV1);
15982                push(@VInf2, "gcc ".$GccV2);
15983            }
15984        }
15985        # show long version names with GCC version and CPU architecture name (if different)
15986        $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
15987        $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
15988        $TestInfo .= $AddTestInfo;
15989        #if($COMMON_LANGUAGE{1}) {
15990        #    $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
15991        #}
15992        if($ExtendedCheck) {
15993            $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
15994        }
15995        if($JoinReport)
15996        {
15997            if($Level eq "Binary") {
15998                $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
15999            }
16000            if($Level eq "Source") {
16001                $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
16002            }
16003        }
16004        $TestInfo .= "</table>\n";
16005
16006        # test results
16007        $TestResults = "<h2>Test Results</h2><hr/>\n";
16008        $TestResults .= "<table class='summary'>";
16009
16010        if(my @Headers = keys(%{$Registered_Headers{1}}))
16011        {
16012            my $Headers_Link = "<a href='#Headers' style='color:Blue;'>".($#Headers + 1)."</a>";
16013            $TestResults .= "<tr><th>Total Header Files</th><td>".$Headers_Link."</td></tr>\n";
16014        }
16015        elsif($CheckObjectsOnly) {
16016            $TestResults .= "<tr><th>Total Header Files</th><td>0&#160;(not&#160;analyzed)</td></tr>\n";
16017        }
16018
16019        if(my @Sources = keys(%{$Registered_Sources{1}}))
16020        {
16021            my $Src_Link = "<a href='#Sources' style='color:Blue;'>".($#Sources + 1)."</a>";
16022            $TestResults .= "<tr><th>Total Source Files</th><td>".$Src_Link."</td></tr>\n";
16023        }
16024
16025        if(not $ExtendedCheck)
16026        {
16027            my $Libs_Link = "0";
16028            $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
16029            $TestResults .= "<tr><th>Total ".get_ObjTitle()."</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
16030        }
16031
16032        $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
16033
16034        my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
16035        if($JoinReport) {
16036            $META_DATA = "kind:".lc($Level).";".$META_DATA;
16037        }
16038        $TestResults .= "<tr><th>Verdict</th>";
16039        if($RESULT{$Level}{"Verdict"} eq "incompatible") {
16040            $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
16041        }
16042        else {
16043            $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
16044        }
16045        $TestResults .= "</tr>\n";
16046        $TestResults .= "</table>\n";
16047
16048        $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
16049        # problem summary
16050        $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
16051        $Problem_Summary .= "<table class='summary'>";
16052        $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
16053
16054        my $Added_Link = "0";
16055        if($Added>0)
16056        {
16057            if($JoinReport) {
16058                $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
16059            }
16060            else {
16061                $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
16062            }
16063        }
16064        $META_DATA .= "added:$Added;";
16065        $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n";
16066
16067        my $Removed_Link = "0";
16068        if($Removed>0)
16069        {
16070            if($JoinReport) {
16071                $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
16072            }
16073            else {
16074                $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
16075            }
16076        }
16077        $META_DATA .= "removed:$Removed;";
16078        $Problem_Summary .= "<tr><th>Removed Symbols</th>";
16079        $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
16080
16081        my $TH_Link = "0";
16082        $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0);
16083        $TH_Link = "n/a" if($CheckObjectsOnly);
16084        $META_DATA .= "type_problems_high:$T_Problems_High;";
16085        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
16086        $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
16087
16088        my $TM_Link = "0";
16089        $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0);
16090        $TM_Link = "n/a" if($CheckObjectsOnly);
16091        $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
16092        $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n";
16093
16094        my $TL_Link = "0";
16095        $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0);
16096        $TL_Link = "n/a" if($CheckObjectsOnly);
16097        $META_DATA .= "type_problems_low:$T_Problems_Low;";
16098        $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n";
16099
16100        my $IH_Link = "0";
16101        $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0);
16102        $IH_Link = "n/a" if($CheckObjectsOnly);
16103        $META_DATA .= "interface_problems_high:$I_Problems_High;";
16104        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
16105        $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
16106
16107        my $IM_Link = "0";
16108        $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0);
16109        $IM_Link = "n/a" if($CheckObjectsOnly);
16110        $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
16111        $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n";
16112
16113        my $IL_Link = "0";
16114        $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0);
16115        $IL_Link = "n/a" if($CheckObjectsOnly);
16116        $META_DATA .= "interface_problems_low:$I_Problems_Low;";
16117        $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
16118
16119        my $ChangedConstants_Link = "0";
16120        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) {
16121            $ChangedConstants_Link = "<a href='#".get_Anchor("Constant", $Level, "Low")."' style='color:Blue;'>$C_Problems_Low</a>";
16122        }
16123        $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
16124        $META_DATA .= "changed_constants:$C_Problems_Low;";
16125        $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n";
16126
16127        if($CheckImpl and $Level eq "Binary")
16128        {
16129            my $ChangedImpl_Link = "0";
16130            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%CompatProblems_Impl)."</a>" if(keys(%CompatProblems_Impl)>0);
16131            $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
16132            $META_DATA .= "changed_implementation:".keys(%CompatProblems_Impl).";";
16133            $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";
16134        }
16135        # Safe Changes
16136        if($T_Other and not $CheckObjectsOnly)
16137        {
16138            my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
16139            $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n";
16140        }
16141
16142        if($I_Other and not $CheckObjectsOnly)
16143        {
16144            my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
16145            $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
16146        }
16147
16148        if($C_Other and not $CheckObjectsOnly)
16149        {
16150            my $CS_Link = "<a href='#".get_Anchor("Constant", $Level, "Safe")."' style='color:Blue;'>$C_Other</a>";
16151            $Problem_Summary .= "<tr><th>Other Changes<br/>in Constants</th><td>-</td><td".getStyle("C", "S", $C_Other).">$CS_Link</td></tr>\n";
16152        }
16153
16154        $META_DATA .= "tool_version:$TOOL_VERSION";
16155        $Problem_Summary .= "</table>\n";
16156        # $TestInfo = getLegend().$TestInfo;
16157        return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
16158    }
16159}
16160
16161sub getStyle($$$)
16162{
16163    my ($Subj, $Act, $Num) = @_;
16164    my %Style = (
16165        "A"=>"new",
16166        "R"=>"failed",
16167        "S"=>"passed",
16168        "L"=>"warning",
16169        "M"=>"failed",
16170        "H"=>"failed"
16171    );
16172    if($Num>0) {
16173        return " class='".$Style{$Act}."'";
16174    }
16175    return "";
16176}
16177
16178sub show_number($)
16179{
16180    if($_[0])
16181    {
16182        my $Num = cut_off_number($_[0], 2, 0);
16183        if($Num eq "0")
16184        {
16185            foreach my $P (3 .. 7)
16186            {
16187                $Num = cut_off_number($_[0], $P, 1);
16188                if($Num ne "0") {
16189                    last;
16190                }
16191            }
16192        }
16193        if($Num eq "0") {
16194            $Num = $_[0];
16195        }
16196        return $Num;
16197    }
16198    return $_[0];
16199}
16200
16201sub cut_off_number($$$)
16202{
16203    my ($num, $digs_to_cut, $z) = @_;
16204    if($num!~/\./)
16205    {
16206        $num .= ".";
16207        foreach (1 .. $digs_to_cut-1) {
16208            $num .= "0";
16209        }
16210    }
16211    elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
16212    {
16213        foreach (1 .. $digs_to_cut - 1 - length($1)) {
16214            $num .= "0";
16215        }
16216    }
16217    elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
16218      $num=sprintf("%.".($digs_to_cut-1)."f", $num);
16219    }
16220    $num=~s/\.[0]+\Z//g;
16221    if($z) {
16222        $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
16223    }
16224    return $num;
16225}
16226
16227sub get_Report_ChangedConstants($$)
16228{
16229    my ($TargetSeverity, $Level) = @_;
16230    my $CHANGED_CONSTANTS = "";
16231
16232    my %ReportMap = ();
16233    foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}}))
16234    {
16235        my $Header = $Constants{1}{$Constant}{"Header"};
16236        if(not $Header)
16237        { # added
16238            $Header = $Constants{2}{$Constant}{"Header"}
16239        }
16240
16241        foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}}))
16242        {
16243            if(not defined $CompatRules{$Level}{$Kind}) {
16244                next;
16245            }
16246            if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) {
16247                next;
16248            }
16249            $ReportMap{$Header}{$Constant}{$Kind} = 1;
16250        }
16251    }
16252
16253    if($ReportFormat eq "xml")
16254    { # XML
16255        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16256        {
16257            $CHANGED_CONSTANTS .= "  <header name=\"$HeaderName\">\n";
16258            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16259            {
16260                $CHANGED_CONSTANTS .= "    <constant name=\"$Constant\">\n";
16261                foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
16262                {
16263                    my $Change = $CompatRules{$Level}{$Kind}{"Change"};
16264                    my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
16265                    my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
16266
16267                    $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
16268                    $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n";
16269                    $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n";
16270                    $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n";
16271                    $CHANGED_CONSTANTS .= "      </problem>\n";
16272                }
16273                $CHANGED_CONSTANTS .= "    </constant>\n";
16274            }
16275            $CHANGED_CONSTANTS .= "    </header>\n";
16276        }
16277        $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
16278    }
16279    else
16280    { # HTML
16281        my $Number = 0;
16282        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16283        {
16284            $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
16285            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16286            {
16287                my $Report = "";
16288
16289                foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}}))
16290                {
16291                    my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind});
16292                    my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
16293                    $Report .= "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
16294                    $Number += 1;
16295                }
16296                if($Report)
16297                {
16298                    $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
16299                    $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Constant.$ContentSpanEnd."<br/>\n".$Report;
16300                    $Report = insertIDs($Report);
16301                }
16302                $CHANGED_CONSTANTS .= $Report;
16303            }
16304            $CHANGED_CONSTANTS .= "<br/>\n";
16305        }
16306        if($CHANGED_CONSTANTS)
16307        {
16308            my $Title = "Problems with Constants, $TargetSeverity Severity";
16309            if($TargetSeverity eq "Safe")
16310            { # Safe Changes
16311                $Title = "Other Changes in Constants";
16312            }
16313            $CHANGED_CONSTANTS = "<a name='".get_Anchor("Constant", $Level, $TargetSeverity)."'></a><h2>$Title ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
16314        }
16315    }
16316    return $CHANGED_CONSTANTS;
16317}
16318
16319sub get_Report_Impl()
16320{
16321    my $CHANGED_IMPLEMENTATION = "";
16322    my %ReportMap = ();
16323    foreach my $Interface (sort keys(%CompatProblems_Impl))
16324    {
16325        my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
16326        my $DyLib = $Symbol_Library{1}{$Interface};
16327        $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
16328    }
16329    my $Changed_Number = 0;
16330    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16331    {
16332        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16333        {
16334            my %NameSpaceSymbols = ();
16335            foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16336                $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1;
16337            }
16338            foreach my $NameSpace (sort keys(%NameSpaceSymbols))
16339            {
16340                $CHANGED_IMPLEMENTATION .= getTitle($HeaderName, $DyLib, $NameSpace);
16341                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
16342                foreach my $Interface (@SortedInterfaces)
16343                {
16344                    $Changed_Number += 1;
16345                    my $Signature = get_Signature($Interface, 1);
16346                    if($NameSpace) {
16347                        $Signature=~s/\b\Q$NameSpace\E::\b//g;
16348                    }
16349                    $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";
16350                }
16351                $CHANGED_IMPLEMENTATION .= "<br/>\n";
16352            }
16353        }
16354    }
16355    if($CHANGED_IMPLEMENTATION)
16356    {
16357        $CHANGED_IMPLEMENTATION = insertIDs($CHANGED_IMPLEMENTATION);
16358        $CHANGED_IMPLEMENTATION = "<a name='Changed_Implementation'></a><h2>Problems with Implementation ($Changed_Number)</h2><hr/>\n".$CHANGED_IMPLEMENTATION.$TOP_REF."<br/>\n";
16359    }
16360
16361    # clean memory
16362    %CompatProblems_Impl = ();
16363
16364    return $CHANGED_IMPLEMENTATION;
16365}
16366
16367sub getTitle($$$)
16368{
16369    my ($Header, $Library, $NameSpace) = @_;
16370    my $Title = "";
16371    if($Library and $Library!~/\.\w+\Z/) {
16372        $Library .= " (.$LIB_EXT)";
16373    }
16374    if($Header and $Library)
16375    {
16376        $Title .= "<span class='h_name'>$Header</span>";
16377        $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
16378    }
16379    elsif($Library) {
16380        $Title .= "<span class='lib_name'>$Library</span><br/>\n";
16381    }
16382    elsif($Header) {
16383        $Title .= "<span class='h_name'>$Header</span><br/>\n";
16384    }
16385    if($NameSpace) {
16386        $Title .= "<span class='ns'>namespace <b>$NameSpace</b></span><br/>\n";
16387    }
16388    return $Title;
16389}
16390
16391sub get_Report_Added($)
16392{
16393    my $Level = $_[0];
16394    my $ADDED_INTERFACES = "";
16395    my %ReportMap = ();
16396    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
16397    {
16398        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
16399        {
16400            if($Kind eq "Added_Symbol")
16401            {
16402                my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
16403                my $DyLib = $Symbol_Library{2}{$Interface};
16404                if($Level eq "Source" and $ReportFormat eq "html")
16405                { # do not show library name in HTML report
16406                    $DyLib = "";
16407                }
16408                $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
16409            }
16410        }
16411    }
16412    if($ReportFormat eq "xml")
16413    { # XML
16414        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16415        {
16416            $ADDED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
16417            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16418            {
16419                $ADDED_INTERFACES .= "    <library name=\"$DyLib\">\n";
16420                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16421                    $ADDED_INTERFACES .= "      <name>$Interface</name>\n";
16422                }
16423                $ADDED_INTERFACES .= "    </library>\n";
16424            }
16425            $ADDED_INTERFACES .= "  </header>\n";
16426        }
16427        $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
16428    }
16429    else
16430    { # HTML
16431        my $Added_Number = 0;
16432        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16433        {
16434            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16435            {
16436                my %NameSpaceSymbols = ();
16437                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16438                    $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1;
16439                }
16440                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
16441                {
16442                    $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
16443                    my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
16444                    foreach my $Interface (@SortedInterfaces)
16445                    {
16446                        $Added_Number += 1;
16447                        my $Signature = get_Signature($Interface, 2);
16448                        if($NameSpace) {
16449                            $Signature=~s/\b\Q$NameSpace\E::\b//g;
16450                        }
16451                        if($Interface=~/\A(_Z|\?)/)
16452                        {
16453                            if($Signature) {
16454                                $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");
16455                            }
16456                            else {
16457                                $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
16458                            }
16459                        }
16460                        else
16461                        {
16462                            if($Signature) {
16463                                $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
16464                            }
16465                            else {
16466                                $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
16467                            }
16468                        }
16469                    }
16470                    $ADDED_INTERFACES .= "<br/>\n";
16471                }
16472            }
16473        }
16474        if($ADDED_INTERFACES)
16475        {
16476            my $Anchor = "<a name='Added'></a>";
16477            if($JoinReport) {
16478                $Anchor = "<a name='".$Level."_Added'></a>";
16479            }
16480            $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
16481        }
16482    }
16483    return $ADDED_INTERFACES;
16484}
16485
16486sub get_Report_Removed($)
16487{
16488    my $Level = $_[0];
16489    my $REMOVED_INTERFACES = "";
16490    my %ReportMap = ();
16491    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
16492    {
16493        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
16494        {
16495            if($Kind eq "Removed_Symbol")
16496            {
16497                my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
16498                my $DyLib = $Symbol_Library{1}{$Symbol};
16499                if($Level eq "Source" and $ReportFormat eq "html")
16500                { # do not show library name in HTML report
16501                    $DyLib = "";
16502                }
16503                $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
16504            }
16505        }
16506    }
16507    if($ReportFormat eq "xml")
16508    { # XML
16509        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16510        {
16511            $REMOVED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
16512            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16513            {
16514                $REMOVED_INTERFACES .= "    <library name=\"$DyLib\">\n";
16515                foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16516                    $REMOVED_INTERFACES .= "      <name>$Symbol</name>\n";
16517                }
16518                $REMOVED_INTERFACES .= "    </library>\n";
16519            }
16520            $REMOVED_INTERFACES .= "  </header>\n";
16521        }
16522        $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
16523    }
16524    else
16525    { # HTML
16526        my $Removed_Number = 0;
16527        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16528        {
16529            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16530            {
16531                my %NameSpaceSymbols = ();
16532                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16533                    $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1;
16534                }
16535                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
16536                {
16537                    $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
16538                    my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
16539                    foreach my $Symbol (@SortedInterfaces)
16540                    {
16541                        $Removed_Number += 1;
16542                        my $SubReport = "";
16543                        my $Signature = get_Signature($Symbol, 1);
16544                        if($NameSpace) {
16545                            $Signature=~s/\b\Q$NameSpace\E::\b//g;
16546                        }
16547                        if($Symbol=~/\A(_Z|\?)/)
16548                        {
16549                            if($Signature) {
16550                                $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
16551                            }
16552                            else {
16553                                $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
16554                            }
16555                        }
16556                        else
16557                        {
16558                            if($Signature) {
16559                                $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
16560                            }
16561                            else {
16562                                $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
16563                            }
16564                        }
16565                    }
16566                }
16567                $REMOVED_INTERFACES .= "<br/>\n";
16568            }
16569        }
16570        if($REMOVED_INTERFACES)
16571        {
16572            my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
16573            if($JoinReport) {
16574                $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
16575            }
16576            $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
16577        }
16578    }
16579    return $REMOVED_INTERFACES;
16580}
16581
16582sub getXmlParams($$)
16583{
16584    my ($Content, $Problem) = @_;
16585    return "" if(not $Content or not $Problem);
16586    my %XMLparams = ();
16587    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
16588    {
16589        my $Macro = "\@".lc($Attr);
16590        if($Content=~/\Q$Macro\E/) {
16591            $XMLparams{lc($Attr)} = $Problem->{$Attr};
16592        }
16593    }
16594    my @PString = ();
16595    foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
16596        push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
16597    }
16598    if(@PString) {
16599        return " ".join(" ", @PString);
16600    }
16601    else {
16602        return "";
16603    }
16604}
16605
16606sub addMarkup($)
16607{
16608    my $Content = $_[0];
16609    # auto-markup
16610    $Content=~s/\n[ ]*//; # spaces
16611    $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
16612    $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
16613    $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
16614    $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
16615    if($Content=~/\ANOTE:/)
16616    { # notes
16617        $Content=~s!(NOTE):!<b>$1</b>:!g;
16618    }
16619    else {
16620        $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
16621    }
16622    $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
16623    my @Keywords = (
16624        "void",
16625        "const",
16626        "static",
16627        "restrict",
16628        "volatile",
16629        "register",
16630        "virtual"
16631    );
16632    my $MKeys = join("|", @Keywords);
16633    foreach (@Keywords) {
16634        $MKeys .= "|non-".$_;
16635    }
16636    $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
16637
16638    # Markdown
16639    $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
16640    $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
16641    return $Content;
16642}
16643
16644sub applyMacroses($$$$)
16645{
16646    my ($Level, $Kind, $Content, $Problem) = @_;
16647    return "" if(not $Content or not $Problem);
16648    $Problem->{"Word_Size"} = $WORD_SIZE{2};
16649    $Content = addMarkup($Content);
16650    # macros
16651    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
16652    {
16653        my $Macro = "\@".lc($Attr);
16654        my $Value = $Problem->{$Attr};
16655        if(not defined $Value
16656        or $Value eq "") {
16657            next;
16658        }
16659        if($Value=~/\s\(/ and $Value!~/['"]/)
16660        { # functions
16661            $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
16662            $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
16663            $Value = black_name($Value);
16664        }
16665        elsif($Value=~/\s/) {
16666            $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
16667        }
16668        elsif($Value=~/\A\d+\Z/
16669        and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
16670        { # bits to bytes
16671            if($Value % $BYTE_SIZE)
16672            { # bits
16673                if($Value==1) {
16674                    $Value = "<b>".$Value."</b> bit";
16675                }
16676                else {
16677                    $Value = "<b>".$Value."</b> bits";
16678                }
16679            }
16680            else
16681            { # bytes
16682                $Value /= $BYTE_SIZE;
16683                if($Value==1) {
16684                    $Value = "<b>".$Value."</b> byte";
16685                }
16686                else {
16687                    $Value = "<b>".$Value."</b> bytes";
16688                }
16689            }
16690        }
16691        else
16692        {
16693            $Value = "<b>".htmlSpecChars($Value)."</b>";
16694        }
16695        $Content=~s/\Q$Macro\E/$Value/g;
16696    }
16697
16698    if($Content=~/(\A|[^\@\w])\@\w/)
16699    {
16700        if(not $IncompleteRules{$Level}{$Kind})
16701        { # only one warning
16702            printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
16703            $IncompleteRules{$Level}{$Kind} = 1;
16704        }
16705    }
16706    return $Content;
16707}
16708
16709sub get_Report_SymbolProblems($$)
16710{
16711    my ($TargetSeverity, $Level) = @_;
16712    my $INTERFACE_PROBLEMS = "";
16713    my (%ReportMap, %SymbolChanges) = ();
16714    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
16715    {
16716        my ($SN, $SS, $SV) = separate_symbol($Symbol);
16717        if($SV and defined $CompatProblems{$Level}{$SN}) {
16718            next;
16719        }
16720        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
16721        {
16722            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
16723            and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
16724            {
16725                my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
16726                my $DyLib = $Symbol_Library{1}{$Symbol};
16727                if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
16728                { # Symbol with Version
16729                    $DyLib = $Symbol_Library{1}{$VSym};
16730                }
16731                if(not $DyLib)
16732                { # const global data
16733                    $DyLib = "";
16734                }
16735                if($Level eq "Source" and $ReportFormat eq "html")
16736                { # do not show library name in HTML report
16737                    $DyLib = "";
16738                }
16739                %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
16740                foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
16741                {
16742                    my $Priority = $CompatRules{$Level}{$Kind}{"Severity"};
16743                    if($Priority ne $TargetSeverity) {
16744                        delete($SymbolChanges{$Symbol}{$Kind}{$Location});
16745                    }
16746                }
16747                if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
16748                {
16749                    delete($SymbolChanges{$Symbol}{$Kind});
16750                    next;
16751                }
16752                $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
16753            }
16754        }
16755        if(not keys(%{$SymbolChanges{$Symbol}})) {
16756            delete($SymbolChanges{$Symbol});
16757        }
16758    }
16759    if($ReportFormat eq "xml")
16760    { # XML
16761        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16762        {
16763            $INTERFACE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
16764            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16765            {
16766                $INTERFACE_PROBLEMS .= "    <library name=\"$DyLib\">\n";
16767                foreach my $Symbol (sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%SymbolChanges))
16768                {
16769                    $INTERFACE_PROBLEMS .= "      <symbol name=\"$Symbol\">\n";
16770                    foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
16771                    {
16772                        foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
16773                        {
16774                            my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
16775                            $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
16776
16777                            $INTERFACE_PROBLEMS .= "        <problem id=\"$Kind\">\n";
16778                            my $Change = $CompatRules{$Level}{$Kind}{"Change"};
16779                            $INTERFACE_PROBLEMS .= "          <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
16780                            my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
16781                            $INTERFACE_PROBLEMS .= "          <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
16782                            my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
16783                            $INTERFACE_PROBLEMS .= "          <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
16784                            $INTERFACE_PROBLEMS .= "        </problem>\n";
16785                        }
16786                    }
16787                    $INTERFACE_PROBLEMS .= "      </symbol>\n";
16788                }
16789                $INTERFACE_PROBLEMS .= "    </library>\n";
16790            }
16791            $INTERFACE_PROBLEMS .= "  </header>\n";
16792        }
16793        $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
16794    }
16795    else
16796    { # HTML
16797        my $ProblemsNum = 0;
16798        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16799        {
16800            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
16801            {
16802                my (%NameSpaceSymbols, %NewSignature) = ();
16803                foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
16804                    $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1;
16805                }
16806                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
16807                {
16808                    $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
16809                    my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$NameSpaceSymbols{$NameSpace}});
16810                    foreach my $Symbol (@SortedInterfaces)
16811                    {
16812                        my $Signature = get_Signature($Symbol, 1);
16813                        my $SYMBOL_REPORT = "";
16814                        my $ProblemNum = 1;
16815                        foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
16816                        {
16817                            foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
16818                            {
16819                                my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
16820                                $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
16821                                if($Problem{"New_Signature"}) {
16822                                    $NewSignature{$Symbol} = $Problem{"New_Signature"};
16823                                }
16824                                if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
16825                                {
16826                                    my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
16827                                    $SYMBOL_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>".$Effect."</td></tr>\n";
16828                                    $ProblemNum += 1;
16829                                    $ProblemsNum += 1;
16830                                }
16831                            }
16832                        }
16833                        $ProblemNum -= 1;
16834                        if($SYMBOL_REPORT)
16835                        {
16836                            $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
16837                            if($Signature) {
16838                                $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
16839                            }
16840                            else {
16841                                $INTERFACE_PROBLEMS .= $Symbol;
16842                            }
16843                            $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
16844                            $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
16845                            if($NewSignature{$Symbol})
16846                            { # argument list changed to
16847                                $INTERFACE_PROBLEMS .= "\n<span class='new_sign_lbl'>changed to:</span><br/><span class='new_sign'>".highLight_Signature_Italic_Color($NewSignature{$Symbol})."</span><br/>\n";
16848                            }
16849                            if($Symbol=~/\A(_Z|\?)/) {
16850                                $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
16851                            }
16852                            $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
16853                            $INTERFACE_PROBLEMS .= $ContentDivEnd;
16854                            if($NameSpace) {
16855                                $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
16856                            }
16857                        }
16858                    }
16859                    $INTERFACE_PROBLEMS .= "<br/>";
16860                }
16861            }
16862        }
16863        if($INTERFACE_PROBLEMS)
16864        {
16865            $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
16866            my $Title = "Problems with Symbols, $TargetSeverity Severity";
16867            if($TargetSeverity eq "Safe")
16868            { # Safe Changes
16869                $Title = "Other Changes in Symbols";
16870            }
16871            $INTERFACE_PROBLEMS = "<a name=\'".get_Anchor("Symbol", $Level, $TargetSeverity)."\'></a><a name=\'".get_Anchor("Interface", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$INTERFACE_PROBLEMS.$TOP_REF."<br/>\n";
16872        }
16873    }
16874    return $INTERFACE_PROBLEMS;
16875}
16876
16877sub get_Report_TypeProblems($$)
16878{
16879    my ($TargetSeverity, $Level) = @_;
16880    my $TYPE_PROBLEMS = "";
16881    my (%ReportMap, %TypeChanges) = ();
16882    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
16883    {
16884        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
16885        {
16886            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
16887            {
16888                foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
16889                {
16890                    my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
16891                    my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
16892                    my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
16893                    if($Severity eq "Safe"
16894                    and $TargetSeverity ne "Safe") {
16895                        next;
16896                    }
16897
16898                    if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
16899                    { # select a problem with the highest priority
16900                        next;
16901                    }
16902                    %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
16903                }
16904            }
16905        }
16906    }
16907    my %Kinds_Locations = ();
16908    foreach my $TypeName (keys(%TypeChanges))
16909    {
16910        my %Kinds_Target = ();
16911        foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
16912        {
16913            foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
16914            {
16915                my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
16916                if($Severity ne $TargetSeverity)
16917                { # other priority
16918                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
16919                    next;
16920                }
16921                $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
16922                my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
16923                if($Kinds_Target{$Kind}{$Target})
16924                { # duplicate target
16925                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
16926                    next;
16927                }
16928                $Kinds_Target{$Kind}{$Target} = 1;
16929                my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
16930                $ReportMap{$HeaderName}{$TypeName} = 1;
16931            }
16932            if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
16933                delete($TypeChanges{$TypeName}{$Kind});
16934            }
16935        }
16936        if(not keys(%{$TypeChanges{$TypeName}})) {
16937            delete($TypeChanges{$TypeName});
16938        }
16939    }
16940    my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}});
16941    if($ReportFormat eq "xml")
16942    { # XML
16943        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16944        {
16945            $TYPE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
16946            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
16947            {
16948                $TYPE_PROBLEMS .= "    <type name=\"".xmlSpecChars($TypeName)."\">\n";
16949                foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
16950                {
16951                    foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
16952                    {
16953                        my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
16954                        $TYPE_PROBLEMS .= "      <problem id=\"$Kind\">\n";
16955                        my $Change = $CompatRules{$Level}{$Kind}{"Change"};
16956                        $TYPE_PROBLEMS .= "        <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
16957                        my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
16958                        $TYPE_PROBLEMS .= "        <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
16959                        my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
16960                        $TYPE_PROBLEMS .= "        <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
16961                        $TYPE_PROBLEMS .= "      </problem>\n";
16962                    }
16963                }
16964                $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
16965                if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
16966                    $TYPE_PROBLEMS .= showVTables($TypeName);
16967                }
16968                $TYPE_PROBLEMS .= "    </type>\n";
16969            }
16970            $TYPE_PROBLEMS .= "  </header>\n";
16971        }
16972        $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
16973    }
16974    else
16975    { # HTML
16976        my $ProblemsNum = 0;
16977        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
16978        {
16979            my (%NameSpace_Type) = ();
16980            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
16981                $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1;
16982            }
16983            foreach my $NameSpace (sort keys(%NameSpace_Type))
16984            {
16985                $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
16986                my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}});
16987                foreach my $TypeName (@SortedTypes)
16988                {
16989                    my $ProblemNum = 1;
16990                    my $TYPE_REPORT = "";
16991                    foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
16992                    {
16993                        foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
16994                        {
16995                            my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
16996                            if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
16997                            {
16998                                my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
16999                                $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
17000                                $ProblemNum += 1;
17001                                $ProblemsNum += 1;
17002                            }
17003                        }
17004                    }
17005                    $ProblemNum -= 1;
17006                    if($TYPE_REPORT)
17007                    {
17008                        my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
17009                        my $ShowVTables = "";
17010                        if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
17011                            $ShowVTables = showVTables($TypeName);
17012                        }
17013
17014                        $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ".show_Type($TypeName, 1, 1)." ($ProblemNum)".$ContentSpanEnd;
17015                        $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
17016                        $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
17017                        $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
17018                        $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
17019                        if($NameSpace) {
17020                            $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
17021                        }
17022                    }
17023                }
17024                $TYPE_PROBLEMS .= "<br/>";
17025            }
17026        }
17027        if($TYPE_PROBLEMS)
17028        {
17029            $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
17030            my $Title = "Problems with Data Types, $TargetSeverity Severity";
17031            if($TargetSeverity eq "Safe")
17032            { # Safe Changes
17033                $Title = "Other Changes in Data Types";
17034            }
17035            $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n";
17036        }
17037    }
17038    return $TYPE_PROBLEMS;
17039}
17040
17041sub show_Type($$$)
17042{
17043    my ($Name, $Html, $LibVersion) = @_;
17044    my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"};
17045    $TType = lc($TType);
17046    if($TType=~/struct|union|enum/) {
17047        $Name=~s/\A\Q$TType\E //g;
17048    }
17049    if($Html) {
17050        $Name = "<span class='ttype'>".$TType."</span> ".htmlSpecChars($Name);
17051    }
17052    else {
17053        $Name = $TType." ".$Name;
17054    }
17055    return $Name;
17056}
17057
17058sub get_Anchor($$$)
17059{
17060    my ($Kind, $Level, $Severity) = @_;
17061    if($JoinReport)
17062    {
17063        if($Severity eq "Safe") {
17064            return "Other_".$Level."_Changes_In_".$Kind."s";
17065        }
17066        else {
17067            return $Kind."_".$Level."_Problems_".$Severity;
17068        }
17069    }
17070    else
17071    {
17072        if($Severity eq "Safe") {
17073            return "Other_Changes_In_".$Kind."s";
17074        }
17075        else {
17076            return $Kind."_Problems_".$Severity;
17077        }
17078    }
17079}
17080
17081sub showVTables($)
17082{
17083    my $TypeName = $_[0];
17084    my $TypeId1 = $TName_Tid{1}{$TypeName};
17085    my %Type1 = get_Type($TypeId1, 1);
17086    if(defined $Type1{"VTable"}
17087    and keys(%{$Type1{"VTable"}}))
17088    {
17089        my $TypeId2 = $TName_Tid{2}{$TypeName};
17090        my %Type2 = get_Type($TypeId2, 2);
17091        if(defined $Type2{"VTable"}
17092        and keys(%{$Type2{"VTable"}}))
17093        {
17094            my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
17095            my %Entries = ();
17096            foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
17097            {
17098                $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
17099                $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
17100            }
17101            my $VTABLES = "";
17102            if($ReportFormat eq "xml")
17103            { # XML
17104                $VTABLES .= "      <vtable>\n";
17105                foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
17106                {
17107                    $VTABLES .= "        <entry offset=\"".$Index."\">\n";
17108                    $VTABLES .= "          <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
17109                    $VTABLES .= "          <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
17110                    $VTABLES .= "        </entry>\n";
17111                }
17112                $VTABLES .= "      </vtable>\n\n";
17113            }
17114            else
17115            { # HTML
17116                $VTABLES .= "<table class='vtable'>";
17117                $VTABLES .= "<tr><th width='2%'>Offset</th>";
17118                $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
17119                $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
17120                foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
17121                {
17122                    my ($Color1, $Color2) = ("", "");
17123                    if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
17124                    {
17125                        if($Entries{$Index}{"E1"})
17126                        {
17127                            $Color1 = " class='failed'";
17128                            $Color2 = " class='failed'";
17129                        }
17130                        else {
17131                            $Color2 = " class='warning'";
17132                        }
17133                    }
17134                    $VTABLES .= "<tr><th>".$Index."</th>\n";
17135                    $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
17136                    $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
17137                }
17138                $VTABLES .= "</table><br/>\n";
17139                $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
17140                $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
17141            }
17142            return $VTABLES;
17143        }
17144    }
17145    return "";
17146}
17147
17148sub simpleVEntry($)
17149{
17150    my $VEntry = $_[0];
17151    if(not defined $VEntry
17152    or $VEntry eq "") {
17153        return "";
17154    }
17155    $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
17156    $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
17157    if($VEntry=~/\A_ZThn.+\Z/) {
17158        $VEntry = "non-virtual thunk";
17159    }
17160    $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i;
17161    # support for old GCC versions
17162    $VEntry=~s/\A0u\Z/(int (*)(...))0/;
17163    $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
17164    $VEntry=~s/\A&_Z\Z/& _Z/;
17165    $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
17166    return $VEntry;
17167}
17168
17169sub adjustParamPos($$$)
17170{
17171    my ($Pos, $Symbol, $LibVersion) = @_;
17172    if(defined $CompleteSignature{$LibVersion}{$Symbol})
17173    {
17174        if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"}
17175        and $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
17176        {
17177            return $Pos-1;
17178        }
17179
17180        return $Pos;
17181    }
17182
17183    return undef;
17184}
17185
17186sub getParamPos($$$)
17187{
17188    my ($Name, $Symbol, $LibVersion) = @_;
17189
17190    if(defined $CompleteSignature{$LibVersion}{$Symbol}
17191    and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"})
17192    {
17193        my $Info = $CompleteSignature{$LibVersion}{$Symbol};
17194        foreach (keys(%{$Info->{"Param"}}))
17195        {
17196            if($Info->{"Param"}{$_}{"name"} eq $Name)
17197            {
17198                return $_;
17199            }
17200        }
17201    }
17202
17203    return undef;
17204}
17205
17206sub getParamName($)
17207{
17208    my $Loc = $_[0];
17209    $Loc=~s/\->.*//g;
17210    return $Loc;
17211}
17212
17213sub getAffectedSymbols($$$$)
17214{
17215    my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
17216    my $LIMIT = 1000;
17217
17218    if(defined $AffectLimit)
17219    {
17220        $LIMIT = $AffectLimit;
17221    }
17222    else
17223    {
17224        if($#{$Syms}>=10000)
17225        { # reduce size of the report
17226            $LIMIT = 10;
17227        }
17228    }
17229    my %SProblems = ();
17230    foreach my $Symbol (@{$Syms})
17231    {
17232        if(keys(%SProblems)>$LIMIT) {
17233            last;
17234        }
17235        if(($Symbol=~/(C2|D2|D0)[EI]/))
17236        { # duplicated problems for C2 constructors, D2 and D0 destructors
17237            next;
17238        }
17239        my ($SN, $SS, $SV) = separate_symbol($Symbol);
17240        if($Level eq "Source")
17241        { # remove symbol version
17242            $Symbol=$SN;
17243        }
17244        my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
17245        my $Severity_Max = 0;
17246        my $Signature = get_Signature($Symbol, 1);
17247        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
17248        {
17249            foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
17250            {
17251                if(not defined $Kinds_Locations->{$Kind}
17252                or not $Kinds_Locations->{$Kind}{$Location}) {
17253                    next;
17254                }
17255                if($SV and defined $CompatProblems{$Level}{$SN}
17256                and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
17257                { # duplicated problems for versioned symbols
17258                    next;
17259                }
17260                my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
17261                next if($Type_Name ne $Target_TypeName);
17262
17263                my $PName = getParamName($Location);
17264                my $PPos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1);
17265
17266                my $Severity = $CompatRules{$Level}{$Kind}{"Severity"};
17267                my $Path_Length = 0;
17268                my $ProblemLocation = $Location;
17269                if($Type_Name) {
17270                    $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
17271                }
17272                while($ProblemLocation=~/\-\>/g) {
17273                    $Path_Length += 1;
17274                }
17275                if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
17276                or (cmpLocations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
17277                {
17278                    $MinPath_Length = $Path_Length;
17279                    $Severity_Max = $Severity_Val{$Severity};
17280                    $ProblemLocation_Last = $ProblemLocation;
17281                    %{$SProblems{$Symbol}} = (
17282                        "Descr"=>getAffectDesc($Level, $Symbol, $Kind, $Location),
17283                        "Severity_Max"=>$Severity_Max,
17284                        "Signature"=>$Signature,
17285                        "Position"=>$PPos,
17286                        "Param_Name"=>$PName,
17287                        "Location"=>$Location
17288                    );
17289                }
17290            }
17291        }
17292    }
17293    my @Symbols = keys(%SProblems);
17294    @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Symbols;
17295    @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
17296    if($#Symbols+1>$LIMIT)
17297    { # remove last element
17298        pop(@Symbols);
17299    }
17300    my $Affected = "";
17301    if($ReportFormat eq "xml")
17302    { # XML
17303        $Affected .= "      <affected>\n";
17304        foreach my $Symbol (@Symbols)
17305        {
17306            my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
17307            my $Description = $SProblems{$Symbol}{"Descr"};
17308            my $Location = $SProblems{$Symbol}{"Location"};
17309            my $Target = "";
17310            if($Param_Name) {
17311                $Target = " affected=\"param\" param_name=\"$Param_Name\"";
17312            }
17313            elsif($Location=~/\Aretval(\-|\Z)/i) {
17314                $Target = " affected=\"retval\"";
17315            }
17316            elsif($Location=~/\Athis(\-|\Z)/i) {
17317                $Target = " affected=\"this\"";
17318            }
17319            $Affected .= "        <symbol$Target name=\"$Symbol\">\n";
17320            $Affected .= "          <comment>".xmlSpecChars($Description)."</comment>\n";
17321            $Affected .= "        </symbol>\n";
17322        }
17323        $Affected .= "      </affected>\n";
17324    }
17325    else
17326    { # HTML
17327        foreach my $Symbol (@Symbols)
17328        {
17329            my $Description = $SProblems{$Symbol}{"Descr"};
17330            my $Signature = $SProblems{$Symbol}{"Signature"};
17331            my $Pos = $SProblems{$Symbol}{"Position"};
17332            $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
17333        }
17334        if(keys(%SProblems)>$LIMIT) {
17335            $Affected .= "and others ...<br/>";
17336        }
17337        $Affected = "<div class='affected'>".$Affected."</div>";
17338        if($Affected)
17339        {
17340            $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
17341            $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
17342        }
17343    }
17344    return $Affected;
17345}
17346
17347sub cmpLocations($$)
17348{
17349    my ($L1, $L2) = @_;
17350    if($L2=~/\A(retval|this)\b/
17351    and $L1!~/\A(retval|this)\b/)
17352    {
17353        if($L1!~/\-\>/) {
17354            return 1;
17355        }
17356        elsif($L2=~/\-\>/) {
17357            return 1;
17358        }
17359    }
17360    return 0;
17361}
17362
17363sub getAffectDesc($$$$)
17364{
17365    my ($Level, $Symbol, $Kind, $Location) = @_;
17366
17367    my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
17368
17369    my $Location_I = $Location;
17370    $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field
17371
17372    my @Sentence = ();
17373
17374    if($Kind eq "Overridden_Virtual_Method"
17375    or $Kind eq "Overridden_Virtual_Method_B") {
17376        push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
17377    }
17378    elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
17379    {
17380        my %SymInfo = %{$CompleteSignature{1}{$Symbol}};
17381
17382        if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
17383        {
17384            my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method";
17385            my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"};
17386
17387            if($ClassName eq $Problem{"Type_Name"}) {
17388                push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
17389            }
17390            else {
17391                push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
17392            }
17393        }
17394        else
17395        {
17396            my $TypeID = undef;
17397
17398            if($Location=~/retval/)
17399            { # return value
17400                if(index($Location, "->")!=-1) {
17401                    push(@Sentence, "Field \'".$Location."\' in return value");
17402                }
17403                else {
17404                    push(@Sentence, "Return value");
17405                }
17406
17407                $TypeID = $SymInfo{"Return"};
17408            }
17409            elsif($Location=~/this/)
17410            { # "this" pointer
17411                if(index($Location, "->")!=-1) {
17412                    push(@Sentence, "Field \'".$Location."\' in the object of this method");
17413                }
17414                else {
17415                    push(@Sentence, "\'this\' pointer");
17416                }
17417
17418                $TypeID = $SymInfo{"Class"};
17419            }
17420            else
17421            { # parameters
17422
17423                my $PName = getParamName($Location);
17424                my $PPos = getParamPos($PName, $Symbol, 1);
17425
17426                if(index($Location, "->")!=-1) {
17427                    push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter");
17428                }
17429                else {
17430                    push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter");
17431                }
17432                if($PName) {
17433                    push(@Sentence, "\'".$PName."\'");
17434                }
17435
17436                $TypeID = $SymInfo{"Param"}{$PPos}{"type"};
17437            }
17438
17439            if($Location!~/this/)
17440            {
17441                if(my %PureType = get_PureType($TypeID, $TypeInfo{1}))
17442                {
17443                    if($PureType{"Type"} eq "Pointer") {
17444                        push(@Sentence, "(pointer)");
17445                    }
17446                    elsif($PureType{"Type"} eq "Ref") {
17447                        push(@Sentence, "(reference)");
17448                    }
17449                }
17450            }
17451
17452            if($Location eq "this") {
17453                push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
17454            }
17455            else
17456            {
17457                my $Location_T = $Location;
17458                $Location_T=~s/\A\w+(\->|\Z)//; # location in type
17459
17460                my $TypeID_Problem = $TypeID;
17461                if($Location_T) {
17462                    $TypeID_Problem = getFieldType($Location_T, $TypeID, 1);
17463                }
17464
17465                if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) {
17466                    push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
17467                }
17468                else {
17469                    push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
17470                }
17471            }
17472        }
17473    }
17474    if($ExtendedSymbols{$Symbol}) {
17475        push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling.");
17476    }
17477    return join(" ", @Sentence);
17478}
17479
17480sub getFieldType($$$)
17481{
17482    my ($Location, $TypeId, $LibVersion) = @_;
17483
17484    my @Fields = split("->", $Location);
17485
17486    foreach my $Name (@Fields)
17487    {
17488        my %Info = get_BaseType($TypeId, $LibVersion);
17489
17490        foreach my $Pos (keys(%{$Info{"Memb"}}))
17491        {
17492            if($Info{"Memb"}{$Pos}{"name"} eq $Name)
17493            {
17494                $TypeId = $Info{"Memb"}{$Pos}{"type"};
17495                last;
17496            }
17497        }
17498    }
17499
17500    return $TypeId;
17501}
17502
17503sub get_XmlSign($$)
17504{
17505    my ($Symbol, $LibVersion) = @_;
17506    my $Info = $CompleteSignature{$LibVersion}{$Symbol};
17507    my $Report = "";
17508    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
17509    {
17510        my $Name = $Info->{"Param"}{$Pos}{"name"};
17511        my $Type = $Info->{"Param"}{$Pos}{"type"};
17512        my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
17513        foreach my $Typedef (keys(%ChangedTypedef))
17514        {
17515            if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) {
17516                $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
17517            }
17518        }
17519        $Report .= "    <param pos=\"$Pos\">\n";
17520        $Report .= "      <name>".$Name."</name>\n";
17521        $Report .= "      <type>".xmlSpecChars($TypeName)."</type>\n";
17522        $Report .= "    </param>\n";
17523    }
17524    if(my $Return = $Info->{"Return"})
17525    {
17526        my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
17527        $Report .= "    <retval>\n";
17528        $Report .= "      <type>".xmlSpecChars($RTName)."</type>\n";
17529        $Report .= "    </retval>\n";
17530    }
17531    return $Report;
17532}
17533
17534sub get_Report_SymbolsInfo($)
17535{
17536    my $Level = $_[0];
17537    my $Report = "<symbols_info>\n";
17538    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
17539    {
17540        my ($SN, $SS, $SV) = separate_symbol($Symbol);
17541        if($SV and defined $CompatProblems{$Level}{$SN}) {
17542            next;
17543        }
17544        $Report .= "  <symbol name=\"$Symbol\">\n";
17545        my ($S1, $P1, $S2, $P2) = ();
17546        if(not $AddedInt{$Level}{$Symbol})
17547        {
17548            if(defined $CompleteSignature{1}{$Symbol}
17549            and defined $CompleteSignature{1}{$Symbol}{"Header"})
17550            {
17551                $P1 = get_XmlSign($Symbol, 1);
17552                $S1 = get_Signature($Symbol, 1);
17553            }
17554            elsif($Symbol=~/\A(_Z|\?)/) {
17555                $S1 = $tr_name{$Symbol};
17556            }
17557        }
17558        if(not $RemovedInt{$Level}{$Symbol})
17559        {
17560            if(defined $CompleteSignature{2}{$Symbol}
17561            and defined $CompleteSignature{2}{$Symbol}{"Header"})
17562            {
17563                $P2 = get_XmlSign($Symbol, 2);
17564                $S2 = get_Signature($Symbol, 2);
17565            }
17566            elsif($Symbol=~/\A(_Z|\?)/) {
17567                $S2 = $tr_name{$Symbol};
17568            }
17569        }
17570        if($S1)
17571        {
17572            $Report .= "    <old signature=\"".xmlSpecChars($S1)."\">\n";
17573            $Report .= $P1;
17574            $Report .= "    </old>\n";
17575        }
17576        if($S2 and $S2 ne $S1)
17577        {
17578            $Report .= "    <new signature=\"".xmlSpecChars($S2)."\">\n";
17579            $Report .= $P2;
17580            $Report .= "    </new>\n";
17581        }
17582        $Report .= "  </symbol>\n";
17583    }
17584    $Report .= "</symbols_info>\n";
17585    return $Report;
17586}
17587
17588sub writeReport($$)
17589{
17590    my ($Level, $Report) = @_;
17591    if($ReportFormat eq "xml") {
17592        $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
17593    }
17594    if($StdOut)
17595    { # --stdout option
17596        print STDOUT $Report;
17597    }
17598    else
17599    {
17600        my $RPath = getReportPath($Level);
17601        mkpath(get_dirname($RPath));
17602
17603        open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
17604        print REPORT $Report;
17605        close(REPORT);
17606
17607        if($Browse or $OpenReport)
17608        { # open in browser
17609            openReport($RPath);
17610            if($JoinReport or $DoubleReport)
17611            {
17612                if($Level eq "Binary")
17613                { # wait to open a browser
17614                    sleep(1);
17615                }
17616            }
17617        }
17618    }
17619}
17620
17621sub openReport($)
17622{
17623    my $Path = $_[0];
17624    my $Cmd = "";
17625    if($Browse)
17626    { # user-defined browser
17627        $Cmd = $Browse." \"$Path\"";
17628    }
17629    if(not $Cmd)
17630    { # default browser
17631        if($OSgroup eq "macos") {
17632            $Cmd = "open \"$Path\"";
17633        }
17634        elsif($OSgroup eq "windows") {
17635            $Cmd = "start ".path_format($Path, $OSgroup);
17636        }
17637        else
17638        { # linux, freebsd, solaris
17639            my @Browsers = (
17640                "x-www-browser",
17641                "sensible-browser",
17642                "firefox",
17643                "opera",
17644                "xdg-open",
17645                "lynx",
17646                "links"
17647            );
17648            foreach my $Br (@Browsers)
17649            {
17650                if($Br = get_CmdPath($Br))
17651                {
17652                    $Cmd = $Br." \"$Path\"";
17653                    last;
17654                }
17655            }
17656        }
17657    }
17658    if($Cmd)
17659    {
17660        if($Debug) {
17661            printMsg("INFO", "running $Cmd");
17662        }
17663        if($OSgroup ne "windows"
17664        and $OSgroup ne "macos")
17665        {
17666            if($Cmd!~/lynx|links/) {
17667                $Cmd .= "  >\"/dev/null\" 2>&1 &";
17668            }
17669        }
17670        system($Cmd);
17671    }
17672    else {
17673        printMsg("ERROR", "cannot open report in browser");
17674    }
17675}
17676
17677sub getReport($)
17678{
17679    my $Level = $_[0];
17680    if($ReportFormat eq "xml")
17681    { # XML
17682
17683        if($Level eq "Join")
17684        {
17685            my $Report = "<reports>\n";
17686            $Report .= getReport("Binary");
17687            $Report .= getReport("Source");
17688            $Report .= "</reports>\n";
17689            return $Report;
17690        }
17691        else
17692        {
17693            my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
17694            my ($Summary, $MetaData) = get_Summary($Level);
17695            $Report .= $Summary."\n";
17696            $Report .= get_Report_Added($Level).get_Report_Removed($Level);
17697            $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
17698            $Report .= get_Report_SymbolsInfo($Level);
17699            $Report .= "</report>\n";
17700            return $Report;
17701        }
17702    }
17703    else
17704    { # HTML
17705        my $CssStyles = readModule("Styles", "Report.css");
17706        my $JScripts = readModule("Scripts", "Sections.js");
17707        if($Level eq "Join")
17708        {
17709            $CssStyles .= "\n".readModule("Styles", "Tabs.css");
17710            $JScripts .= "\n".readModule("Scripts", "Tabs.js");
17711            my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
17712            my $Keywords = $TargetLibraryFName.", compatibility, API, report";
17713            my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
17714            my ($BSummary, $BMetaData) = get_Summary("Binary");
17715            my ($SSummary, $SMetaData) = get_Summary("Source");
17716            my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>";
17717            $Report .= get_Report_Header("Join")."
17718            <br/><div class='tabset'>
17719            <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
17720            <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
17721            </div>";
17722            $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>";
17723            $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>";
17724            $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
17725            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
17726            return $Report;
17727        }
17728        else
17729        {
17730            my ($Summary, $MetaData) = get_Summary($Level);
17731            my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
17732            my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
17733            my $Description = "$Level compatibility report for the ".$TargetLibraryFName." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
17734            if($Level eq "Binary")
17735            {
17736                if(getArch(1) eq getArch(2)
17737                and getArch(1) ne "unknown") {
17738                    $Description .= " on ".showArch(getArch(1));
17739                }
17740            }
17741            my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
17742            $Report .= get_Report_Header($Level)."\n".$Summary."\n";
17743            $Report .= get_Report_Added($Level).get_Report_Removed($Level);
17744            $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
17745            $Report .= get_SourceInfo();
17746            $Report .= "</div>\n<br/><br/><br/><hr/>\n";
17747            $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
17748            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
17749            return $Report;
17750        }
17751    }
17752}
17753
17754sub getLegend()
17755{
17756    return "<br/>
17757<table class='summary'>
17758<tr>
17759    <td class='new'>added</td>
17760    <td class='passed'>compatible</td>
17761</tr>
17762<tr>
17763    <td class='warning'>warning</td>
17764    <td class='failed'>incompatible</td>
17765</tr></table>\n";
17766}
17767
17768sub createReport()
17769{
17770    if($JoinReport)
17771    { # --stdout
17772        writeReport("Join", getReport("Join"));
17773    }
17774    elsif($DoubleReport)
17775    { # default
17776        writeReport("Binary", getReport("Binary"));
17777        writeReport("Source", getReport("Source"));
17778    }
17779    elsif($BinaryOnly)
17780    { # --binary
17781        writeReport("Binary", getReport("Binary"));
17782    }
17783    elsif($SourceOnly)
17784    { # --source
17785        writeReport("Source", getReport("Source"));
17786    }
17787}
17788
17789sub getReportFooter($$)
17790{
17791    my ($LibName, $Wide) = @_;
17792    my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
17793    my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
17794    $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
17795    $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
17796    my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
17797    $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
17798    return $Footer;
17799}
17800
17801sub get_Report_Problems($$)
17802{
17803    my ($Priority, $Level) = @_;
17804    my $Report = get_Report_TypeProblems($Priority, $Level);
17805    if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
17806        $Report .= $SProblems;
17807    }
17808    if($Priority eq "Low")
17809    {
17810        $Report .= get_Report_ChangedConstants("Low", $Level);
17811        if($ReportFormat eq "html")
17812        {
17813            if($CheckImpl and $Level eq "Binary") {
17814                $Report .= get_Report_Impl();
17815            }
17816        }
17817    }
17818    if($Priority eq "Safe")
17819    {
17820        $Report .= get_Report_ChangedConstants("Safe", $Level);
17821    }
17822    if($ReportFormat eq "html")
17823    {
17824        if($Report)
17825        { # add anchor
17826            if($JoinReport)
17827            {
17828                if($Priority eq "Safe") {
17829                    $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
17830                }
17831                else {
17832                    $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
17833                }
17834            }
17835            else
17836            {
17837                if($Priority eq "Safe") {
17838                    $Report = "<a name=\'Other_Changes\'></a>".$Report;
17839                }
17840                else {
17841                    $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
17842                }
17843            }
17844        }
17845    }
17846    return $Report;
17847}
17848
17849sub composeHTML_Head($$$$$)
17850{
17851    my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
17852    return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
17853    <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
17854    <head>
17855    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
17856    <meta name=\"keywords\" content=\"$Keywords\" />
17857    <meta name=\"description\" content=\"$Description\" />
17858    <title>
17859        $Title
17860    </title>
17861    <style type=\"text/css\">
17862    $Styles
17863    </style>
17864    <script type=\"text/javascript\" language=\"JavaScript\">
17865    <!--
17866    $Scripts
17867    -->
17868    </script>
17869    </head>";
17870}
17871
17872sub insertIDs($)
17873{
17874    my $Text = $_[0];
17875    while($Text=~/CONTENT_ID/)
17876    {
17877        if(int($Content_Counter)%2) {
17878            $ContentID -= 1;
17879        }
17880        $Text=~s/CONTENT_ID/c_$ContentID/;
17881        $ContentID += 1;
17882        $Content_Counter += 1;
17883    }
17884    return $Text;
17885}
17886
17887sub checkPreprocessedUnit($)
17888{
17889    my $Path = $_[0];
17890    my ($CurHeader, $CurHeaderName) = ("", "");
17891    my $CurClass = ""; # extra info
17892    open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
17893
17894    while(my $Line = <PREPROC>)
17895    { # detecting public and private constants
17896        if(substr($Line, 0, 1) eq "#")
17897        {
17898            chomp($Line);
17899            if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
17900            {
17901                $CurHeader = path_format($1, $OSgroup);
17902                $CurHeaderName = get_filename($CurHeader);
17903                $CurClass = "";
17904
17905                if(index($CurHeader, $TMP_DIR)==0) {
17906                    next;
17907                }
17908
17909                if(substr($CurHeaderName, 0, 1) eq "<")
17910                { # <built-in>, <command-line>, etc.
17911                    $CurHeaderName = "";
17912                    $CurHeader = "";
17913                }
17914
17915                if($ExtraInfo)
17916                {
17917                    if($CurHeaderName) {
17918                        $PreprocessedHeaders{$Version}{$CurHeader} = 1;
17919                    }
17920                }
17921            }
17922            if(not $ExtraDump)
17923            {
17924                if($CurHeaderName)
17925                {
17926                    if(not $Include_Neighbors{$Version}{$CurHeaderName}
17927                    and not $Registered_Headers{$Version}{$CurHeader})
17928                    { # not a target
17929                        next;
17930                    }
17931                    if(not is_target_header($CurHeaderName, 1)
17932                    and not is_target_header($CurHeaderName, 2))
17933                    { # user-defined header
17934                        next;
17935                    }
17936                }
17937            }
17938
17939            if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
17940            {
17941                my ($Name, $Value) = ($1, $2);
17942                if(not $Constants{$Version}{$Name}{"Access"})
17943                {
17944                    $Constants{$Version}{$Name}{"Access"} = "public";
17945                    $Constants{$Version}{$Name}{"Value"} = $Value;
17946                    if($CurHeaderName) {
17947                        $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
17948                    }
17949                }
17950            }
17951            elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
17952                $Constants{$Version}{$1}{"Access"} = "private";
17953            }
17954        }
17955        else
17956        {
17957            if(defined $ExtraDump)
17958            {
17959                if($Line=~/(\w+)\s*\(/)
17960                { # functions
17961                    $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader;
17962                }
17963                #elsif($Line=~/(\w+)\s*;/)
17964                #{ # data
17965                #    $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader;
17966                #}
17967                elsif($Line=~/(\A|\s)class\s+(\w+)/) {
17968                    $CurClass = $2;
17969                }
17970            }
17971        }
17972    }
17973    close(PREPROC);
17974    foreach my $Constant (keys(%{$Constants{$Version}}))
17975    {
17976        if($Constants{$Version}{$Constant}{"Access"} eq "private")
17977        {
17978            delete($Constants{$Version}{$Constant});
17979            next;
17980        }
17981        if(not $ExtraDump and ($Constant=~/_h\Z/i
17982        or isBuiltIn($Constants{$Version}{$Constant}{"Header"})))
17983        { # skip
17984            delete($Constants{$Version}{$Constant});
17985        }
17986        else {
17987            delete($Constants{$Version}{$Constant}{"Access"});
17988        }
17989    }
17990    if($Debug)
17991    {
17992        mkpath($DEBUG_PATH{$Version});
17993        copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
17994    }
17995}
17996
17997sub uncoverConstant($$)
17998{
17999    my ($LibVersion, $Constant) = @_;
18000    return "" if(not $LibVersion or not $Constant);
18001    return $Constant if(isCyclical(\@RecurConstant, $Constant));
18002    if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
18003        return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
18004    }
18005
18006    if(defined $Constants{$LibVersion}{$Constant})
18007    {
18008        my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
18009        if(defined $Constants{$LibVersion}{$Value})
18010        {
18011            push(@RecurConstant, $Constant);
18012            my $Uncovered = uncoverConstant($LibVersion, $Value);
18013            if($Uncovered ne "") {
18014                $Value = $Uncovered;
18015            }
18016            pop(@RecurConstant);
18017        }
18018
18019        # FIXME: uncover $Value using all the enum constants
18020        # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
18021        return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
18022    }
18023    return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
18024}
18025
18026sub simpleConstant($$)
18027{
18028    my ($LibVersion, $Value) = @_;
18029    if($Value=~/\W/)
18030    {
18031        my $Value_Copy = $Value;
18032        while($Value_Copy=~s/([a-z_]\w+)/\@/i)
18033        {
18034            my $Word = $1;
18035            if($Value!~/$Word\s*\(/)
18036            {
18037                my $Val = uncoverConstant($LibVersion, $Word);
18038                if($Val ne "")
18039                {
18040                    $Value=~s/\b$Word\b/$Val/g;
18041                }
18042            }
18043        }
18044    }
18045    return $Value;
18046}
18047
18048sub computeValue($)
18049{
18050    my $Value = $_[0];
18051
18052    if($Value=~/\A\((-?[\d]+)\)\Z/) {
18053        return $1;
18054    }
18055
18056    if($Value=~/\A[\d\-\+()]+\Z/) {
18057        return eval($Value);
18058    }
18059
18060    return $Value;
18061}
18062
18063my %IgnoreConstant = map {$_=>1} (
18064    "VERSION",
18065    "VERSIONCODE",
18066    "VERNUM",
18067    "VERS_INFO",
18068    "PATCHLEVEL",
18069    "INSTALLPREFIX",
18070    "VBUILD",
18071    "VPATCH",
18072    "VMINOR",
18073    "BUILD_STRING",
18074    "BUILD_TIME",
18075    "PACKAGE_STRING",
18076    "PRODUCTION",
18077    "CONFIGURE_COMMAND",
18078    "INSTALLDIR",
18079    "BINDIR",
18080    "CONFIG_FILE_PATH",
18081    "DATADIR",
18082    "EXTENSION_DIR",
18083    "INCLUDE_PATH",
18084    "LIBDIR",
18085    "LOCALSTATEDIR",
18086    "SBINDIR",
18087    "SYSCONFDIR",
18088    "RELEASE",
18089    "SOURCE_ID",
18090    "SUBMINOR",
18091    "MINOR",
18092    "MINNOR",
18093    "MINORVERSION",
18094    "MAJOR",
18095    "MAJORVERSION",
18096    "MICRO",
18097    "MICROVERSION",
18098    "BINARY_AGE",
18099    "INTERFACE_AGE",
18100    "CORE_ABI",
18101    "PATCH",
18102    "COPYRIGHT",
18103    "TIMESTAMP",
18104    "REVISION",
18105    "PACKAGE_TAG",
18106    "PACKAGEDATE",
18107    "NUMVERSION",
18108    "Release",
18109    "Version"
18110);
18111
18112sub constantFilter($$$)
18113{
18114    my ($Name, $Value, $Level) = @_;
18115
18116    if($Level eq "Binary")
18117    {
18118        if($Name=~/_t\Z/)
18119        { # __malloc_ptr_t
18120            return 1;
18121        }
18122        foreach (keys(%IgnoreConstant))
18123        {
18124            if($Name=~/(\A|_)$_(_|\Z)/)
18125            { # version
18126                return 1;
18127            }
18128            if(/\A[A-Z].*[a-z]\Z/)
18129            {
18130                if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/)
18131                { # version
18132                    return 1;
18133                }
18134            }
18135        }
18136        if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
18137        { # version
18138            return 1;
18139        }
18140        if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/)
18141        { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
18142            return 1;
18143        }
18144
18145        if($Value=~/\A["'].*['"]/i)
18146        { # string
18147            return 0;
18148        }
18149
18150        if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i)
18151        { # static int gcry_pth_init
18152          # extern ABC
18153          # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
18154          # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ...
18155            return 1;
18156        }
18157        if($Value=~/\w+\s*\(/i)
18158        { # foo(p)
18159            return 1;
18160        }
18161        if($Value=~/\A[a-z_]+\w*\Z/i)
18162        { # asn1_node_st
18163          # __SMTH_P
18164            return 1;
18165        }
18166    }
18167
18168    return 0;
18169}
18170
18171sub mergeConstants($)
18172{
18173    my $Level = $_[0];
18174    foreach my $Constant (keys(%{$Constants{1}}))
18175    {
18176        if($SkipConstants{1}{$Constant})
18177        { # skipped by the user
18178            next;
18179        }
18180
18181        if(my $Header = $Constants{1}{$Constant}{"Header"})
18182        {
18183            if(not is_target_header($Header, 1)
18184            and not is_target_header($Header, 2))
18185            { # user-defined header
18186                next;
18187            }
18188        }
18189        else {
18190            next;
18191        }
18192
18193        my $Old_Value = uncoverConstant(1, $Constant);
18194
18195        if(constantFilter($Constant, $Old_Value, $Level))
18196        { # separate binary and source problems
18197            next;
18198        }
18199
18200        if(not defined $Constants{2}{$Constant}{"Value"})
18201        { # removed
18202            %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = (
18203                "Target"=>$Constant,
18204                "Old_Value"=>$Old_Value  );
18205            next;
18206        }
18207
18208        if($Constants{2}{$Constant}{"Value"} eq "")
18209        { # empty value
18210          # TODO: implement a rule
18211            next;
18212        }
18213
18214        my $New_Value = uncoverConstant(2, $Constant);
18215
18216        my $Old_Value_Pure = $Old_Value;
18217        my $New_Value_Pure = $New_Value;
18218
18219        $Old_Value_Pure=~s/(\W)\s+/$1/g;
18220        $Old_Value_Pure=~s/\s+(\W)/$1/g;
18221        $New_Value_Pure=~s/(\W)\s+/$1/g;
18222        $New_Value_Pure=~s/\s+(\W)/$1/g;
18223
18224        next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
18225
18226        if($New_Value_Pure ne $Old_Value_Pure)
18227        { # different values
18228            if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value))
18229            { # complex values
18230                next;
18231            }
18232            if(computeValue($Old_Value) eq computeValue($New_Value))
18233            { # expressions
18234                next;
18235            }
18236            if(convert_integer($Old_Value) eq convert_integer($New_Value))
18237            { # 0x0001 and 0x1, 0x1 and 1 equal constants
18238                next;
18239            }
18240            if($Old_Value eq "0" and $New_Value eq "NULL")
18241            { # 0 => NULL
18242                next;
18243            }
18244            if($Old_Value eq "NULL" and $New_Value eq "0")
18245            { # NULL => 0
18246                next;
18247            }
18248            %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = (
18249                "Target"=>$Constant,
18250                "Old_Value"=>$Old_Value,
18251                "New_Value"=>$New_Value  );
18252        }
18253    }
18254
18255    foreach my $Constant (keys(%{$Constants{2}}))
18256    {
18257        if(not defined $Constants{1}{$Constant}{"Value"})
18258        {
18259            if($SkipConstants{2}{$Constant})
18260            { # skipped by the user
18261                next;
18262            }
18263
18264            if(my $Header = $Constants{2}{$Constant}{"Header"})
18265            {
18266                if(not is_target_header($Header, 1)
18267                and not is_target_header($Header, 2))
18268                { # user-defined header
18269                    next;
18270                }
18271            }
18272            else {
18273                next;
18274            }
18275
18276            my $New_Value = uncoverConstant(2, $Constant);
18277            if(not defined $New_Value or $New_Value eq "") {
18278                next;
18279            }
18280
18281            if(constantFilter($Constant, $New_Value, $Level))
18282            { # separate binary and source problems
18283                next;
18284            }
18285
18286            %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = (
18287                "Target"=>$Constant,
18288                "New_Value"=>$New_Value  );
18289        }
18290    }
18291}
18292
18293sub convert_integer($)
18294{
18295    my $Value = $_[0];
18296    if($Value=~/\A0x[a-f0-9]+\Z/)
18297    { # hexadecimal
18298        return hex($Value);
18299    }
18300    elsif($Value=~/\A0[0-7]+\Z/)
18301    { # octal
18302        return oct($Value);
18303    }
18304    elsif($Value=~/\A0b[0-1]+\Z/)
18305    { # binary
18306        return oct($Value);
18307    }
18308    else {
18309        return $Value;
18310    }
18311}
18312
18313sub readSymbols($)
18314{
18315    my $LibVersion = $_[0];
18316    my @LibPaths = getSOPaths($LibVersion);
18317    if($#LibPaths==-1 and not $CheckHeadersOnly)
18318    {
18319        if($LibVersion==1)
18320        {
18321            printMsg("WARNING", "checking headers only");
18322            $CheckHeadersOnly = 1;
18323        }
18324        else {
18325            exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
18326        }
18327    }
18328
18329    foreach my $LibPath (@LibPaths) {
18330        readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
18331    }
18332
18333    if($CheckUndefined)
18334    {
18335        my %UndefinedLibs = ();
18336
18337        my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}}));
18338
18339        foreach my $LibName (sort @Libs)
18340        {
18341            if(defined $UndefinedSymbols{$LibVersion}{$LibName})
18342            {
18343                foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}}))
18344                {
18345                    if($Symbol_Library{$LibVersion}{$Symbol}
18346                    or $DepSymbol_Library{$LibVersion}{$Symbol})
18347                    { # exported by target library
18348                        next;
18349                    }
18350                    if(index($Symbol, '@')!=-1)
18351                    { # exported default symbol version (@@)
18352                        $Symbol=~s/\@/\@\@/;
18353                        if($Symbol_Library{$LibVersion}{$Symbol}
18354                        or $DepSymbol_Library{$LibVersion}{$Symbol}) {
18355                            next;
18356                        }
18357                    }
18358                    foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) {
18359                        $UndefinedLibs{$Path} = 1;
18360                    }
18361                }
18362            }
18363        }
18364        if($ExtraInfo)
18365        { # extra information for other tools
18366            if(my @Paths = sort keys(%UndefinedLibs))
18367            {
18368                my $LibString = "";
18369                my %Dirs = ();
18370                foreach (@Paths)
18371                {
18372                    $KnownLibs{$_} = 1;
18373                    my ($Dir, $Name) = separate_path($_);
18374
18375                    if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) {
18376                        $Dirs{esc($Dir)} = 1;
18377                    }
18378
18379                    $Name = parse_libname($Name, "name", $OStarget);
18380                    $Name=~s/\Alib//;
18381
18382                    $LibString .= " -l$Name";
18383                }
18384
18385                foreach my $Dir (sort {$b cmp $a} keys(%Dirs))
18386                {
18387                    $LibString = " -L".esc($Dir).$LibString;
18388                }
18389
18390                writeFile($ExtraInfo."/libs-string", $LibString);
18391            }
18392        }
18393    }
18394
18395    if($ExtraInfo) {
18396        writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs)));
18397    }
18398
18399    if(not $CheckHeadersOnly)
18400    {
18401        if($#LibPaths!=-1)
18402        {
18403            if(not keys(%{$Symbol_Library{$LibVersion}}))
18404            {
18405                printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
18406                printMsg("WARNING", "checking headers only");
18407                $CheckHeadersOnly = 1;
18408            }
18409        }
18410    }
18411
18412   # clean memory
18413   %SystemObjects = ();
18414}
18415
18416my %Prefix_Lib_Map=(
18417 # symbols for autodetecting library dependencies (by prefix)
18418    "pthread_" => ["libpthread"],
18419    "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"],
18420    "cairo_" => ["libcairo"],
18421    "gtk_" => ["libgtk-x11-2.0"],
18422    "atk_" => ["libatk-1.0"],
18423    "gdk_" => ["libgdk-x11-2.0"],
18424    "gl" => ["libGL"],
18425    "glu" => ["libGLU"],
18426    "popt" => ["libpopt"],
18427    "Py" => ["libpython"],
18428    "jpeg_" => ["libjpeg"],
18429    "BZ2_" => ["libbz2"],
18430    "Fc" => ["libfontconfig"],
18431    "Xft" => ["libXft"],
18432    "SSL_" => ["libssl"],
18433    "sem_" => ["libpthread"],
18434    "snd_" => ["libasound"],
18435    "art_" => ["libart_lgpl_2"],
18436    "dbus_g" => ["libdbus-glib-1"],
18437    "GOMP_" => ["libgomp"],
18438    "omp_" => ["libgomp"],
18439    "cms" => ["liblcms"]
18440);
18441
18442my %Pattern_Lib_Map=(
18443    "SL[a-z]" => ["libslang"]
18444);
18445
18446my %Symbol_Lib_Map=(
18447 # symbols for autodetecting library dependencies (by name)
18448    "pow" => "libm",
18449    "fmod" => "libm",
18450    "sin" => "libm",
18451    "floor" => "libm",
18452    "cos" => "libm",
18453    "dlopen" => "libdl",
18454    "deflate" => "libz",
18455    "inflate" => "libz",
18456    "move_panel" => "libpanel",
18457    "XOpenDisplay" => "libX11",
18458    "resize_term" => "libncurses",
18459    "clock_gettime" => "librt",
18460    "crypt" => "libcrypt"
18461);
18462
18463sub find_SymbolLibs($$)
18464{
18465    my ($LibVersion, $Symbol) = @_;
18466
18467    if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/)
18468    { # debug symbols
18469        return ();
18470    }
18471
18472    my %Paths = ();
18473
18474    if(my $LibName = $Symbol_Lib_Map{$Symbol})
18475    {
18476        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
18477            $Paths{$Path} = 1;
18478        }
18479    }
18480
18481    if(my $SymbolPrefix = getPrefix($Symbol))
18482    {
18483        if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) {
18484            return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}};
18485        }
18486
18487        if(not keys(%Paths))
18488        {
18489            if(defined $Prefix_Lib_Map{$SymbolPrefix})
18490            {
18491                foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}})
18492                {
18493                    if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
18494                        $Paths{$Path} = 1;
18495                    }
18496                }
18497            }
18498        }
18499
18500        if(not keys(%Paths))
18501        {
18502            foreach my $Prefix (sort keys(%Pattern_Lib_Map))
18503            {
18504                if($Symbol=~/\A$Prefix/)
18505                {
18506                    foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}})
18507                    {
18508                        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
18509                            $Paths{$Path} = 1;
18510                        }
18511                    }
18512                }
18513            }
18514        }
18515
18516        if(not keys(%Paths))
18517        {
18518            if($SymbolPrefix)
18519            { # try to find a library by symbol prefix
18520                if($SymbolPrefix eq "inotify" and
18521                index($Symbol, "\@GLIBC")!=-1)
18522                {
18523                    if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) {
18524                        $Paths{$Path} = 1;
18525                    }
18526                }
18527                else
18528                {
18529                    if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) {
18530                        $Paths{$Path} = 1;
18531                    }
18532                }
18533            }
18534        }
18535
18536        if(my @Paths = keys(%Paths)) {
18537            $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths;
18538        }
18539    }
18540    return keys(%Paths);
18541}
18542
18543sub get_LibPath_Prefix($$)
18544{
18545    my ($LibVersion, $Prefix) = @_;
18546
18547    $Prefix = lc($Prefix);
18548    $Prefix=~s/[_]+\Z//g;
18549
18550    foreach ("-2", "2", "-1", "1", "")
18551    { # libgnome-2.so
18552      # libxml2.so
18553      # libdbus-1.so
18554        if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) {
18555            return $Path;
18556        }
18557    }
18558    return "";
18559}
18560
18561sub getPrefix($)
18562{
18563    my $Str = $_[0];
18564    if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
18565    { # XmuValidArea: Xmu
18566        return $1;
18567    }
18568    elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
18569    { # snfReadFont: snf
18570        return $1;
18571    }
18572    elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
18573    { # XRRTimes: XRR
18574        return $1;
18575    }
18576    elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i)
18577    { # H5HF_delete: H5
18578        return $1;
18579    }
18580    elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
18581    { # alarm_event_add: alarm_
18582        return $1;
18583    }
18584    elsif($Str=~/\A(([a-z])\2{1,})/i)
18585    { # ffopen
18586        return $1;
18587    }
18588    return "";
18589}
18590
18591sub getSymbolSize($$)
18592{ # size from the shared library
18593    my ($Symbol, $LibVersion) = @_;
18594    return 0 if(not $Symbol);
18595    if(defined $Symbol_Library{$LibVersion}{$Symbol}
18596    and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
18597    {
18598        if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
18599        and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
18600        {
18601            if($Size<0) {
18602                return -$Size;
18603            }
18604        }
18605    }
18606    return 0;
18607}
18608
18609sub canonifyName($$)
18610{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
18611  # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
18612    my ($Name, $Type) = @_;
18613
18614    # single
18615    while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
18616    {
18617        my $P = $1;
18618        $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
18619    }
18620
18621    # double
18622    if($Name=~/$DEFAULT_STD_PARMS/)
18623    {
18624        if($Type eq "S")
18625        {
18626            my ($ShortName, $FuncParams) = split_Signature($Name);
18627
18628            foreach my $FParam (separate_Params($FuncParams, 0, 0))
18629            {
18630                if(index($FParam, "<")!=-1)
18631                {
18632                    $FParam=~s/>([^<>]+)\Z/>/; # remove quals
18633                    my $FParam_N = canonifyName($FParam, "T");
18634                    if($FParam_N ne $FParam) {
18635                        $Name=~s/\Q$FParam\E/$FParam_N/g;
18636                    }
18637                }
18638            }
18639        }
18640        elsif($Type eq "T")
18641        {
18642            my ($ShortTmpl, $TmplParams) = template_Base($Name);
18643
18644            my @TParams = separate_Params($TmplParams, 0, 0);
18645            if($#TParams>=1)
18646            {
18647                my $FParam = $TParams[0];
18648                foreach my $Pos (1 .. $#TParams)
18649                {
18650                    my $TParam = $TParams[$Pos];
18651                    if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
18652                        $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
18653                    }
18654                }
18655            }
18656        }
18657    }
18658    if($Type eq "S") {
18659        return formatName($Name, "S");
18660    }
18661    return $Name;
18662}
18663
18664sub translateSymbols(@)
18665{
18666    my $LibVersion = pop(@_);
18667    my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
18668    foreach my $Symbol (sort @_)
18669    {
18670        if(index($Symbol, "_Z")==0)
18671        {
18672            next if($tr_name{$Symbol});
18673            $Symbol=~s/[\@\$]+(.*)\Z//;
18674            push(@MnglNames1, $Symbol);
18675        }
18676        elsif(index($Symbol, "?")==0)
18677        {
18678            next if($tr_name{$Symbol});
18679            push(@MnglNames2, $Symbol);
18680        }
18681        else
18682        { # not mangled
18683            $tr_name{$Symbol} = $Symbol;
18684            $mangled_name_gcc{$Symbol} = $Symbol;
18685            $mangled_name{$LibVersion}{$Symbol} = $Symbol;
18686        }
18687    }
18688    if($#MnglNames1 > -1)
18689    { # GCC names
18690        @UnmangledNames = reverse(unmangleArray(@MnglNames1));
18691        foreach my $MnglName (@MnglNames1)
18692        {
18693            if(my $Unmangled = pop(@UnmangledNames))
18694            {
18695                $tr_name{$MnglName} = canonifyName($Unmangled, "S");
18696                if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
18697                    $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
18698                }
18699                if(index($MnglName, "_ZTV")==0
18700                and $tr_name{$MnglName}=~/vtable for (.+)/)
18701                { # bind class name and v-table symbol
18702                    my $ClassName = $1;
18703                    $ClassVTable{$ClassName} = $MnglName;
18704                    $VTableClass{$MnglName} = $ClassName;
18705                }
18706            }
18707        }
18708    }
18709    if($#MnglNames2 > -1)
18710    { # MSVC names
18711        @UnmangledNames = reverse(unmangleArray(@MnglNames2));
18712        foreach my $MnglName (@MnglNames2)
18713        {
18714            if(my $Unmangled = pop(@UnmangledNames))
18715            {
18716                $tr_name{$MnglName} = formatName($Unmangled, "S");
18717                $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
18718            }
18719        }
18720    }
18721    return \%tr_name;
18722}
18723
18724sub link_symbol($$$)
18725{
18726    my ($Symbol, $RunWith, $Deps) = @_;
18727    if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
18728        return 1;
18729    }
18730    if($Deps eq "+Deps")
18731    { # check the dependencies
18732        if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
18733            return 1;
18734        }
18735    }
18736    return 0;
18737}
18738
18739sub link_symbol_internal($$$)
18740{
18741    my ($Symbol, $RunWith, $Where) = @_;
18742    return 0 if(not $Where or not $Symbol);
18743    if($Where->{$RunWith}{$Symbol})
18744    { # the exact match by symbol name
18745        return 1;
18746    }
18747    if(my $VSym = $SymVer{$RunWith}{$Symbol})
18748    { # indirect symbol version, i.e.
18749      # foo_old and its symlink foo@v (or foo@@v)
18750      # foo_old may be in symtab table
18751        if($Where->{$RunWith}{$VSym}) {
18752            return 1;
18753        }
18754    }
18755    my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
18756    if($Sym and $Ver)
18757    { # search for the symbol with the same version
18758      # or without version
18759        if($Where->{$RunWith}{$Sym})
18760        { # old: foo@v|foo@@v
18761          # new: foo
18762            return 1;
18763        }
18764        if($Where->{$RunWith}{$Sym."\@".$Ver})
18765        { # old: foo|foo@@v
18766          # new: foo@v
18767            return 1;
18768        }
18769        if($Where->{$RunWith}{$Sym."\@\@".$Ver})
18770        { # old: foo|foo@v
18771          # new: foo@@v
18772            return 1;
18773        }
18774    }
18775    return 0;
18776}
18777
18778sub readSymbols_App($)
18779{
18780    my $Path = $_[0];
18781    return () if(not $Path);
18782    my @Imported = ();
18783    if($OSgroup eq "macos")
18784    {
18785        my $NM = get_CmdPath("nm");
18786        if(not $NM) {
18787            exitStatus("Not_Found", "can't find \"nm\"");
18788        }
18789        open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
18790        while(<APP>)
18791        {
18792            if(/ U _([\w\$]+)\s*\Z/) {
18793                push(@Imported, $1);
18794            }
18795        }
18796        close(APP);
18797    }
18798    elsif($OSgroup eq "windows")
18799    {
18800        my $DumpBinCmd = get_CmdPath("dumpbin");
18801        if(not $DumpBinCmd) {
18802            exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
18803        }
18804        open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
18805        while(<APP>)
18806        {
18807            if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
18808                push(@Imported, $1);
18809            }
18810        }
18811        close(APP);
18812    }
18813    else
18814    {
18815        my $ReadelfCmd = get_CmdPath("readelf");
18816        if(not $ReadelfCmd) {
18817            exitStatus("Not_Found", "can't find \"readelf\"");
18818        }
18819        open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |");
18820        my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
18821        while(<APP>)
18822        {
18823            if(defined $symtab)
18824            { # do nothing with symtab
18825                if(index($_, "'.dynsym'")!=-1)
18826                { # dynamic table
18827                    $symtab = undef;
18828                }
18829            }
18830            elsif(index($_, "'.symtab'")!=-1)
18831            { # symbol table
18832                $symtab = 1;
18833            }
18834            elsif(my @Info = readline_ELF($_))
18835            {
18836                my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
18837                if($Ndx eq "UND")
18838                { # only imported symbols
18839                    push(@Imported, $Symbol);
18840                }
18841            }
18842        }
18843        close(APP);
18844    }
18845    return @Imported;
18846}
18847
18848my %ELF_BIND = map {$_=>1} (
18849    "WEAK",
18850    "GLOBAL"
18851);
18852
18853my %ELF_TYPE = map {$_=>1} (
18854    "FUNC",
18855    "IFUNC",
18856    "OBJECT",
18857    "COMMON"
18858);
18859
18860my %ELF_VIS = map {$_=>1} (
18861    "DEFAULT",
18862    "PROTECTED"
18863);
18864
18865sub readline_ELF($)
18866{ # read the line of 'readelf' output corresponding to the symbol
18867    my @Info = split(/\s+/, $_[0]);
18868    #  Num:   Value      Size Type   Bind   Vis       Ndx  Name
18869    #  3629:  000b09c0   32   FUNC   GLOBAL DEFAULT   13   _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
18870    #  135:   00000000    0   FUNC   GLOBAL DEFAULT   UND  av_image_fill_pointers@LIBAVUTIL_52 (3)
18871    shift(@Info); # spaces
18872    shift(@Info); # num
18873
18874    if($#Info==7)
18875    { # UND SYMBOL (N)
18876        if($Info[7]=~/\(\d+\)/) {
18877            pop(@Info);
18878        }
18879    }
18880
18881    if($#Info!=6)
18882    { # other lines
18883        return ();
18884    }
18885    return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND");
18886    return () if(not defined $ELF_BIND{$Info[3]});
18887    return () if(not defined $ELF_VIS{$Info[4]});
18888    if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
18889    { # 1272: 00000000     0 OBJECT  GLOBAL DEFAULT  ABS CXXABI_1.3
18890        return ();
18891    }
18892    if($OStarget eq "symbian")
18893    { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
18894        if(index($Info[6], "_._.absent_export_")!=-1)
18895        { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
18896            return ();
18897        }
18898        $Info[6]=~s/\@.+//g; # remove version
18899    }
18900    if(index($Info[2], "0x") == 0)
18901    { # size == 0x3d158
18902        $Info[2] = hex($Info[2]);
18903    }
18904    return @Info;
18905}
18906
18907sub get_LibPath($$)
18908{
18909    my ($LibVersion, $Name) = @_;
18910    return "" if(not $LibVersion or not $Name);
18911    if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
18912        return $Cache{"get_LibPath"}{$LibVersion}{$Name};
18913    }
18914    return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
18915}
18916
18917sub get_LibPath_I($$)
18918{
18919    my ($LibVersion, $Name) = @_;
18920    if(is_abs($Name))
18921    {
18922        if(-f $Name)
18923        { # absolute path
18924            return $Name;
18925        }
18926        else
18927        { # broken
18928            return "";
18929        }
18930    }
18931    if(defined $RegisteredObjects{$LibVersion}{$Name})
18932    { # registered paths
18933        return $RegisteredObjects{$LibVersion}{$Name};
18934    }
18935    if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
18936    { # registered paths
18937        return $RegisteredSONAMEs{$LibVersion}{$Name};
18938    }
18939    if(my $DefaultPath = $DyLib_DefaultPath{$Name})
18940    { # ldconfig default paths
18941        return $DefaultPath;
18942    }
18943    foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}})
18944    { # search in default linker directories
18945      # and then in all system paths
18946        if(-f $Dir."/".$Name) {
18947            return join_P($Dir,$Name);
18948        }
18949    }
18950    if(not defined $Cache{"checkSystemFiles"}) {
18951        checkSystemFiles();
18952    }
18953    if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
18954        return $AllObjects[0];
18955    }
18956    if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
18957    {
18958        if($ShortName ne $Name)
18959        { # FIXME: check this case
18960            if(my $Path = get_LibPath($LibVersion, $ShortName)) {
18961                return $Path;
18962            }
18963        }
18964    }
18965    # can't find
18966    return "";
18967}
18968
18969sub readSymbols_Lib($$$$$$)
18970{
18971    my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
18972    return () if(not $LibVersion or not $Lib_Path);
18973
18974    my $Real_Path = realpath($Lib_Path);
18975
18976    if(not $Real_Path)
18977    { # broken link
18978        return ();
18979    }
18980
18981    my $Lib_Name = get_filename($Real_Path);
18982
18983    if($ExtraInfo)
18984    {
18985        $KnownLibs{$Real_Path} = 1;
18986        $KnownLibs{$Lib_Path} = 1; # links
18987    }
18988
18989    if($IsNeededLib)
18990    {
18991        if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
18992            return ();
18993        }
18994    }
18995    return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
18996    $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
18997
18998    if($CheckImpl)
18999    {
19000        if(not $IsNeededLib) {
19001            getImplementations($LibVersion, $Lib_Path);
19002        }
19003    }
19004
19005    push(@RecurLib, $Lib_Name);
19006    my (%Value_Interface, %Interface_Value, %NeededLib) = ();
19007    my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
19008
19009    if(not $IsNeededLib)
19010    { # special cases: libstdc++ and libc
19011        if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget))
19012        {
19013            if($ShortName eq "libstdc++")
19014            { # libstdc++.so.6
19015                $STDCXX_TESTING = 1;
19016            }
19017            elsif($ShortName eq "libc")
19018            { # libc-2.11.3.so
19019                $GLIBC_TESTING = 1;
19020            }
19021        }
19022    }
19023    my $DebugPath = "";
19024    if($Debug and not $DumpSystem)
19025    { # debug mode
19026        $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
19027        mkpath(get_dirname($DebugPath));
19028    }
19029    if($OStarget eq "macos")
19030    { # Mac OS X: *.dylib, *.a
19031        my $NM = get_CmdPath("nm");
19032        if(not $NM) {
19033            exitStatus("Not_Found", "can't find \"nm\"");
19034        }
19035        $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
19036        if($DebugPath)
19037        { # debug mode
19038          # write to file
19039            system($NM." >\"$DebugPath\"");
19040            open(LIB, $DebugPath);
19041        }
19042        else
19043        { # write to pipe
19044            open(LIB, $NM." |");
19045        }
19046        while(<LIB>)
19047        {
19048            if($CheckUndefined)
19049            {
19050                if(not $IsNeededLib)
19051                {
19052                    if(/ U _([\w\$]+)\s*\Z/)
19053                    {
19054                        $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0;
19055                        next;
19056                    }
19057                }
19058            }
19059
19060            if(/ [STD] _([\w\$]+)\s*\Z/)
19061            {
19062                my $Symbol = $1;
19063                if($IsNeededLib)
19064                {
19065                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
19066                    {
19067                        $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
19068                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
19069                    }
19070                }
19071                else
19072                {
19073                    $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
19074                    $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
19075                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
19076                    {
19077                        if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
19078                            setLanguage($LibVersion, "C++");
19079                        }
19080                    }
19081                    if($CheckObjectsOnly
19082                    and $LibVersion==1) {
19083                        $CheckedSymbols{"Binary"}{$Symbol} = 1;
19084                    }
19085                }
19086            }
19087        }
19088        close(LIB);
19089
19090        if($Deps)
19091        {
19092            if($LIB_TYPE eq "dynamic")
19093            { # dependencies
19094
19095                my $OtoolCmd = get_CmdPath("otool");
19096                if(not $OtoolCmd) {
19097                    exitStatus("Not_Found", "can't find \"otool\"");
19098                }
19099
19100                open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
19101                while(<LIB>)
19102                {
19103                    if(/\s*([\/\\].+\.$LIB_EXT)\s*/
19104                    and $1 ne $Lib_Path) {
19105                        $NeededLib{$1} = 1;
19106                    }
19107                }
19108                close(LIB);
19109            }
19110        }
19111    }
19112    elsif($OStarget eq "windows")
19113    { # Windows *.dll, *.lib
19114        my $DumpBinCmd = get_CmdPath("dumpbin");
19115        if(not $DumpBinCmd) {
19116            exitStatus("Not_Found", "can't find \"dumpbin\"");
19117        }
19118        $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
19119        if($DebugPath)
19120        { # debug mode
19121          # write to file
19122            system($DumpBinCmd." >\"$DebugPath\"");
19123            open(LIB, $DebugPath);
19124        }
19125        else
19126        { # write to pipe
19127            open(LIB, $DumpBinCmd." |");
19128        }
19129        while(<LIB>)
19130        { # 1197 4AC 0000A620 SetThreadStackGuarantee
19131          # 1198 4AD          SetThreadToken (forwarded to ...)
19132          # 3368 _o2i_ECPublicKey
19133            if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
19134            or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
19135            or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
19136            { # dynamic, static and forwarded symbols
19137                my $realname = $1;
19138                if($IsNeededLib)
19139                {
19140                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
19141                    {
19142                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
19143                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
19144                    }
19145                }
19146                else
19147                {
19148                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
19149                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
19150                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
19151                    {
19152                        if(index($realname, "_Z")==0 or index($realname, "?")==0) {
19153                            setLanguage($LibVersion, "C++");
19154                        }
19155                    }
19156                    if($CheckObjectsOnly
19157                    and $LibVersion==1) {
19158                        $CheckedSymbols{"Binary"}{$realname} = 1;
19159                    }
19160                }
19161            }
19162        }
19163        close(LIB);
19164
19165        if($Deps)
19166        {
19167            if($LIB_TYPE eq "dynamic")
19168            { # dependencies
19169                open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
19170                while(<LIB>)
19171                {
19172                    if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
19173                    and $1 ne $Lib_Path) {
19174                        $NeededLib{path_format($1, $OSgroup)} = 1;
19175                    }
19176                }
19177                close(LIB);
19178            }
19179        }
19180    }
19181    else
19182    { # Unix; *.so, *.a
19183      # Symbian: *.dso, *.lib
19184        my $ReadelfCmd = get_CmdPath("readelf");
19185        if(not $ReadelfCmd) {
19186            exitStatus("Not_Found", "can't find \"readelf\"");
19187        }
19188        my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
19189        if($DebugPath)
19190        { # debug mode
19191          # write to file
19192            system($Cmd." >\"$DebugPath\"");
19193            open(LIB, $DebugPath);
19194        }
19195        else
19196        { # write to pipe
19197            open(LIB, $Cmd." |");
19198        }
19199        my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
19200        while(<LIB>)
19201        {
19202            if($LIB_TYPE eq "dynamic")
19203            { # dynamic library specifics
19204                if(defined $symtab)
19205                {
19206                    if(index($_, "'.dynsym'")!=-1)
19207                    { # dynamic table
19208                        $symtab = undef;
19209                    }
19210                    # do nothing with symtab
19211                    next;
19212                }
19213                elsif(index($_, "'.symtab'")!=-1)
19214                { # symbol table
19215                    $symtab = 1;
19216                    next;
19217                }
19218            }
19219            if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
19220            { # read ELF entry
19221                if($Ndx eq "UND")
19222                { # ignore interfaces that are imported from somewhere else
19223                    if($CheckUndefined)
19224                    {
19225                        if(not $IsNeededLib) {
19226                            $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0;
19227                        }
19228                    }
19229                    next;
19230                }
19231                if($Bind eq "WEAK")
19232                {
19233                    $WeakSymbols{$LibVersion}{$Symbol} = 1;
19234                    if($Weak eq "-Weak")
19235                    { # skip WEAK symbols
19236                        next;
19237                    }
19238                }
19239                my $Short = $Symbol;
19240                $Short=~s/\@.+//g;
19241                if($Type eq "OBJECT")
19242                { # global data
19243                    $GlobalDataObject{$LibVersion}{$Symbol} = $Size;
19244                    $GlobalDataObject{$LibVersion}{$Short} = $Size;
19245                }
19246                if($IsNeededLib)
19247                {
19248                    if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
19249                    {
19250                        $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
19251                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
19252                    }
19253                }
19254                else
19255                {
19256                    $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
19257                    $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
19258                    if($Vers)
19259                    {
19260                        if($LIB_EXT eq "so")
19261                        { # value
19262                            $Interface_Value{$LibVersion}{$Symbol} = $Value;
19263                            $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
19264                        }
19265                    }
19266                    if($COMMON_LANGUAGE{$LibVersion} ne "C++")
19267                    {
19268                        if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
19269                            setLanguage($LibVersion, "C++");
19270                        }
19271                    }
19272                    if($CheckObjectsOnly
19273                    and $LibVersion==1) {
19274                        $CheckedSymbols{"Binary"}{$Symbol} = 1;
19275                    }
19276                }
19277            }
19278        }
19279        close(LIB);
19280
19281        if($Deps and $LIB_TYPE eq "dynamic")
19282        { # dynamic library specifics
19283            $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
19284            open(LIB, $Cmd." |");
19285
19286            while(<LIB>)
19287            {
19288                if(/NEEDED.+\[([^\[\]]+)\]/)
19289                { # dependencies:
19290                  # 0x00000001 (NEEDED) Shared library: [libc.so.6]
19291                    $NeededLib{$1} = 1;
19292                }
19293            }
19294
19295            close(LIB);
19296        }
19297    }
19298    if($Vers)
19299    {
19300        if(not $IsNeededLib and $LIB_EXT eq "so")
19301        { # get symbol versions
19302            my %Found = ();
19303
19304            # by value
19305            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
19306            {
19307                next if(index($Symbol,"\@")==-1);
19308                if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
19309                {
19310                    foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
19311                    {
19312                        if($Symbol_SameValue ne $Symbol
19313                        and index($Symbol_SameValue,"\@")==-1)
19314                        {
19315                            $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
19316                            $Found{$Symbol} = 1;
19317                            last;
19318                        }
19319                    }
19320                }
19321            }
19322
19323            # default
19324            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
19325            {
19326                next if(defined $Found{$Symbol});
19327                next if(index($Symbol,"\@\@")==-1);
19328
19329                if($Symbol=~/\A([^\@]*)\@\@/
19330                and not $SymVer{$LibVersion}{$1})
19331                {
19332                    $SymVer{$LibVersion}{$1} = $Symbol;
19333                    $Found{$Symbol} = 1;
19334                }
19335            }
19336
19337            # non-default
19338            foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
19339            {
19340                next if(defined $Found{$Symbol});
19341                next if(index($Symbol,"\@")==-1);
19342
19343                if($Symbol=~/\A([^\@]*)\@([^\@]*)/
19344                and not $SymVer{$LibVersion}{$1})
19345                {
19346                    $SymVer{$LibVersion}{$1} = $Symbol;
19347                    $Found{$Symbol} = 1;
19348                }
19349            }
19350        }
19351    }
19352    if($Deps)
19353    {
19354        foreach my $DyLib (sort keys(%NeededLib))
19355        {
19356            $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1;
19357
19358            if(my $DepPath = get_LibPath($LibVersion, $DyLib))
19359            {
19360                if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) {
19361                    readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
19362                }
19363            }
19364        }
19365    }
19366    pop(@RecurLib);
19367    return $Library_Symbol{$LibVersion};
19368}
19369
19370sub get_prefixes($)
19371{
19372    my %Prefixes = ();
19373    get_prefixes_I([$_[0]], \%Prefixes);
19374    return keys(%Prefixes);
19375}
19376
19377sub get_prefixes_I($$)
19378{
19379    foreach my $P (@{$_[0]})
19380    {
19381        my @Parts = reverse(split(/[\/\\]+/, $P));
19382        my $Name = $Parts[0];
19383        foreach (1 .. $#Parts)
19384        {
19385            $_[1]->{$Name}{$P} = 1;
19386            last if($_>4 or $Parts[$_] eq "include");
19387            $Name = $Parts[$_].$SLASH.$Name;
19388        }
19389    }
19390}
19391
19392sub checkSystemFiles()
19393{
19394    $Cache{"checkSystemFiles"} = 1;
19395
19396    my @SysHeaders = ();
19397
19398    foreach my $DevelPath (@{$SystemPaths{"lib"}})
19399    {
19400        next if(not -d $DevelPath);
19401
19402        my @Files = cmd_find($DevelPath);
19403
19404        if(not $CheckObjectsOnly)
19405        {
19406            # search for headers in /usr/lib
19407            my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files;
19408            @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers;
19409            push(@SysHeaders, @Headers);
19410        }
19411
19412        # search for libraries in /usr/lib (including symbolic links)
19413        my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files;
19414        foreach my $Path (@Libs)
19415        {
19416            my $N = get_filename($Path);
19417            $SystemObjects{$N}{$Path} = 1;
19418            $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1;
19419        }
19420    }
19421
19422    if(not $CheckObjectsOnly)
19423    {
19424        foreach my $DevelPath (@{$SystemPaths{"include"}})
19425        {
19426            next if(not -d $DevelPath);
19427            # search for all header files in the /usr/include
19428            # with or without extension (ncurses.h, QtCore, ...)
19429            push(@SysHeaders, cmd_find($DevelPath,"f"));
19430            foreach my $Link (cmd_find($DevelPath,"l"))
19431            { # add symbolic links
19432                if(-f $Link) {
19433                    push(@SysHeaders, $Link);
19434                }
19435            }
19436        }
19437        get_prefixes_I(\@SysHeaders, \%SystemHeaders);
19438    }
19439}
19440
19441sub getSOPaths($)
19442{
19443    my $LibVersion = $_[0];
19444    my @Paths = ();
19445    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
19446    {
19447        if(not -e $Dest) {
19448            exitStatus("Access_Error", "can't access \'$Dest\'");
19449        }
19450        $Dest = get_abs_path($Dest);
19451        my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
19452        foreach (@SoPaths_Dest) {
19453            push(@Paths, $_);
19454        }
19455    }
19456    return sort @Paths;
19457}
19458
19459sub skipLib($$)
19460{
19461    my ($Path, $LibVersion) = @_;
19462    return 1 if(not $Path or not $LibVersion);
19463    my $Name = get_filename($Path);
19464    if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
19465        return 1;
19466    }
19467    my $ShortName = parse_libname($Name, "name+ext", $OStarget);
19468    if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
19469        return 1;
19470    }
19471    foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
19472    {
19473        if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
19474            return 1;
19475        }
19476    }
19477    foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
19478    {
19479        if($Name=~/$P/) {
19480            return 1;
19481        }
19482        if($P=~/[\/\\]/ and $Path=~/$P/) {
19483            return 1;
19484        }
19485    }
19486    return 0;
19487}
19488
19489sub specificHeader($$)
19490{
19491    my ($Header, $Spec) = @_;
19492    my $Name = get_filename($Header);
19493
19494    if($Spec eq "windows")
19495    {# MS Windows
19496        return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i);
19497        return 1 if($Name=~/([._-]w|win)(32|64)/i);
19498        return 1 if($Name=~/\A(Win|Windows)[A-Z]/);
19499        return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i);
19500        my @Dirs = (
19501            "win32",
19502            "win64",
19503            "win",
19504            "windows",
19505            "msvcrt"
19506        ); # /gsf-win32/
19507        if(my $DIRs = join("|", @Dirs)) {
19508            return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
19509        }
19510    }
19511    elsif($Spec eq "macos")
19512    { # Mac OS
19513        return 1 if($Name=~/(\A|[_-])mac[._-]/i);
19514    }
19515
19516    return 0;
19517}
19518
19519sub skipAlienHeader($)
19520{
19521    my $Path = $_[0];
19522    my $Name = get_filename($Path);
19523    my $Dir = get_dirname($Path);
19524
19525    if($Tolerance=~/2/)
19526    { # 2 - skip internal headers
19527        my @Terms = (
19528            "p",
19529            "priv",
19530            "int",
19531            "impl",
19532            "implementation",
19533            "internal",
19534            "private",
19535            "old",
19536            "compat",
19537            "debug",
19538            "test",
19539            "gen"
19540        );
19541
19542        my @Dirs = (
19543            "private",
19544            "priv",
19545            "port",
19546            "impl",
19547            "internal",
19548            "detail",
19549            "details",
19550            "old",
19551            "compat",
19552            "debug",
19553            "config",
19554            "compiler",
19555            "platform",
19556            "test"
19557        );
19558
19559        if(my $TERMs = join("|", @Terms)) {
19560            return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i);
19561        }
19562        if(my $DIRs = join("|", @Dirs)) {
19563            return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i);
19564        }
19565
19566        return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/);
19567    }
19568
19569    if($Tolerance=~/1/)
19570    { # 1 - skip non-Linux headers
19571        if($OSgroup ne "windows")
19572        {
19573            if(specificHeader($Path, "windows")) {
19574                return 1;
19575            }
19576        }
19577        if($OSgroup ne "macos")
19578        {
19579            if(specificHeader($Path, "macos")) {
19580                return 1;
19581            }
19582        }
19583    }
19584
19585    # valid
19586    return 0;
19587}
19588
19589sub skipHeader($$)
19590{
19591    my ($Path, $LibVersion) = @_;
19592    return 1 if(not $Path or not $LibVersion);
19593    if(defined $Cache{"skipHeader"}{$Path}) {
19594        return $Cache{"skipHeader"}{$Path};
19595    }
19596    if(defined $Tolerance and $Tolerance=~/1|2/)
19597    { # --tolerant
19598        if(skipAlienHeader($Path)) {
19599            return ($Cache{"skipHeader"}{$Path} = 1);
19600        }
19601    }
19602    if(not keys(%{$SkipHeaders{$LibVersion}})) {
19603        return 0;
19604    }
19605    return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
19606}
19607
19608sub skipHeader_I($$)
19609{ # returns:
19610  #  1 - if header should NOT be included and checked
19611  #  2 - if header should NOT be included, but should be checked
19612    my ($Path, $LibVersion) = @_;
19613    my $Name = get_filename($Path);
19614    if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
19615        return $Kind;
19616    }
19617    foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}}
19618    keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
19619    {
19620        if(index($Path, $D)!=-1)
19621        {
19622            if($Path=~/\Q$D\E([\/\\]|\Z)/) {
19623                return $SkipHeaders{$LibVersion}{"Path"}{$D};
19624            }
19625        }
19626    }
19627    foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}}
19628    keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
19629    {
19630        if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
19631        {
19632            if($Name=~/$P/) {
19633                return $Kind;
19634            }
19635            if($P=~/[\/\\]/ and $Path=~/$P/) {
19636                return $Kind;
19637            }
19638        }
19639    }
19640
19641    return 0;
19642}
19643
19644sub registerObject_Dir($$)
19645{
19646    my ($Dir, $LibVersion) = @_;
19647    if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}})
19648    { # system directory
19649        return;
19650    }
19651    if($RegisteredObject_Dirs{$LibVersion}{$Dir})
19652    { # already registered
19653        return;
19654    }
19655    foreach my $Path (find_libs($Dir,"",1))
19656    {
19657        next if(ignore_path($Path));
19658        next if(skipLib($Path, $LibVersion));
19659        registerObject($Path, $LibVersion);
19660    }
19661    $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
19662}
19663
19664sub registerObject($$)
19665{
19666    my ($Path, $LibVersion) = @_;
19667    my $Name = get_filename($Path);
19668    $RegisteredObjects{$LibVersion}{$Name} = $Path;
19669    if($OSgroup=~/linux|bsd/i)
19670    {
19671        if(my $SONAME = getSONAME($Path)) {
19672            $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
19673        }
19674    }
19675    if(my $Short = parse_libname($Name, "name+ext", $OStarget)) {
19676        $RegisteredObjects_Short{$LibVersion}{$Short} = $Path;
19677    }
19678}
19679
19680sub getSONAME($)
19681{
19682    my $Path = $_[0];
19683    return if(not $Path);
19684    if(defined $Cache{"getSONAME"}{$Path}) {
19685        return $Cache{"getSONAME"}{$Path};
19686    }
19687    my $ObjdumpCmd = get_CmdPath("objdump");
19688    if(not $ObjdumpCmd) {
19689        exitStatus("Not_Found", "can't find \"objdump\"");
19690    }
19691    my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
19692    if($OSgroup eq "windows") {
19693        $SonameCmd .= " | find \"SONAME\"";
19694    }
19695    else {
19696        $SonameCmd .= " | grep SONAME";
19697    }
19698    if(my $SonameInfo = `$SonameCmd`) {
19699        if($SonameInfo=~/SONAME\s+([^\s]+)/) {
19700            return ($Cache{"getSONAME"}{$Path} = $1);
19701        }
19702    }
19703    return ($Cache{"getSONAME"}{$Path}="");
19704}
19705
19706sub getSOPaths_Dest($$)
19707{
19708    my ($Dest, $LibVersion) = @_;
19709    if(skipLib($Dest, $LibVersion)) {
19710        return ();
19711    }
19712    if(-f $Dest)
19713    {
19714        if(not parse_libname($Dest, "name", $OStarget)) {
19715            exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
19716        }
19717        registerObject($Dest, $LibVersion);
19718        registerObject_Dir(get_dirname($Dest), $LibVersion);
19719        return ($Dest);
19720    }
19721    elsif(-d $Dest)
19722    {
19723        $Dest=~s/[\/\\]+\Z//g;
19724        my %Libs = ();
19725        if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}})
19726        { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
19727          # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
19728            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2))
19729            { # all files and symlinks that match the name of a library
19730                if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
19731                {
19732                    registerObject($Path, $LibVersion);
19733                    $Libs{realpath($Path)}=1;
19734                }
19735            }
19736        }
19737        else
19738        { # search for all files and symlinks
19739            foreach my $Path (find_libs($Dest,"",""))
19740            {
19741                next if(ignore_path($Path));
19742                next if(skipLib($Path, $LibVersion));
19743                registerObject($Path, $LibVersion);
19744                $Libs{realpath($Path)}=1;
19745            }
19746            if($OSgroup eq "macos")
19747            { # shared libraries on MacOS X may have no extension
19748                foreach my $Path (cmd_find($Dest,"f"))
19749                {
19750                    next if(ignore_path($Path));
19751                    next if(skipLib($Path, $LibVersion));
19752                    if(get_filename($Path)!~/\./
19753                    and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
19754                    {
19755                        registerObject($Path, $LibVersion);
19756                        $Libs{realpath($Path)}=1;
19757                    }
19758                }
19759            }
19760        }
19761        return keys(%Libs);
19762    }
19763    else {
19764        return ();
19765    }
19766}
19767
19768sub isCyclical($$)
19769{
19770    my ($Stack, $Value) = @_;
19771    return (grep {$_ eq $Value} @{$Stack});
19772}
19773
19774sub detectWordSize()
19775{
19776    return "" if(not $GCC_PATH);
19777    if($Cache{"detectWordSize"}) {
19778        return $Cache{"detectWordSize"};
19779    }
19780    writeFile("$TMP_DIR/empty.h", "");
19781    my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
19782    unlink("$TMP_DIR/empty.h");
19783    my $WSize = 0;
19784    if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
19785    { # GCC 4
19786        $WSize = $1;
19787    }
19788    elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
19789    { # GCC 3
19790        my $PTRDIFF = $1;
19791        if($PTRDIFF=~/long/) {
19792            $WSize = "8";
19793        }
19794        else {
19795            $WSize = "4";
19796        }
19797    }
19798    if(not $WSize) {
19799        exitStatus("Error", "can't check WORD size");
19800    }
19801    return ($Cache{"detectWordSize"} = $WSize);
19802}
19803
19804sub getWordSize($) {
19805    return $WORD_SIZE{$_[0]};
19806}
19807
19808sub majorVersion($)
19809{
19810    my $V = $_[0];
19811    return 0 if(not $V);
19812    my @VParts = split(/\./, $V);
19813    return $VParts[0];
19814}
19815
19816sub cmpVersions($$)
19817{ # compare two versions in dotted-numeric format
19818    my ($V1, $V2) = @_;
19819    return 0 if($V1 eq $V2);
19820    my @V1Parts = split(/\./, $V1);
19821    my @V2Parts = split(/\./, $V2);
19822    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++)
19823    {
19824        return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
19825        return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
19826    }
19827    return -1 if($#V1Parts < $#V2Parts);
19828    return 1 if($#V1Parts > $#V2Parts);
19829    return 0;
19830}
19831
19832sub read_ABI_Dump($$)
19833{
19834    my ($LibVersion, $Path) = @_;
19835    return if(not $LibVersion or not -e $Path);
19836    my $FilePath = "";
19837    if(isDump_U($Path))
19838    { # input *.abi
19839        $FilePath = $Path;
19840    }
19841    else
19842    { # input *.abi.tar.gz
19843        $FilePath = unpackDump($Path);
19844        if(not isDump_U($FilePath)) {
19845            exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
19846        }
19847    }
19848
19849    my $ABI = {};
19850
19851    my $Line = readLineNum($FilePath, 0);
19852    if($Line=~/xml/)
19853    { # XML format
19854        loadModule("XmlDump");
19855        $ABI = readXmlDump($FilePath);
19856    }
19857    else
19858    { # Perl Data::Dumper format (default)
19859        open(DUMP, $FilePath);
19860        local $/ = undef;
19861        my $Content = <DUMP>;
19862        close(DUMP);
19863
19864        if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
19865        { # remove temp file
19866            unlink($FilePath);
19867        }
19868        if($Content!~/};\s*\Z/) {
19869            exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
19870        }
19871        $ABI = eval($Content);
19872        if(not $ABI) {
19873            exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
19874        }
19875    }
19876    # new dumps (>=1.22) have a personal versioning
19877    my $DVersion = $ABI->{"ABI_DUMP_VERSION"};
19878    my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
19879    if(not $DVersion)
19880    { # old dumps (<=1.21.6) have been marked by the tool version
19881        $DVersion = $ToolVersion;
19882    }
19883    $UsedDump{$LibVersion}{"V"} = $DVersion;
19884
19885    if($ABI->{"ABI_DUMP_VERSION"})
19886    {
19887        if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0)
19888        { # Don't know how to parse future dump formats
19889            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
19890        }
19891    }
19892    else
19893    { # support for old ABI dumps
19894        if(cmpVersions($DVersion, $TOOL_VERSION)>0)
19895        { # Don't know how to parse future dump formats
19896            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
19897        }
19898    }
19899    if(majorVersion($DVersion)<2)
19900    { # support for old ABI dumps
19901        if($UseOldDumps)
19902        {
19903            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) {
19904                exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
19905            }
19906        }
19907        else
19908        {
19909            my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)";
19910            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
19911                $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0)";
19912            }
19913            exitStatus("Dump_Version", $Msg);
19914        }
19915    }
19916
19917    if(defined $ABI->{"ABI_DUMPER_VERSION"})
19918    { # DWARF ABI Dump
19919        $UseConv_Real{$LibVersion}{"P"} = 1;
19920        $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet
19921
19922        $UsedDump{$LibVersion}{"DWARF"} = 1;
19923
19924        $TargetComponent = "module";
19925    }
19926
19927    if(not checkDump($LibVersion, "2.11"))
19928    { # old ABI dumps
19929        $UsedDump{$LibVersion}{"BinOnly"} = 1;
19930    }
19931    elsif($ABI->{"BinOnly"})
19932    { # ABI dump created with --binary option
19933        $UsedDump{$LibVersion}{"BinOnly"} = 1;
19934    }
19935    else
19936    { # default
19937        $UsedDump{$LibVersion}{"SrcBin"} = 1;
19938    }
19939
19940    if(defined $ABI->{"Mode"}
19941    and $ABI->{"Mode"} eq "Extended")
19942    { # --ext option
19943        $ExtendedCheck = 1;
19944    }
19945    if($ABI->{"Extra"}) {
19946        $ExtraDump = 1;
19947    }
19948
19949    if(my $Lang = $ABI->{"Language"})
19950    {
19951        $UsedDump{$LibVersion}{"L"} = $Lang;
19952        setLanguage($LibVersion, $Lang);
19953    }
19954    if(checkDump($LibVersion, "2.15")) {
19955        $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
19956    }
19957    else
19958    { # support for old ABI dumps
19959        my $TInfo = $ABI->{"TypeInfo"};
19960        if(not $TInfo)
19961        { # support for older ABI dumps
19962            $TInfo = $ABI->{"TypeDescr"};
19963        }
19964        my %Tid_TDid = ();
19965        foreach my $TDid (keys(%{$TInfo}))
19966        {
19967            foreach my $Tid (keys(%{$TInfo->{$TDid}}))
19968            {
19969                $MAX_ID = $Tid if($Tid>$MAX_ID);
19970                $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
19971                $Tid_TDid{$Tid}{$TDid} = 1;
19972            }
19973        }
19974        my %NewID = ();
19975        foreach my $Tid (keys(%Tid_TDid))
19976        {
19977            my @TDids = keys(%{$Tid_TDid{$Tid}});
19978            if($#TDids>=1)
19979            {
19980                foreach my $TDid (@TDids)
19981                {
19982                    if($TDid) {
19983                        %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
19984                    }
19985                    else
19986                    {
19987                        my $ID = ++$MAX_ID;
19988
19989                        $NewID{$TDid}{$Tid} = $ID;
19990                        %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
19991                        $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
19992                    }
19993                }
19994            }
19995            else
19996            {
19997                my $TDid = $TDids[0];
19998                %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
19999            }
20000        }
20001        foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
20002        {
20003            my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
20004            if(defined $Info{"BaseType"})
20005            {
20006                my $Bid = $Info{"BaseType"}{"Tid"};
20007                my $BDid = $Info{"BaseType"}{"TDid"};
20008                $BDid="" if(not defined $BDid);
20009                delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
20010                if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
20011                    $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID;
20012                }
20013            }
20014            delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
20015        }
20016    }
20017    read_Machine_DumpInfo($ABI, $LibVersion);
20018    $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
20019    if(not $SymbolInfo{$LibVersion})
20020    { # support for old dumps
20021        $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
20022    }
20023    if(not keys(%{$SymbolInfo{$LibVersion}}))
20024    { # validation of old-version dumps
20025        if(not $ExtendedCheck) {
20026            exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
20027        }
20028    }
20029    if(checkDump($LibVersion, "2.15")) {
20030        $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
20031    }
20032    else
20033    { # support for old ABI dumps
20034        my $DepSymbols = $ABI->{"DepSymbols"};
20035        if(not $DepSymbols) {
20036            $DepSymbols = $ABI->{"DepInterfaces"};
20037        }
20038        if(not $DepSymbols)
20039        { # Cannot reconstruct DepSymbols. This may result in false
20040          # positives if the old dump is for library 2. Not a problem if
20041          # old dumps are only from old libraries.
20042            $DepSymbols = {};
20043        }
20044        foreach my $Symbol (keys(%{$DepSymbols})) {
20045            $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
20046        }
20047    }
20048    $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
20049    $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
20050    $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
20051    if(not $SkipTypes{$LibVersion})
20052    { # support for old dumps
20053        $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
20054    }
20055    $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
20056    if(not $SkipSymbols{$LibVersion})
20057    { # support for old dumps
20058        $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
20059    }
20060    if(not $SkipSymbols{$LibVersion})
20061    { # support for old dumps
20062        $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
20063    }
20064    $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
20065    $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
20066    foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
20067    {
20068        $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
20069        my ($CPath, $Type) = classifyPath($Path);
20070        $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
20071    }
20072    read_Source_DumpInfo($ABI, $LibVersion);
20073    read_Libs_DumpInfo($ABI, $LibVersion);
20074    if(not checkDump($LibVersion, "2.10.1")
20075    or not $TargetHeaders{$LibVersion})
20076    { # support for old ABI dumps: added target headers
20077        foreach (keys(%{$Registered_Headers{$LibVersion}})) {
20078            $TargetHeaders{$LibVersion}{get_filename($_)} = 1;
20079        }
20080        foreach (keys(%{$Registered_Sources{$LibVersion}})) {
20081            $TargetHeaders{$LibVersion}{get_filename($_)} = 1;
20082        }
20083    }
20084    $Constants{$LibVersion} = $ABI->{"Constants"};
20085    if(defined $ABI->{"GccConstants"})
20086    { # 3.0
20087        foreach my $Name (keys(%{$ABI->{"GccConstants"}})) {
20088            $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name};
20089        }
20090    }
20091
20092    $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
20093    if(not $NestedNameSpaces{$LibVersion})
20094    { # support for old dumps
20095      # Cannot reconstruct NameSpaces. This may affect design
20096      # of the compatibility report.
20097        $NestedNameSpaces{$LibVersion} = {};
20098    }
20099    # target system type
20100    # needed to adopt HTML report
20101    if(not $DumpSystem)
20102    { # to use in createSymbolsList(...)
20103        $OStarget = $ABI->{"Target"};
20104    }
20105    # recreate environment
20106    foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
20107    {
20108        foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
20109        {
20110            $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
20111            if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
20112            { # data marked as -size in the dump
20113                $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol};
20114            }
20115            if($COMMON_LANGUAGE{$LibVersion} ne "C++")
20116            {
20117                if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
20118                    setLanguage($LibVersion, "C++");
20119                }
20120            }
20121        }
20122    }
20123    foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
20124    {
20125        foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
20126            $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
20127        }
20128    }
20129
20130    my @VFunc = ();
20131    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
20132    {
20133        if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
20134        {
20135            if(not $Symbol_Library{$LibVersion}{$MnglName}
20136            and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
20137                push(@VFunc, $MnglName);
20138            }
20139        }
20140    }
20141    translateSymbols(@VFunc, $LibVersion);
20142    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
20143    translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
20144
20145    if(not checkDump($LibVersion, "3.0"))
20146    { # support for old ABI dumps
20147        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
20148        {
20149            if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"})
20150            {
20151                if(ref($BaseType) eq "HASH") {
20152                    $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"};
20153                }
20154            }
20155        }
20156    }
20157
20158    if(not checkDump($LibVersion, "3.2"))
20159    { # support for old ABI dumps
20160        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
20161        {
20162            if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"})
20163            {
20164                foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) {
20165                    $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset});
20166                }
20167            }
20168        }
20169
20170        # repair target headers list
20171        delete($TargetHeaders{$LibVersion});
20172        foreach (keys(%{$Registered_Headers{$LibVersion}})) {
20173            $TargetHeaders{$LibVersion}{get_filename($_)} = 1;
20174        }
20175        foreach (keys(%{$Registered_Sources{$LibVersion}})) {
20176            $TargetHeaders{$LibVersion}{get_filename($_)} = 1;
20177        }
20178
20179        # non-target constants from anon enums
20180        foreach my $Name (keys(%{$Constants{$LibVersion}}))
20181        {
20182            if(not $ExtraDump
20183            and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion))
20184            {
20185                delete($Constants{$LibVersion}{$Name});
20186            }
20187        }
20188    }
20189
20190    if(not checkDump($LibVersion, "2.20"))
20191    { # support for old ABI dumps
20192        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
20193        {
20194            my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"};
20195
20196            if($TType=~/Struct|Union|Enum|Typedef/)
20197            { # repair complex types first
20198                next;
20199            }
20200
20201            if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"})
20202            {
20203                my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"});
20204                if($BType=~/Struct|Union|Enum/i)
20205                {
20206                    my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"};
20207                    $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g;
20208                }
20209            }
20210        }
20211        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
20212        {
20213            my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"};
20214            my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
20215            if($TType=~/Struct|Union|Enum/) {
20216                $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName;
20217            }
20218        }
20219    }
20220
20221    foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
20222    { # order is important
20223        if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
20224        { # support for old ABI dumps < 2.0 (ACC 1.22)
20225            foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
20226            {
20227                if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
20228                {
20229                    if($Access ne "public") {
20230                        $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
20231                    }
20232                }
20233                $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
20234            }
20235            delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
20236        }
20237        if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
20238        { # support for old ABI dumps
20239            $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
20240        }
20241        elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"})
20242        { # DWARF ABI Dumps
20243            $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source;
20244        }
20245        if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
20246            $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
20247        }
20248        my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
20249        if(defined $TInfo{"Base"})
20250        {
20251            foreach (keys(%{$TInfo{"Base"}})) {
20252                $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
20253            }
20254        }
20255        if($TInfo{"Type"} eq "MethodPtr")
20256        {
20257            if(defined $TInfo{"Param"})
20258            { # support for old ABI dumps <= 1.17
20259                if(not defined $TInfo{"Param"}{"0"})
20260                {
20261                    my $Max = keys(%{$TInfo{"Param"}});
20262                    foreach my $Pos (1 .. $Max) {
20263                        $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
20264                    }
20265                    delete($TInfo{"Param"}{$Max});
20266                    %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
20267                }
20268            }
20269        }
20270        if($TInfo{"BaseType"} eq $TypeId)
20271        { # fix ABI dump
20272            delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"});
20273        }
20274        if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"})
20275        {
20276            if(my $BTid = $TInfo{"BaseType"})
20277            {
20278                my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
20279                if(not $BName)
20280                { # broken type
20281                    next;
20282                }
20283                if($TInfo{"Name"} eq $BName)
20284                { # typedef to "class Class"
20285                  # should not be registered in TName_Tid
20286                    next;
20287                }
20288                if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
20289                    $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
20290                }
20291            }
20292        }
20293        if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
20294        { # classes: class (id1), typedef (artificial, id2 > id1)
20295            $TName_Tid{$LibVersion}{formatName($TInfo{"Name"}, "T")} = $TypeId;
20296        }
20297    }
20298
20299    if(not checkDump($LibVersion, "2.15"))
20300    { # support for old ABI dumps
20301        my %Dups = ();
20302        foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
20303        {
20304            if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
20305            {
20306                if(not defined $TypeInfo{$LibVersion}{$ClassId})
20307                { # remove template decls
20308                    delete($SymbolInfo{$LibVersion}{$InfoId});
20309                    next;
20310                }
20311            }
20312            my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
20313            if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
20314            { # templates
20315                delete($SymbolInfo{$LibVersion}{$InfoId});
20316            }
20317        }
20318    }
20319
20320    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
20321    {
20322        if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
20323        and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"}
20324        and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
20325        { # support for old ABI dumps (< 3.1)
20326            if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
20327            or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this")
20328            { # add "this" first parameter
20329                my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion);
20330                my %PInfo = ("name"=>"this", "type"=>"$ThisTid");
20331
20332                if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
20333                {
20334                    my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
20335                    foreach my $Pos (reverse(0 .. $#Pos)) {
20336                        %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}};
20337                    }
20338                }
20339                $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo;
20340            }
20341        }
20342
20343        if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
20344        { # ABI dumps have no mangled names for C-functions
20345            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
20346        }
20347        if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
20348        { # support for old ABI dumps
20349            $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
20350        }
20351        elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"})
20352        { # DWARF ABI Dumps
20353            $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source;
20354        }
20355    }
20356
20357    $Descriptor{$LibVersion}{"Dump"} = 1;
20358}
20359
20360sub read_Machine_DumpInfo($$)
20361{
20362    my ($ABI, $LibVersion) = @_;
20363    if($ABI->{"Arch"}) {
20364        $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
20365    }
20366    if($ABI->{"WordSize"}) {
20367        $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
20368    }
20369    else
20370    { # support for old dumps
20371        $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
20372    }
20373    if(not $WORD_SIZE{$LibVersion})
20374    { # support for old dumps (<1.23)
20375        if(my $Tid = getTypeIdByName("char*", $LibVersion))
20376        { # size of char*
20377            $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
20378        }
20379        else
20380        {
20381            my $PSize = 0;
20382            foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
20383            {
20384                if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
20385                { # any "pointer"-type
20386                    $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
20387                    last;
20388                }
20389            }
20390            if($PSize)
20391            { # a pointer type size
20392                $WORD_SIZE{$LibVersion} = $PSize;
20393            }
20394            else {
20395                printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
20396            }
20397        }
20398    }
20399    if($ABI->{"GccVersion"}) {
20400        $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
20401    }
20402}
20403
20404sub read_Libs_DumpInfo($$)
20405{
20406    my ($ABI, $LibVersion) = @_;
20407    $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
20408    if(not $Library_Symbol{$LibVersion})
20409    { # support for old dumps
20410        $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
20411    }
20412    if(keys(%{$Library_Symbol{$LibVersion}})
20413    and not $DumpAPI) {
20414        $Descriptor{$LibVersion}{"Libs"} = "OK";
20415    }
20416}
20417
20418sub read_Source_DumpInfo($$)
20419{
20420    my ($ABI, $LibVersion) = @_;
20421
20422    if(keys(%{$ABI->{"Headers"}})
20423    and not $DumpAPI) {
20424        $Descriptor{$LibVersion}{"Headers"} = "OK";
20425    }
20426    foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
20427    { # headers info is stored in the old dumps in the different way
20428        if($UseOldDumps
20429        and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
20430        { # support for old dumps: headers info corrected in 1.22
20431            $Identity = $Name;
20432        }
20433        $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
20434        $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
20435    }
20436
20437    if(keys(%{$ABI->{"Sources"}})
20438    and not $DumpAPI) {
20439        $Descriptor{$LibVersion}{"Sources"} = "OK";
20440    }
20441    foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}}))
20442    { # headers info is stored in the old dumps in the different way
20443        $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name;
20444        $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name};
20445    }
20446}
20447
20448sub find_libs($$$)
20449{
20450    my ($Path, $Type, $MaxDepth) = @_;
20451    # FIXME: correct the search pattern
20452    return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1);
20453}
20454
20455sub createDescriptor($$)
20456{
20457    my ($LibVersion, $Path) = @_;
20458    if(not $LibVersion or not $Path
20459    or not -e $Path) {
20460        return "";
20461    }
20462    if(-d $Path)
20463    { # directory with headers files and shared objects
20464        return "
20465            <version>
20466                ".$TargetVersion{$LibVersion}."
20467            </version>
20468
20469            <headers>
20470                $Path
20471            </headers>
20472
20473            <libs>
20474                $Path
20475            </libs>";
20476    }
20477    else
20478    { # files
20479        if($Path=~/\.(xml|desc)\Z/i)
20480        { # standard XML-descriptor
20481            return readFile($Path);
20482        }
20483        elsif(is_header($Path, 2, $LibVersion))
20484        { # header file
20485            return "
20486                <version>
20487                    ".$TargetVersion{$LibVersion}."
20488                </version>
20489
20490                <headers>
20491                    $Path
20492                </headers>
20493
20494                <libs>
20495                    none
20496                </libs>";
20497        }
20498        elsif(parse_libname($Path, "name", $OStarget))
20499        { # shared object
20500            return "
20501                <version>
20502                    ".$TargetVersion{$LibVersion}."
20503                </version>
20504
20505                <headers>
20506                    none
20507                </headers>
20508
20509                <libs>
20510                    $Path
20511                </libs>";
20512        }
20513        else
20514        { # standard XML-descriptor
20515            return readFile($Path);
20516        }
20517    }
20518}
20519
20520sub detect_lib_default_paths()
20521{
20522    my %LPaths = ();
20523    if($OSgroup eq "bsd")
20524    {
20525        if(my $LdConfig = get_CmdPath("ldconfig"))
20526        {
20527            foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
20528            {
20529                if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/)
20530                {
20531                    my $Name = "lib".$1;
20532                    if(not defined $LPaths{$Name}) {
20533                        $LPaths{$Name} = $2;
20534                    }
20535                }
20536            }
20537        }
20538        else {
20539            printMsg("WARNING", "can't find ldconfig");
20540        }
20541    }
20542    else
20543    {
20544        if(my $LdConfig = get_CmdPath("ldconfig"))
20545        {
20546            if($SystemRoot and $OSgroup eq "linux")
20547            { # use host (x86) ldconfig with the target (arm) ld.so.conf
20548                if(-e $SystemRoot."/etc/ld.so.conf") {
20549                    $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
20550                }
20551            }
20552            foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
20553            {
20554                if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
20555                {
20556                    my ($Name, $Path) = ($1, $2);
20557                    $Path=~s/[\/]{2,}/\//;
20558                    if(not defined $LPaths{$Name})
20559                    { # get first element from the list of available paths
20560
20561                      # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
20562                      # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6
20563                      # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6
20564
20565                        $LPaths{$Name} = $Path;
20566                    }
20567                }
20568            }
20569        }
20570        elsif($OSgroup eq "linux") {
20571            printMsg("WARNING", "can't find ldconfig");
20572        }
20573    }
20574    return \%LPaths;
20575}
20576
20577sub detect_bin_default_paths()
20578{
20579    my $EnvPaths = $ENV{"PATH"};
20580    if($OSgroup eq "beos") {
20581        $EnvPaths.=":".$ENV{"BETOOLS"};
20582    }
20583    my $Sep = ($OSgroup eq "windows")?";":":|;";
20584    foreach my $Path (split(/$Sep/, $EnvPaths))
20585    {
20586        $Path = path_format($Path, $OSgroup);
20587        next if(not $Path);
20588        if($SystemRoot
20589        and $Path=~/\A\Q$SystemRoot\E\//)
20590        { # do NOT use binaries from target system
20591            next;
20592        }
20593        push_U(\@DefaultBinPaths, $Path);
20594    }
20595}
20596
20597sub detect_inc_default_paths()
20598{
20599    return () if(not $GCC_PATH);
20600    my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]);
20601    writeFile("$TMP_DIR/empty.h", "");
20602    foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
20603    { # detecting GCC default include paths
20604        next if(index($Line, "/cc1plus ")!=-1);
20605
20606        if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
20607        {
20608            my $Path = realpath($1);
20609            $Path = path_format($Path, $OSgroup);
20610            if(index($Path, "c++")!=-1
20611            or index($Path, "/g++/")!=-1)
20612            {
20613                push_U($DPaths{"Cpp"}, $Path);
20614                if(not defined $MAIN_CPP_DIR
20615                or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
20616                    $MAIN_CPP_DIR = $Path;
20617                }
20618            }
20619            elsif(index($Path, "gcc")!=-1) {
20620                push_U($DPaths{"Gcc"}, $Path);
20621            }
20622            else
20623            {
20624                if($Path=~/local[\/\\]+include/)
20625                { # local paths
20626                    next;
20627                }
20628                if($SystemRoot
20629                and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
20630                { # The GCC include path for user headers is not a part of the system root
20631                  # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
20632                  # or it is the internal cross-GCC path like arm-linux-gnueabi/include
20633                    next;
20634                }
20635                push_U($DPaths{"Inc"}, $Path);
20636            }
20637        }
20638    }
20639    unlink("$TMP_DIR/empty.h");
20640    return %DPaths;
20641}
20642
20643sub detect_default_paths($)
20644{
20645    my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
20646    my $Search = $_[0];
20647    if($Search!~/inc/) {
20648        $HSearch = 0;
20649    }
20650    if($Search!~/lib/) {
20651        $LSearch = 0;
20652    }
20653    if($Search!~/bin/) {
20654        $BSearch = 0;
20655    }
20656    if($Search!~/gcc/) {
20657        $GSearch = 0;
20658    }
20659    if(@{$SystemPaths{"include"}})
20660    { # <search_headers> section of the XML descriptor
20661      # do NOT search for systems headers
20662        $HSearch = 0;
20663    }
20664    if(@{$SystemPaths{"lib"}})
20665    { # <search_headers> section of the XML descriptor
20666      # do NOT search for systems headers
20667        $LSearch = 0;
20668    }
20669    foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
20670    { # additional search paths
20671        next if($Type eq "include" and not $HSearch);
20672        next if($Type eq "lib" and not $LSearch);
20673        next if($Type eq "bin" and not $BSearch);
20674        push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}});
20675    }
20676    if($OSgroup ne "windows")
20677    { # unix-like
20678        foreach my $Type ("include", "lib", "bin")
20679        { # automatic detection of system "devel" directories
20680            next if($Type eq "include" and not $HSearch);
20681            next if($Type eq "lib" and not $LSearch);
20682            next if($Type eq "bin" and not $BSearch);
20683            my ($UsrDir, $RootDir) = ("/usr", "/");
20684            if($SystemRoot and $Type ne "bin")
20685            { # 1. search for target headers and libraries
20686              # 2. use host commands: ldconfig, readelf, etc.
20687                ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
20688            }
20689            push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1));
20690            if(-d $RootDir."/".$Type)
20691            { # if "/lib" is symbolic link
20692                if($RootDir eq "/") {
20693                    push_U($SystemPaths{$Type}, "/".$Type);
20694                }
20695                else {
20696                    push_U($SystemPaths{$Type}, $RootDir."/".$Type);
20697                }
20698            }
20699            if(-d $UsrDir)
20700            {
20701                push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1));
20702                if(-d $UsrDir."/".$Type)
20703                { # if "/usr/lib" is symbolic link
20704                    push_U($SystemPaths{$Type}, $UsrDir."/".$Type);
20705                }
20706            }
20707        }
20708    }
20709    if($BSearch)
20710    {
20711        detect_bin_default_paths();
20712        push_U($SystemPaths{"bin"}, @DefaultBinPaths);
20713    }
20714    # check environment variables
20715    if($OSgroup eq "beos")
20716    {
20717        foreach (my @Paths = @{$SystemPaths{"bin"}})
20718        {
20719            if($_ eq ".") {
20720                next;
20721            }
20722            # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
20723            if(my @Dirs = sort cmd_find($_, "d", "bin")) {
20724                push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs);
20725            }
20726        }
20727        if($HSearch)
20728        {
20729            push_U(\@DefaultIncPaths, grep { is_abs($_) } (
20730                split(/:|;/, $ENV{"BEINCLUDES"})
20731                ));
20732        }
20733        if($LSearch)
20734        {
20735            push_U(\@DefaultLibPaths, grep { is_abs($_) } (
20736                split(/:|;/, $ENV{"BELIBRARIES"}),
20737                split(/:|;/, $ENV{"LIBRARY_PATH"})
20738                ));
20739        }
20740    }
20741    if($LSearch)
20742    { # using linker to get system paths
20743        if(my $LPaths = detect_lib_default_paths())
20744        { # unix-like
20745            my %Dirs = ();
20746            foreach my $Name (keys(%{$LPaths}))
20747            {
20748                if($SystemRoot
20749                and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
20750                { # wrong ldconfig configuration
20751                  # check your <sysroot>/etc/ld.so.conf
20752                    next;
20753                }
20754                $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
20755                if(my $Dir = get_dirname($LPaths->{$Name})) {
20756                    $Dirs{$Dir} = 1;
20757                }
20758            }
20759            push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs));
20760        }
20761        push_U($SystemPaths{"lib"}, @DefaultLibPaths);
20762    }
20763    if($BSearch)
20764    {
20765        if($CrossGcc)
20766        { # --cross-gcc=arm-linux-gcc
20767            if(-e $CrossGcc)
20768            { # absolute or relative path
20769                $GCC_PATH = get_abs_path($CrossGcc);
20770            }
20771            elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
20772            { # command name
20773                $GCC_PATH = $CrossGcc;
20774            }
20775            else {
20776                exitStatus("Access_Error", "can't access \'$CrossGcc\'");
20777            }
20778            if($GCC_PATH=~/\s/) {
20779                $GCC_PATH = "\"".$GCC_PATH."\"";
20780            }
20781        }
20782    }
20783    if($GSearch)
20784    { # GCC path and default include dirs
20785        if(not $CrossGcc)
20786        { # try default gcc
20787            $GCC_PATH = get_CmdPath("gcc");
20788        }
20789        if(not $GCC_PATH)
20790        { # try to find gcc-X.Y
20791            foreach my $Path (@{$SystemPaths{"bin"}})
20792            {
20793                if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1))
20794                { # select the latest version
20795                    @GCCs = sort {$b cmp $a} @GCCs;
20796                    if(check_gcc($GCCs[0], "3"))
20797                    {
20798                        $GCC_PATH = $GCCs[0];
20799                        last;
20800                    }
20801                }
20802            }
20803        }
20804        if(not $GCC_PATH) {
20805            exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
20806        }
20807
20808        if(not $CheckObjectsOnly_Opt)
20809        {
20810            if(my $GCC_Ver = get_dumpversion($GCC_PATH))
20811            {
20812                my $GccTarget = get_dumpmachine($GCC_PATH);
20813                printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
20814                if($GccTarget=~/symbian/)
20815                {
20816                    $OStarget = "symbian";
20817                    $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
20818                }
20819
20820                # check GCC version
20821                if($GCC_Ver=~/\A4\.8(|\.0|\.1)\Z/)
20822                { # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850
20823                    printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update or downgrade GCC or use a local installation by --gcc-path=PATH option.");
20824                    $EMERGENCY_MODE_48 = 1;
20825                }
20826            }
20827            else {
20828                exitStatus("Error", "something is going wrong with the GCC compiler");
20829            }
20830        }
20831        if($HSearch)
20832        {
20833            if(not $NoStdInc)
20834            { # do NOT search in GCC standard paths
20835                my %DPaths = detect_inc_default_paths();
20836                @DefaultCppPaths = @{$DPaths{"Cpp"}};
20837                @DefaultGccPaths = @{$DPaths{"Gcc"}};
20838                @DefaultIncPaths = @{$DPaths{"Inc"}};
20839                push_U($SystemPaths{"include"}, @DefaultIncPaths);
20840            }
20841        }
20842    }
20843    if($HSearch)
20844    { # users include paths
20845        my $IncPath = "/usr/include";
20846        if($SystemRoot) {
20847            $IncPath = $SystemRoot.$IncPath;
20848        }
20849        if(-d $IncPath) {
20850            push_U(\@UsersIncPath, $IncPath);
20851        }
20852    }
20853
20854    if($ExtraInfo)
20855    {
20856        writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths));
20857        writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths)));
20858    }
20859}
20860
20861sub getLIB_EXT($)
20862{
20863    my $Target = $_[0];
20864    if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
20865        return $Ext;
20866    }
20867    return $OS_LibExt{$LIB_TYPE}{"default"};
20868}
20869
20870sub getAR_EXT($)
20871{
20872    my $Target = $_[0];
20873    if(my $Ext = $OS_Archive{$Target}) {
20874        return $Ext;
20875    }
20876    return $OS_Archive{"default"};
20877}
20878
20879sub get_dumpversion($)
20880{
20881    my $Cmd = $_[0];
20882    return "" if(not $Cmd);
20883    if($Cache{"get_dumpversion"}{$Cmd}) {
20884        return $Cache{"get_dumpversion"}{$Cmd};
20885    }
20886    my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
20887    chomp($V);
20888    return ($Cache{"get_dumpversion"}{$Cmd} = $V);
20889}
20890
20891sub get_dumpmachine($)
20892{
20893    my $Cmd = $_[0];
20894    return "" if(not $Cmd);
20895    if($Cache{"get_dumpmachine"}{$Cmd}) {
20896        return $Cache{"get_dumpmachine"}{$Cmd};
20897    }
20898    my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
20899    chomp($Machine);
20900    return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
20901}
20902
20903sub checkCmd($)
20904{
20905    my $Cmd = $_[0];
20906    return "" if(not $Cmd);
20907    my @Options = (
20908        "--version",
20909        "-help"
20910    );
20911    foreach my $Opt (@Options)
20912    {
20913        my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
20914        if($Info) {
20915            return 1;
20916        }
20917    }
20918    return 0;
20919}
20920
20921sub check_gcc($$)
20922{
20923    my ($Cmd, $ReqVer) = @_;
20924    return 0 if(not $Cmd or not $ReqVer);
20925    if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
20926        return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
20927    }
20928    if(my $GccVer = get_dumpversion($Cmd))
20929    {
20930        $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
20931        if(cmpVersions($GccVer, $ReqVer)>=0) {
20932            return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
20933        }
20934    }
20935    return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
20936}
20937
20938sub get_depth($)
20939{
20940    if(defined $Cache{"get_depth"}{$_[0]}) {
20941        return $Cache{"get_depth"}{$_[0]};
20942    }
20943    return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
20944}
20945
20946sub registerGccHeaders()
20947{
20948    return if($Cache{"registerGccHeaders"}); # this function should be called once
20949
20950    foreach my $Path (@DefaultGccPaths)
20951    {
20952        my @Headers = cmd_find($Path,"f");
20953        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
20954        foreach my $HPath (@Headers)
20955        {
20956            my $FileName = get_filename($HPath);
20957            if(not defined $DefaultGccHeader{$FileName})
20958            { # skip duplicated
20959                $DefaultGccHeader{$FileName} = $HPath;
20960            }
20961        }
20962    }
20963    $Cache{"registerGccHeaders"} = 1;
20964}
20965
20966sub registerCppHeaders()
20967{
20968    return if($Cache{"registerCppHeaders"}); # this function should be called once
20969
20970    foreach my $CppDir (@DefaultCppPaths)
20971    {
20972        my @Headers = cmd_find($CppDir,"f");
20973        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
20974        foreach my $Path (@Headers)
20975        {
20976            my $FileName = get_filename($Path);
20977            if(not defined $DefaultCppHeader{$FileName})
20978            { # skip duplicated
20979                $DefaultCppHeader{$FileName} = $Path;
20980            }
20981        }
20982    }
20983    $Cache{"registerCppHeaders"} = 1;
20984}
20985
20986sub parse_libname($$$)
20987{
20988    return "" if(not $_[0]);
20989    if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
20990        return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
20991    }
20992    return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
20993}
20994
20995sub parse_libname_I($$$)
20996{
20997    my ($Name, $Type, $Target) = @_;
20998
20999    if($Target eq "symbian") {
21000        return parse_libname_symbian($Name, $Type);
21001    }
21002    elsif($Target eq "windows") {
21003        return parse_libname_windows($Name, $Type);
21004    }
21005
21006    # unix
21007    my $Ext = getLIB_EXT($Target);
21008    if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
21009    { # libSDL-1.2.so.0.7.1
21010      # libwbxml2.so.0.0.18
21011      # libopcodes-2.21.53-system.20110810.so
21012        if($Type eq "name")
21013        { # libSDL-1.2
21014          # libwbxml2
21015            return $2;
21016        }
21017        elsif($Type eq "name+ext")
21018        { # libSDL-1.2.so
21019          # libwbxml2.so
21020            return $1;
21021        }
21022        elsif($Type eq "version")
21023        {
21024            if(defined $7
21025            and $7 ne "")
21026            { # 0.7.1
21027                return $7;
21028            }
21029            else
21030            { # libc-2.5.so (=>2.5 version)
21031                my $MV = $5;
21032                $MV=~s/\A[\-\_]+//g;
21033                return $MV;
21034            }
21035        }
21036        elsif($Type eq "short")
21037        { # libSDL
21038          # libwbxml2
21039            return $3;
21040        }
21041        elsif($Type eq "shortest")
21042        { # SDL
21043          # wbxml
21044            return shortest_name($3);
21045        }
21046    }
21047    return "";# error
21048}
21049
21050sub parse_libname_symbian($$)
21051{
21052    my ($Name, $Type) = @_;
21053    my $Ext = getLIB_EXT("symbian");
21054    if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
21055    { # libpthread{00010001}.dso
21056        if($Type eq "name")
21057        { # libpthread{00010001}
21058            return $2;
21059        }
21060        elsif($Type eq "name+ext")
21061        { # libpthread{00010001}.dso
21062            return $1;
21063        }
21064        elsif($Type eq "version")
21065        { # 00010001
21066            my $V = $4;
21067            $V=~s/\{(.+)\}/$1/;
21068            return $V;
21069        }
21070        elsif($Type eq "short")
21071        { # libpthread
21072            return $3;
21073        }
21074        elsif($Type eq "shortest")
21075        { # pthread
21076            return shortest_name($3);
21077        }
21078    }
21079    return "";# error
21080}
21081
21082sub parse_libname_windows($$)
21083{
21084    my ($Name, $Type) = @_;
21085    my $Ext = getLIB_EXT("windows");
21086    if($Name=~/((.+?)\.$Ext)\Z/)
21087    { # netapi32.dll
21088        if($Type eq "name")
21089        { # netapi32
21090            return $2;
21091        }
21092        elsif($Type eq "name+ext")
21093        { # netapi32.dll
21094            return $1;
21095        }
21096        elsif($Type eq "version")
21097        { # DLL version embedded
21098          # at binary-level
21099            return "";
21100        }
21101        elsif($Type eq "short")
21102        { # netapi32
21103            return $2;
21104        }
21105        elsif($Type eq "shortest")
21106        { # netapi
21107            return shortest_name($2);
21108        }
21109    }
21110    return "";# error
21111}
21112
21113sub shortest_name($)
21114{
21115    my $Name = $_[0];
21116    # remove prefix
21117    $Name=~s/\A(lib|open)//;
21118    # remove suffix
21119    $Name=~s/[\W\d_]+\Z//i;
21120    $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
21121    return $Name;
21122}
21123
21124sub createSymbolsList($$$$$)
21125{
21126    my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
21127    read_ABI_Dump(1, $DPath);
21128    if(not $CheckObjectsOnly) {
21129        prepareSymbols(1);
21130    }
21131    my %SymbolHeaderLib = ();
21132    my $Total = 0;
21133    # Get List
21134    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
21135    {
21136        if(not link_symbol($Symbol, 1, "-Deps"))
21137        { # skip src only and all external functions
21138            next;
21139        }
21140        if(not symbolFilter($Symbol, 1, "Public", "Binary"))
21141        { # skip other symbols
21142            next;
21143        }
21144        my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
21145        if(not $HeaderName)
21146        { # skip src only and all external functions
21147            next;
21148        }
21149        my $DyLib = $Symbol_Library{1}{$Symbol};
21150        if(not $DyLib)
21151        { # skip src only and all external functions
21152            next;
21153        }
21154        $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
21155        $Total+=1;
21156    }
21157    # Draw List
21158    my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
21159    $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
21160    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
21161    {
21162        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
21163        {
21164            my %NS_Symbol = ();
21165            foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
21166                $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1;
21167            }
21168            foreach my $NameSpace (sort keys(%NS_Symbol))
21169            {
21170                $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
21171                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
21172                foreach my $Symbol (@SortedInterfaces)
21173                {
21174                    my $SubReport = "";
21175                    my $Signature = get_Signature($Symbol, 1);
21176                    if($NameSpace) {
21177                        $Signature=~s/\b\Q$NameSpace\E::\b//g;
21178                    }
21179                    if($Symbol=~/\A(_Z|\?)/)
21180                    {
21181                        if($Signature) {
21182                            $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
21183                        }
21184                        else {
21185                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
21186                        }
21187                    }
21188                    else
21189                    {
21190                        if($Signature) {
21191                            $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
21192                        }
21193                        else {
21194                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
21195                        }
21196                    }
21197                    $SYMBOLS_LIST .= $SubReport;
21198                }
21199            }
21200            $SYMBOLS_LIST .= "<br/>\n";
21201        }
21202    }
21203    # clear info
21204    (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
21205    %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
21206    %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
21207    %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
21208    ($Content_Counter, $ContentID) = (0, 0);
21209    # print report
21210    my $CssStyles = readModule("Styles", "SymbolsList.css");
21211    my $JScripts = readModule("Scripts", "Sections.js");
21212    $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
21213    my $Title = "$LName: public symbols";
21214    my $Keywords = "$LName, API, symbols";
21215    my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
21216    $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
21217    <body><div>\n$SYMBOLS_LIST</div>
21218    <br/><br/><hr/>\n".getReportFooter($LName, 1)."
21219    <div style='height:999px;'></div></body></html>";
21220    writeFile($SaveTo, $SYMBOLS_LIST);
21221}
21222
21223sub add_target_libs($)
21224{
21225    foreach (@{$_[0]}) {
21226        $TargetLibs{$_} = 1;
21227    }
21228}
21229
21230sub is_target_lib($)
21231{
21232    my $LName = $_[0];
21233    if(not $LName) {
21234        return 0;
21235    }
21236    if($TargetLibraryName
21237    and $LName!~/\Q$TargetLibraryName\E/) {
21238        return 0;
21239    }
21240    if(keys(%TargetLibs)
21241    and not $TargetLibs{$LName}
21242    and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
21243        return 0;
21244    }
21245    return 1;
21246}
21247
21248sub is_target_header($$)
21249{ # --header, --headers-list
21250    my ($H, $V) = @_;
21251    if(keys(%{$TargetHeaders{$V}}))
21252    {
21253        if($TargetHeaders{$V}{$H}) {
21254            return 1;
21255        }
21256    }
21257    return 0;
21258}
21259
21260sub checkVersionNum($$)
21261{
21262    my ($LibVersion, $Path) = @_;
21263    if(my $VerNum = $TargetVersion{$LibVersion}) {
21264        return $VerNum;
21265    }
21266    my $UsedAltDescr = 0;
21267    foreach my $Part (split(/\s*,\s*/, $Path))
21268    { # try to get version string from file path
21269        next if(isDump($Part)); # ABI dump
21270        next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
21271        my $VerNum = "";
21272        if(parse_libname($Part, "name", $OStarget))
21273        {
21274            $UsedAltDescr = 1;
21275            $VerNum = parse_libname($Part, "version", $OStarget);
21276            if(not $VerNum) {
21277                $VerNum = readStrVer($Part);
21278            }
21279        }
21280        elsif(is_header($Part, 2, $LibVersion) or -d $Part)
21281        {
21282            $UsedAltDescr = 1;
21283            $VerNum = readStrVer($Part);
21284        }
21285        if($VerNum ne "")
21286        {
21287            $TargetVersion{$LibVersion} = $VerNum;
21288            if($DumpAPI) {
21289                printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)");
21290            }
21291            else {
21292                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)");
21293            }
21294            return $TargetVersion{$LibVersion};
21295        }
21296    }
21297    if($UsedAltDescr)
21298    {
21299        if($DumpAPI) {
21300            exitStatus("Error", "version number is not set (use -vnum option)");
21301        }
21302        else {
21303            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)");
21304        }
21305    }
21306}
21307
21308sub readStrVer($)
21309{
21310    my $Str = $_[0];
21311    return "" if(not $Str);
21312    $Str=~s/\Q$TargetLibraryName\E//g;
21313    if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
21314    { # .../libssh-0.4.0/...
21315        return $2;
21316    }
21317    elsif(my $V = parse_libname($Str, "version", $OStarget)) {
21318        return $V;
21319    }
21320    return "";
21321}
21322
21323sub readLibs($)
21324{
21325    my $LibVersion = $_[0];
21326    if($OStarget eq "windows")
21327    { # dumpbin.exe will crash
21328        # without VS Environment
21329        check_win32_env();
21330    }
21331    readSymbols($LibVersion);
21332    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
21333    translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
21334}
21335
21336sub dump_sorting($)
21337{
21338    my $Hash = $_[0];
21339    return [] if(not $Hash);
21340    my @Keys = keys(%{$Hash});
21341    return [] if($#Keys<0);
21342    if($Keys[0]=~/\A\d+\Z/)
21343    { # numbers
21344        return [sort {int($a)<=>int($b)} @Keys];
21345    }
21346    else
21347    { # strings
21348        return [sort {$a cmp $b} @Keys];
21349    }
21350}
21351
21352sub printMsg($$)
21353{
21354    my ($Type, $Msg) = @_;
21355    if($Type!~/\AINFO/) {
21356        $Msg = $Type.": ".$Msg;
21357    }
21358    if($Type!~/_C\Z/) {
21359        $Msg .= "\n";
21360    }
21361    if($Quiet)
21362    { # --quiet option
21363        appendFile($COMMON_LOG_PATH, $Msg);
21364    }
21365    else
21366    {
21367        if($Type eq "ERROR") {
21368            print STDERR $Msg;
21369        }
21370        else {
21371            print $Msg;
21372        }
21373    }
21374}
21375
21376sub exitStatus($$)
21377{
21378    my ($Code, $Msg) = @_;
21379    printMsg("ERROR", $Msg);
21380    exit($ERROR_CODE{$Code});
21381}
21382
21383sub exitReport()
21384{ # the tool has run without any errors
21385    printReport();
21386    if($COMPILE_ERRORS)
21387    { # errors in headers may add false positives/negatives
21388        exit($ERROR_CODE{"Compile_Error"});
21389    }
21390    if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
21391    { # --binary
21392        exit($ERROR_CODE{"Incompatible"});
21393    }
21394    elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
21395    { # --source
21396        exit($ERROR_CODE{"Incompatible"});
21397    }
21398    elsif($RESULT{"Source"}{"Problems"}
21399    or $RESULT{"Binary"}{"Problems"})
21400    { # default
21401        exit($ERROR_CODE{"Incompatible"});
21402    }
21403    else {
21404        exit($ERROR_CODE{"Compatible"});
21405    }
21406}
21407
21408sub readRules($)
21409{
21410    my $Kind = $_[0];
21411    if(not -f $RULES_PATH{$Kind}) {
21412        exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
21413    }
21414    my $Content = readFile($RULES_PATH{$Kind});
21415    while(my $Rule = parseTag(\$Content, "rule"))
21416    {
21417        my $RId = parseTag(\$Rule, "id");
21418        my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
21419        foreach my $Prop (@Properties) {
21420            if(my $Value = parseTag(\$Rule, lc($Prop)))
21421            {
21422                $Value=~s/\n[ ]*//;
21423                $CompatRules{$Kind}{$RId}{$Prop} = $Value;
21424            }
21425        }
21426        if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
21427            $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
21428        }
21429        else {
21430            $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
21431        }
21432    }
21433}
21434
21435sub getReportPath($)
21436{
21437    my $Level = $_[0];
21438    my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
21439    if($Level eq "Binary")
21440    {
21441        if($BinaryReportPath)
21442        { # --bin-report-path
21443            return $BinaryReportPath;
21444        }
21445        elsif($OutputReportPath)
21446        { # --report-path
21447            return $OutputReportPath;
21448        }
21449        else
21450        { # default
21451            return $Dir."/abi_compat_report.$ReportFormat";
21452        }
21453    }
21454    elsif($Level eq "Source")
21455    {
21456        if($SourceReportPath)
21457        { # --src-report-path
21458            return $SourceReportPath;
21459        }
21460        elsif($OutputReportPath)
21461        { # --report-path
21462            return $OutputReportPath;
21463        }
21464        else
21465        { # default
21466            return $Dir."/src_compat_report.$ReportFormat";
21467        }
21468    }
21469    else
21470    {
21471        if($OutputReportPath)
21472        { # --report-path
21473            return $OutputReportPath;
21474        }
21475        else
21476        { # default
21477            return $Dir."/compat_report.$ReportFormat";
21478        }
21479    }
21480}
21481
21482sub printStatMsg($)
21483{
21484    my $Level = $_[0];
21485    printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
21486}
21487
21488sub listAffected($)
21489{
21490    my $Level = $_[0];
21491    my $List = "";
21492    foreach (keys(%{$TotalAffected{$Level}}))
21493    {
21494        if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
21495        { # skip "Low"-severity problems
21496            next;
21497        }
21498        $List .= "$_\n";
21499    }
21500    my $Dir = get_dirname(getReportPath($Level));
21501    if($Level eq "Binary") {
21502        writeFile($Dir."/abi_affected.txt", $List);
21503    }
21504    elsif($Level eq "Source") {
21505        writeFile($Dir."/src_affected.txt", $List);
21506    }
21507}
21508
21509sub printReport()
21510{
21511    printMsg("INFO", "creating compatibility report ...");
21512    createReport();
21513    if($JoinReport or $DoubleReport)
21514    {
21515        if($RESULT{"Binary"}{"Problems"}
21516        or $RESULT{"Source"}{"Problems"}) {
21517            printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
21518        }
21519        else {
21520            printMsg("INFO", "result: COMPATIBLE");
21521        }
21522        printStatMsg("Binary");
21523        printStatMsg("Source");
21524        if($ListAffected)
21525        { # --list-affected
21526            listAffected("Binary");
21527            listAffected("Source");
21528        }
21529    }
21530    elsif($BinaryOnly)
21531    {
21532        if($RESULT{"Binary"}{"Problems"}) {
21533            printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
21534        }
21535        else {
21536            printMsg("INFO", "result: COMPATIBLE");
21537        }
21538        printStatMsg("Binary");
21539        if($ListAffected)
21540        { # --list-affected
21541            listAffected("Binary");
21542        }
21543    }
21544    elsif($SourceOnly)
21545    {
21546        if($RESULT{"Source"}{"Problems"}) {
21547            printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
21548        }
21549        else {
21550            printMsg("INFO", "result: COMPATIBLE");
21551        }
21552        printStatMsg("Source");
21553        if($ListAffected)
21554        { # --list-affected
21555            listAffected("Source");
21556        }
21557    }
21558    if($StdOut)
21559    {
21560        if($JoinReport or not $DoubleReport)
21561        { # --binary or --source
21562            printMsg("INFO", "compatibility report has been generated to stdout");
21563        }
21564        else
21565        { # default
21566            printMsg("INFO", "compatibility reports have been generated to stdout");
21567        }
21568    }
21569    else
21570    {
21571        if($JoinReport)
21572        {
21573            printMsg("INFO", "see detailed report:\n  ".getReportPath("Join"));
21574        }
21575        elsif($DoubleReport)
21576        { # default
21577            printMsg("INFO", "see detailed reports:\n  ".getReportPath("Binary")."\n  ".getReportPath("Source"));
21578        }
21579        elsif($BinaryOnly)
21580        { # --binary
21581            printMsg("INFO", "see detailed report:\n  ".getReportPath("Binary"));
21582        }
21583        elsif($SourceOnly)
21584        { # --source
21585            printMsg("INFO", "see detailed report:\n  ".getReportPath("Source"));
21586        }
21587    }
21588}
21589
21590sub check_win32_env()
21591{
21592    if(not $ENV{"DevEnvDir"}
21593    or not $ENV{"LIB"}) {
21594        exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
21595    }
21596}
21597
21598sub diffSets($$)
21599{
21600    my ($S1, $S2) = @_;
21601    my @SK1 = keys(%{$S1});
21602    my @SK2 = keys(%{$S2});
21603    if($#SK1!=$#SK2) {
21604        return 1;
21605    }
21606    foreach my $K1 (@SK1)
21607    {
21608        if(not defined $S2->{$K1}) {
21609            return 1;
21610        }
21611    }
21612    return 0;
21613}
21614
21615sub create_ABI_Dump()
21616{
21617    if(not -e $DumpAPI) {
21618        exitStatus("Access_Error", "can't access \'$DumpAPI\'");
21619    }
21620    my @DParts = split(/\s*,\s*/, $DumpAPI);
21621    foreach my $Part (@DParts)
21622    {
21623        if(not -e $Part) {
21624            exitStatus("Access_Error", "can't access \'$Part\'");
21625        }
21626    }
21627    checkVersionNum(1, $DumpAPI);
21628    foreach my $Part (@DParts)
21629    {
21630        if(isDump($Part)) {
21631            read_ABI_Dump(1, $Part);
21632        }
21633        else {
21634            readDescriptor(1, createDescriptor(1, $Part));
21635        }
21636    }
21637
21638    if(not $Descriptor{1}{"Version"})
21639    { # set to default: X
21640        $Descriptor{1}{"Version"} = "X";
21641    }
21642
21643    initLogging(1);
21644    detect_default_paths("inc|lib|bin|gcc"); # complete analysis
21645
21646    my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
21647    $DumpPath .= ".".$AR_EXT; # gzipped by default
21648    if($OutputDumpPath)
21649    { # user defined path
21650        $DumpPath = $OutputDumpPath;
21651    }
21652    my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
21653
21654    if(not $Archive and not $StdOut)
21655    { # check archive utilities
21656        if($OSgroup eq "windows")
21657        { # using zip
21658            my $ZipCmd = get_CmdPath("zip");
21659            if(not $ZipCmd) {
21660                exitStatus("Not_Found", "can't find \"zip\"");
21661            }
21662        }
21663        else
21664        { # using tar and gzip
21665            my $TarCmd = get_CmdPath("tar");
21666            if(not $TarCmd) {
21667                exitStatus("Not_Found", "can't find \"tar\"");
21668            }
21669            my $GzipCmd = get_CmdPath("gzip");
21670            if(not $GzipCmd) {
21671                exitStatus("Not_Found", "can't find \"gzip\"");
21672            }
21673        }
21674    }
21675
21676    if(not $Descriptor{1}{"Dump"})
21677    {
21678        if(not $CheckHeadersOnly) {
21679            readLibs(1);
21680        }
21681        if($CheckHeadersOnly) {
21682            setLanguage(1, "C++");
21683        }
21684        if(not $CheckObjectsOnly) {
21685            searchForHeaders(1);
21686        }
21687        $WORD_SIZE{1} = detectWordSize();
21688    }
21689    if(not $Descriptor{1}{"Dump"})
21690    {
21691        if($Descriptor{1}{"Headers"}) {
21692            readHeaders(1);
21693        }
21694    }
21695    cleanDump(1);
21696    if(not keys(%{$SymbolInfo{1}}))
21697    { # check if created dump is valid
21698        if(not $ExtendedCheck and not $CheckObjectsOnly)
21699        {
21700            if($CheckHeadersOnly) {
21701                exitStatus("Empty_Set", "the set of public symbols is empty");
21702            }
21703            else {
21704                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
21705            }
21706        }
21707    }
21708    my %HeadersInfo = ();
21709    foreach my $HPath (keys(%{$Registered_Headers{1}})) {
21710        $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
21711    }
21712    if($ExtraDump)
21713    { # add unmangled names to the ABI dump
21714        my @Names = ();
21715        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
21716        {
21717            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) {
21718                push(@Names, $MnglName);
21719            }
21720        }
21721        translateSymbols(@Names, 1);
21722        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
21723        {
21724            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"})
21725            {
21726                if(my $Unmangled = $tr_name{$MnglName})
21727                {
21728                    if($MnglName ne $Unmangled) {
21729                        $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled;
21730                    }
21731                }
21732            }
21733        }
21734    }
21735
21736    my %GccConstants = (); # built-in GCC constants
21737    foreach my $Name (keys(%{$Constants{1}}))
21738    {
21739        if(not defined $Constants{1}{$Name}{"Header"})
21740        {
21741            $GccConstants{$Name} = $Constants{1}{$Name}{"Value"};
21742            delete($Constants{1}{$Name});
21743        }
21744    }
21745
21746    printMsg("INFO", "creating library ABI dump ...");
21747    my %ABI = (
21748        "TypeInfo" => $TypeInfo{1},
21749        "SymbolInfo" => $SymbolInfo{1},
21750        "Symbols" => $Library_Symbol{1},
21751        "DepSymbols" => $DepLibrary_Symbol{1},
21752        "SymbolVersion" => $SymVer{1},
21753        "LibraryVersion" => $Descriptor{1}{"Version"},
21754        "LibraryName" => $TargetLibraryName,
21755        "Language" => $COMMON_LANGUAGE{1},
21756        "SkipTypes" => $SkipTypes{1},
21757        "SkipSymbols" => $SkipSymbols{1},
21758        "SkipNameSpaces" => $SkipNameSpaces{1},
21759        "SkipHeaders" => $SkipHeadersList{1},
21760        "Headers" => \%HeadersInfo,
21761        "Constants" => $Constants{1},
21762        "GccConstants" => \%GccConstants,
21763        "NameSpaces" => $NestedNameSpaces{1},
21764        "Target" => $OStarget,
21765        "Arch" => getArch(1),
21766        "WordSize" => $WORD_SIZE{1},
21767        "GccVersion" => get_dumpversion($GCC_PATH),
21768        "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
21769        "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
21770    );
21771    if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
21772        $ABI{"TargetHeaders"} = $TargetHeaders{1};
21773    }
21774    if($UseXML) {
21775        $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
21776    }
21777    if($ExtendedCheck)
21778    { # --ext option
21779        $ABI{"Mode"} = "Extended";
21780    }
21781    if($BinaryOnly)
21782    { # --binary
21783        $ABI{"BinOnly"} = 1;
21784    }
21785    if($ExtraDump)
21786    { # --extra-dump
21787        $ABI{"Extra"} = 1;
21788        $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1};
21789        $ABI{"Needed"} = $Library_Needed{1};
21790    }
21791
21792    my $ABI_DUMP = "";
21793    if($UseXML)
21794    {
21795        loadModule("XmlDump");
21796        $ABI_DUMP = createXmlDump(\%ABI);
21797    }
21798    else
21799    { # default
21800        $ABI_DUMP = Dumper(\%ABI);
21801    }
21802    if($StdOut)
21803    { # --stdout option
21804        print STDOUT $ABI_DUMP;
21805        printMsg("INFO", "ABI dump has been generated to stdout");
21806        return;
21807    }
21808    else
21809    { # write to gzipped file
21810        my ($DDir, $DName) = separate_path($DumpPath);
21811        my $DPath = $TMP_DIR."/".$DName;
21812        if(not $Archive) {
21813            $DPath = $DumpPath;
21814        }
21815
21816        mkpath($DDir);
21817
21818        open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
21819        print DUMP $ABI_DUMP;
21820        close(DUMP);
21821
21822        if(not -s $DPath) {
21823            exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
21824        }
21825        if($Archive) {
21826            $DumpPath = createArchive($DPath, $DDir);
21827        }
21828
21829        if($OutputDumpPath) {
21830            printMsg("INFO", "library ABI has been dumped to:\n  $OutputDumpPath");
21831        }
21832        else {
21833            printMsg("INFO", "library ABI has been dumped to:\n  $DumpPath");
21834        }
21835        printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
21836    }
21837}
21838
21839sub quickEmptyReports()
21840{ # Quick "empty" reports
21841  # 4 times faster than merging equal dumps
21842  # NOTE: the dump contains the "LibraryVersion" attribute
21843  # if you change the version, then your dump will be different
21844  # OVERCOME: use -v1 and v2 options for comparing dumps
21845  # and don't change version in the XML descriptor (and dumps)
21846  # OVERCOME 2: separate meta info from the dumps in ACC 2.0
21847    if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
21848    {
21849        my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
21850        my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
21851        if($FilePath1 and $FilePath2)
21852        {
21853            my $Line = readLineNum($FilePath1, 0);
21854            if($Line=~/xml/)
21855            { # XML format
21856                # is not supported yet
21857                return;
21858            }
21859
21860            local $/ = undef;
21861
21862            open(DUMP1, $FilePath1);
21863            my $Content1 = <DUMP1>;
21864            close(DUMP1);
21865
21866            open(DUMP2, $FilePath2);
21867            my $Content2 = <DUMP2>;
21868            close(DUMP2);
21869
21870            if($Content1 eq $Content2)
21871            {
21872                # clean memory
21873                undef $Content2;
21874
21875                # read a number of headers, libs, symbols and types
21876                my $ABIdump = eval($Content1);
21877
21878                # clean memory
21879                undef $Content1;
21880
21881                if(not $ABIdump) {
21882                    exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
21883                }
21884                if(not $ABIdump->{"TypeInfo"})
21885                { # support for old dumps
21886                    $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
21887                }
21888                if(not $ABIdump->{"SymbolInfo"})
21889                { # support for old dumps
21890                    $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
21891                }
21892                read_Source_DumpInfo($ABIdump, 1);
21893                read_Libs_DumpInfo($ABIdump, 1);
21894                read_Machine_DumpInfo($ABIdump, 1);
21895                read_Machine_DumpInfo($ABIdump, 2);
21896
21897                %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
21898                %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
21899
21900                %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
21901                %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
21902
21903                $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
21904                $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
21905                exitReport();
21906            }
21907        }
21908    }
21909}
21910
21911sub initLogging($)
21912{
21913    my $LibVersion = $_[0];
21914    # create log directory
21915    my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
21916    if($OutputLogPath{$LibVersion})
21917    { # user-defined by -log-path option
21918        ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
21919    }
21920    if($LogMode ne "n") {
21921        mkpath($LOG_DIR);
21922    }
21923    $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
21924    if($Debug)
21925    { # debug directory
21926        $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
21927
21928        if(not $ExtraInfo)
21929        { # enable --extra-info
21930            $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info";
21931        }
21932    }
21933    resetLogging($LibVersion);
21934}
21935
21936sub writeLog($$)
21937{
21938    my ($LibVersion, $Msg) = @_;
21939    if($LogMode ne "n") {
21940        appendFile($LOG_PATH{$LibVersion}, $Msg);
21941    }
21942}
21943
21944sub resetLogging($)
21945{
21946    my $LibVersion = $_[0];
21947    if($LogMode!~/a|n/)
21948    { # remove old log
21949        unlink($LOG_PATH{$LibVersion});
21950        if($Debug) {
21951            rmtree($DEBUG_PATH{$LibVersion});
21952        }
21953    }
21954}
21955
21956sub printErrorLog($)
21957{
21958    my $LibVersion = $_[0];
21959    if($LogMode ne "n") {
21960        printMsg("ERROR", "see log for details:\n  ".$LOG_PATH{$LibVersion}."\n");
21961    }
21962}
21963
21964sub isDump($)
21965{
21966    if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz|\.zip|\.xml|)(\.\w+|)\Z/) {
21967        return $1;
21968    }
21969    return 0;
21970}
21971
21972sub isDump_U($)
21973{
21974    if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.xml|)(\.\w+|)\Z/) {
21975        return $1;
21976    }
21977    return 0;
21978}
21979
21980sub compareInit()
21981{
21982    # read input XML descriptors or ABI dumps
21983    if(not $Descriptor{1}{"Path"}) {
21984        exitStatus("Error", "-old option is not specified");
21985    }
21986    my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
21987    foreach my $Part (@DParts1)
21988    {
21989        if(not -e $Part) {
21990            exitStatus("Access_Error", "can't access \'$Part\'");
21991        }
21992    }
21993    if(not $Descriptor{2}{"Path"}) {
21994        exitStatus("Error", "-new option is not specified");
21995    }
21996    my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
21997    foreach my $Part (@DParts2)
21998    {
21999        if(not -e $Part) {
22000            exitStatus("Access_Error", "can't access \'$Part\'");
22001        }
22002    }
22003    detect_default_paths("bin"); # to extract dumps
22004    if($#DParts1==0 and $#DParts2==0
22005    and isDump($Descriptor{1}{"Path"})
22006    and isDump($Descriptor{2}{"Path"}))
22007    { # optimization: equal ABI dumps
22008        quickEmptyReports();
22009    }
22010    checkVersionNum(1, $Descriptor{1}{"Path"});
22011    checkVersionNum(2, $Descriptor{2}{"Path"});
22012    printMsg("INFO", "preparation, please wait ...");
22013    foreach my $Part (@DParts1)
22014    {
22015        if(isDump($Part)) {
22016            read_ABI_Dump(1, $Part);
22017        }
22018        else {
22019            readDescriptor(1, createDescriptor(1, $Part));
22020        }
22021    }
22022    foreach my $Part (@DParts2)
22023    {
22024        if(isDump($Part)) {
22025            read_ABI_Dump(2, $Part);
22026        }
22027        else {
22028            readDescriptor(2, createDescriptor(2, $Part));
22029        }
22030    }
22031
22032    if(not $Descriptor{1}{"Version"})
22033    { # set to default: X
22034        $Descriptor{1}{"Version"} = "X";
22035    }
22036
22037    if(not $Descriptor{2}{"Version"})
22038    { # set to default: Y
22039        $Descriptor{2}{"Version"} = "Y";
22040    }
22041
22042    initLogging(1);
22043    initLogging(2);
22044    # check consistency
22045    if(not $Descriptor{1}{"Headers"}
22046    and not $Descriptor{1}{"Libs"}) {
22047        exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
22048    }
22049    if(not $Descriptor{2}{"Headers"}
22050    and not $Descriptor{2}{"Libs"}) {
22051        exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
22052    }
22053    if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
22054    and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
22055        exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
22056    }
22057    elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
22058    and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
22059        exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
22060    }
22061    if(not $Descriptor{1}{"Headers"})
22062    {
22063        if($CheckHeadersOnly_Opt) {
22064            exitStatus("Error", "can't find header files info in descriptor d1");
22065        }
22066    }
22067    if(not $Descriptor{2}{"Headers"})
22068    {
22069        if($CheckHeadersOnly_Opt) {
22070            exitStatus("Error", "can't find header files info in descriptor d2");
22071        }
22072    }
22073    if(not $Descriptor{1}{"Headers"}
22074    or not $Descriptor{2}{"Headers"})
22075    {
22076        if(not $CheckObjectsOnly_Opt)
22077        {
22078            printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
22079            $CheckObjectsOnly = 1;
22080        }
22081    }
22082    if(not $Descriptor{1}{"Libs"})
22083    {
22084        if($CheckObjectsOnly_Opt) {
22085            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
22086        }
22087    }
22088    if(not $Descriptor{2}{"Libs"})
22089    {
22090        if($CheckObjectsOnly_Opt) {
22091            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
22092        }
22093    }
22094    if(not $Descriptor{1}{"Libs"}
22095    or not $Descriptor{2}{"Libs"})
22096    { # comparing standalone header files
22097      # comparing ABI dumps created with --headers-only
22098        if(not $CheckHeadersOnly_Opt)
22099        {
22100            printMsg("WARNING", "checking headers only");
22101            $CheckHeadersOnly = 1;
22102        }
22103    }
22104    if($UseDumps)
22105    { # --use-dumps
22106      # parallel processing
22107        my $DumpPath1 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT";
22108        my $DumpPath2 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT";
22109
22110        unlink($DumpPath1);
22111        unlink($DumpPath2);
22112
22113        my $pid = fork();
22114        if($pid)
22115        { # dump on two CPU cores
22116            my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
22117            if($RelativeDirectory{1}) {
22118                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
22119            }
22120            if($OutputLogPath{1}) {
22121                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
22122            }
22123            if($CrossGcc) {
22124                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
22125            }
22126            if($Quiet)
22127            {
22128                @PARAMS = (@PARAMS, "-quiet");
22129                @PARAMS = (@PARAMS, "-logging-mode", "a");
22130            }
22131            elsif($LogMode and $LogMode ne "w")
22132            { # "w" is default
22133                @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
22134            }
22135            if($ExtendedCheck) {
22136                @PARAMS = (@PARAMS, "-extended");
22137            }
22138            if($UserLang) {
22139                @PARAMS = (@PARAMS, "-lang", $UserLang);
22140            }
22141            if($TargetVersion{1}) {
22142                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
22143            }
22144            if($BinaryOnly) {
22145                @PARAMS = (@PARAMS, "-binary");
22146            }
22147            if($SourceOnly) {
22148                @PARAMS = (@PARAMS, "-source");
22149            }
22150            if($SortDump) {
22151                @PARAMS = (@PARAMS, "-sort");
22152            }
22153            if($DumpFormat and $DumpFormat ne "perl") {
22154                @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
22155            }
22156            if($CheckHeadersOnly) {
22157                @PARAMS = (@PARAMS, "-headers-only");
22158            }
22159            if($CheckObjectsOnly) {
22160                @PARAMS = (@PARAMS, "-objects-only");
22161            }
22162            if($Debug)
22163            {
22164                @PARAMS = (@PARAMS, "-debug");
22165                printMsg("INFO", "running perl $0 @PARAMS");
22166            }
22167            system("perl", $0, @PARAMS);
22168            if(not -f $DumpPath1) {
22169                exit(1);
22170            }
22171        }
22172        else
22173        { # child
22174            my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
22175            if($RelativeDirectory{2}) {
22176                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
22177            }
22178            if($OutputLogPath{2}) {
22179                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
22180            }
22181            if($CrossGcc) {
22182                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
22183            }
22184            if($Quiet)
22185            {
22186                @PARAMS = (@PARAMS, "-quiet");
22187                @PARAMS = (@PARAMS, "-logging-mode", "a");
22188            }
22189            elsif($LogMode and $LogMode ne "w")
22190            { # "w" is default
22191                @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
22192            }
22193            if($ExtendedCheck) {
22194                @PARAMS = (@PARAMS, "-extended");
22195            }
22196            if($UserLang) {
22197                @PARAMS = (@PARAMS, "-lang", $UserLang);
22198            }
22199            if($TargetVersion{2}) {
22200                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
22201            }
22202            if($BinaryOnly) {
22203                @PARAMS = (@PARAMS, "-binary");
22204            }
22205            if($SourceOnly) {
22206                @PARAMS = (@PARAMS, "-source");
22207            }
22208            if($SortDump) {
22209                @PARAMS = (@PARAMS, "-sort");
22210            }
22211            if($DumpFormat and $DumpFormat ne "perl") {
22212                @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
22213            }
22214            if($CheckHeadersOnly) {
22215                @PARAMS = (@PARAMS, "-headers-only");
22216            }
22217            if($CheckObjectsOnly) {
22218                @PARAMS = (@PARAMS, "-objects-only");
22219            }
22220            if($Debug)
22221            {
22222                @PARAMS = (@PARAMS, "-debug");
22223                printMsg("INFO", "running perl $0 @PARAMS");
22224            }
22225            system("perl", $0, @PARAMS);
22226            if(not -f $DumpPath2) {
22227                exit(1);
22228            }
22229            else {
22230                exit(0);
22231            }
22232        }
22233        waitpid($pid, 0);
22234        my @CMP_PARAMS = ("-l", $TargetLibraryName);
22235        @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1);
22236        @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2);
22237        if($TargetLibraryFName ne $TargetLibraryName) {
22238            @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
22239        }
22240        if($ShowRetVal) {
22241            @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
22242        }
22243        if($CrossGcc) {
22244            @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
22245        }
22246        @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
22247        if($Quiet) {
22248            @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
22249        }
22250        if($ReportFormat and $ReportFormat ne "html")
22251        { # HTML is default format
22252            @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
22253        }
22254        if($OutputReportPath) {
22255            @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
22256        }
22257        if($BinaryReportPath) {
22258            @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
22259        }
22260        if($SourceReportPath) {
22261            @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
22262        }
22263        if($LoggingPath) {
22264            @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
22265        }
22266        if($CheckHeadersOnly) {
22267            @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
22268        }
22269        if($CheckObjectsOnly) {
22270            @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
22271        }
22272        if($BinaryOnly) {
22273            @CMP_PARAMS = (@CMP_PARAMS, "-binary");
22274        }
22275        if($SourceOnly) {
22276            @CMP_PARAMS = (@CMP_PARAMS, "-source");
22277        }
22278        if($Browse) {
22279            @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
22280        }
22281        if($OpenReport) {
22282            @CMP_PARAMS = (@CMP_PARAMS, "-open");
22283        }
22284        if($Debug)
22285        {
22286            @CMP_PARAMS = (@CMP_PARAMS, "-debug");
22287            printMsg("INFO", "running perl $0 @CMP_PARAMS");
22288        }
22289        system("perl", $0, @CMP_PARAMS);
22290        exit($?>>8);
22291    }
22292    if(not $Descriptor{1}{"Dump"}
22293    or not $Descriptor{2}{"Dump"})
22294    { # need GCC toolchain to analyze
22295      # header files and libraries
22296        detect_default_paths("inc|lib|gcc");
22297    }
22298    if(not $Descriptor{1}{"Dump"})
22299    {
22300        if(not $CheckHeadersOnly) {
22301            readLibs(1);
22302        }
22303        if($CheckHeadersOnly) {
22304            setLanguage(1, "C++");
22305        }
22306        if(not $CheckObjectsOnly) {
22307            searchForHeaders(1);
22308        }
22309        $WORD_SIZE{1} = detectWordSize();
22310    }
22311    if(not $Descriptor{2}{"Dump"})
22312    {
22313        if(not $CheckHeadersOnly) {
22314            readLibs(2);
22315        }
22316        if($CheckHeadersOnly) {
22317            setLanguage(2, "C++");
22318        }
22319        if(not $CheckObjectsOnly) {
22320            searchForHeaders(2);
22321        }
22322        $WORD_SIZE{2} = detectWordSize();
22323    }
22324    if($WORD_SIZE{1} ne $WORD_SIZE{2})
22325    { # support for old ABI dumps
22326      # try to synch different WORD sizes
22327        if(not checkDump(1, "2.1"))
22328        {
22329            $WORD_SIZE{1} = $WORD_SIZE{2};
22330            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
22331        }
22332        elsif(not checkDump(2, "2.1"))
22333        {
22334            $WORD_SIZE{2} = $WORD_SIZE{1};
22335            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
22336        }
22337    }
22338    elsif(not $WORD_SIZE{1}
22339    and not $WORD_SIZE{2})
22340    { # support for old ABI dumps
22341        $WORD_SIZE{1} = "4";
22342        $WORD_SIZE{2} = "4";
22343    }
22344    if($Descriptor{1}{"Dump"})
22345    { # support for old ABI dumps
22346        prepareTypes(1);
22347    }
22348    if($Descriptor{2}{"Dump"})
22349    { # support for old ABI dumps
22350        prepareTypes(2);
22351    }
22352    if($AppPath and not keys(%{$Symbol_Library{1}})) {
22353        printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
22354    }
22355    # started to process input data
22356    if(not $CheckObjectsOnly)
22357    {
22358        if($Descriptor{1}{"Headers"}
22359        and not $Descriptor{1}{"Dump"}) {
22360            readHeaders(1);
22361        }
22362        if($Descriptor{2}{"Headers"}
22363        and not $Descriptor{2}{"Dump"}) {
22364            readHeaders(2);
22365        }
22366    }
22367
22368    # clean memory
22369    %SystemHeaders = ();
22370    %mangled_name_gcc = ();
22371
22372    prepareSymbols(1);
22373    prepareSymbols(2);
22374
22375    # clean memory
22376    %SymbolInfo = ();
22377
22378    # Virtual Tables
22379    registerVTable(1);
22380    registerVTable(2);
22381
22382    if(not checkDump(1, "1.22")
22383    and checkDump(2, "1.22"))
22384    { # support for old ABI dumps
22385        foreach my $ClassName (keys(%{$VirtualTable{2}}))
22386        {
22387            if($ClassName=~/</)
22388            { # templates
22389                if(not defined $VirtualTable{1}{$ClassName})
22390                { # synchronize
22391                    delete($VirtualTable{2}{$ClassName});
22392                }
22393            }
22394        }
22395    }
22396
22397    registerOverriding(1);
22398    registerOverriding(2);
22399
22400    setVirtFuncPositions(1);
22401    setVirtFuncPositions(2);
22402
22403    # Other
22404    addParamNames(1);
22405    addParamNames(2);
22406
22407    detectChangedTypedefs();
22408}
22409
22410sub compareAPIs($)
22411{
22412    my $Level = $_[0];
22413    readRules($Level);
22414    loadModule("CallConv");
22415    if($Level eq "Binary") {
22416        printMsg("INFO", "comparing ABIs ...");
22417    }
22418    else {
22419        printMsg("INFO", "comparing APIs ...");
22420    }
22421    if($CheckHeadersOnly
22422    or $Level eq "Source")
22423    { # added/removed in headers
22424        detectAdded_H($Level);
22425        detectRemoved_H($Level);
22426    }
22427    else
22428    { # added/removed in libs
22429        detectAdded($Level);
22430        detectRemoved($Level);
22431    }
22432    if(not $CheckObjectsOnly)
22433    {
22434        mergeSymbols($Level);
22435        if(keys(%{$CheckedSymbols{$Level}})) {
22436            mergeConstants($Level);
22437        }
22438    }
22439
22440    $Cache{"mergeTypes"} = (); # free memory
22441
22442    if($CheckHeadersOnly
22443    or $Level eq "Source")
22444    { # added/removed in headers
22445        mergeHeaders($Level);
22446    }
22447    else
22448    { # added/removed in libs
22449        mergeLibs($Level);
22450        if($CheckImpl
22451        and $Level eq "Binary") {
22452            mergeImpl();
22453        }
22454    }
22455}
22456
22457sub getSysOpts()
22458{
22459    my %Opts = (
22460    "OStarget"=>$OStarget,
22461    "Debug"=>$Debug,
22462    "Quiet"=>$Quiet,
22463    "LogMode"=>$LogMode,
22464    "CheckHeadersOnly"=>$CheckHeadersOnly,
22465
22466    "SystemRoot"=>$SystemRoot,
22467    "MODULES_DIR"=>$MODULES_DIR,
22468    "GCC_PATH"=>$GCC_PATH,
22469    "TargetSysInfo"=>$TargetSysInfo,
22470    "CrossPrefix"=>$CrossPrefix,
22471    "TargetLibraryName"=>$TargetLibraryName,
22472    "CrossGcc"=>$CrossGcc,
22473    "UseStaticLibs"=>$UseStaticLibs,
22474    "NoStdInc"=>$NoStdInc,
22475
22476    "BinaryOnly" => $BinaryOnly,
22477    "SourceOnly" => $SourceOnly
22478    );
22479    return \%Opts;
22480}
22481
22482sub get_CodeError($)
22483{
22484    my %CODE_ERROR = reverse(%ERROR_CODE);
22485    return $CODE_ERROR{$_[0]};
22486}
22487
22488sub scenario()
22489{
22490    if($StdOut)
22491    { # enable quiet mode
22492        $Quiet = 1;
22493        $JoinReport = 1;
22494    }
22495    if(not $LogMode)
22496    { # default
22497        $LogMode = "w";
22498    }
22499    if($UserLang)
22500    { # --lang=C++
22501        $UserLang = uc($UserLang);
22502        $COMMON_LANGUAGE{1}=$UserLang;
22503        $COMMON_LANGUAGE{2}=$UserLang;
22504    }
22505    if($LoggingPath)
22506    {
22507        $OutputLogPath{1} = $LoggingPath;
22508        $OutputLogPath{2} = $LoggingPath;
22509        if($Quiet) {
22510            $COMMON_LOG_PATH = $LoggingPath;
22511        }
22512    }
22513    if($Quick) {
22514        $ADD_TMPL_INSTANCES = 0;
22515    }
22516    if($OutputDumpPath)
22517    { # validate
22518        if(not isDump($OutputDumpPath)) {
22519            exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
22520        }
22521    }
22522    if($BinaryOnly and $SourceOnly)
22523    { # both --binary and --source
22524      # is the default mode
22525        $DoubleReport = 1;
22526        $JoinReport = 0;
22527        $BinaryOnly = 0;
22528        $SourceOnly = 0;
22529        if($OutputReportPath)
22530        { # --report-path
22531            $DoubleReport = 0;
22532            $JoinReport = 1;
22533        }
22534    }
22535    elsif($BinaryOnly or $SourceOnly)
22536    { # --binary or --source
22537        $DoubleReport = 0;
22538        $JoinReport = 0;
22539    }
22540    if($UseXML)
22541    { # --xml option
22542        $ReportFormat = "xml";
22543        $DumpFormat = "xml";
22544    }
22545    if($ReportFormat)
22546    { # validate
22547        $ReportFormat = lc($ReportFormat);
22548        if($ReportFormat!~/\A(xml|html|htm)\Z/) {
22549            exitStatus("Error", "unknown report format \'$ReportFormat\'");
22550        }
22551        if($ReportFormat eq "htm")
22552        { # HTM == HTML
22553            $ReportFormat = "html";
22554        }
22555        elsif($ReportFormat eq "xml")
22556        { # --report-format=XML equal to --xml
22557            $UseXML = 1;
22558        }
22559    }
22560    else
22561    { # default: HTML
22562        $ReportFormat = "html";
22563    }
22564    if($DumpFormat)
22565    { # validate
22566        $DumpFormat = lc($DumpFormat);
22567        if($DumpFormat!~/\A(xml|perl)\Z/) {
22568            exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
22569        }
22570        if($DumpFormat eq "xml")
22571        { # --dump-format=XML equal to --xml
22572            $UseXML = 1;
22573        }
22574    }
22575    else
22576    { # default: Perl Data::Dumper
22577        $DumpFormat = "perl";
22578    }
22579    if($Quiet and $LogMode!~/a|n/)
22580    { # --quiet log
22581        if(-f $COMMON_LOG_PATH) {
22582            unlink($COMMON_LOG_PATH);
22583        }
22584    }
22585    if($ExtraInfo) {
22586        $CheckUndefined = 1;
22587    }
22588    if($TestTool and $UseDumps)
22589    { # --test && --use-dumps == --test-dump
22590        $TestDump = 1;
22591    }
22592    if($Tolerant)
22593    { # enable all
22594        $Tolerance = 1234;
22595    }
22596    if($Help)
22597    {
22598        HELP_MESSAGE();
22599        exit(0);
22600    }
22601    if($InfoMsg) {
22602        INFO_MESSAGE();
22603        exit(0);
22604    }
22605    if($ShowVersion)
22606    {
22607        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.");
22608        exit(0);
22609    }
22610    if($DumpVersion)
22611    {
22612        printMsg("INFO", $TOOL_VERSION);
22613        exit(0);
22614    }
22615    if($ExtendedCheck) {
22616        $CheckHeadersOnly = 1;
22617    }
22618    if($SystemRoot_Opt)
22619    { # user defined root
22620        if(not -e $SystemRoot_Opt) {
22621            exitStatus("Access_Error", "can't access \'$SystemRoot\'");
22622        }
22623        $SystemRoot = $SystemRoot_Opt;
22624        $SystemRoot=~s/[\/]+\Z//g;
22625        if($SystemRoot) {
22626            $SystemRoot = get_abs_path($SystemRoot);
22627        }
22628    }
22629    $Data::Dumper::Sortkeys = 1;
22630
22631    if($SortDump)
22632    {
22633        $Data::Dumper::Useperl = 1;
22634        $Data::Dumper::Sortkeys = \&dump_sorting;
22635    }
22636
22637    if($TargetLibsPath)
22638    {
22639        if(not -f $TargetLibsPath) {
22640            exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
22641        }
22642        foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
22643            $TargetLibs{$Lib} = 1;
22644        }
22645    }
22646    if($TargetHeadersPath)
22647    { # --headers-list
22648        if(not -f $TargetHeadersPath) {
22649            exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
22650        }
22651        foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
22652        {
22653            $TargetHeaders{1}{$Header} = 1;
22654            $TargetHeaders{2}{$Header} = 1;
22655        }
22656    }
22657    if($TargetHeader)
22658    { # --header
22659        $TargetHeaders{1}{$TargetHeader} = 1;
22660        $TargetHeaders{2}{$TargetHeader} = 1;
22661    }
22662    if($TestTool
22663    or $TestDump)
22664    { # --test, --test-dump
22665        detect_default_paths("bin|gcc"); # to compile libs
22666        loadModule("RegTests");
22667        testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
22668        $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
22669        exit(0);
22670    }
22671    if($DumpSystem)
22672    { # --dump-system
22673        loadModule("SysCheck");
22674        if($DumpSystem=~/\.(xml|desc)\Z/)
22675        { # system XML descriptor
22676            if(not -f $DumpSystem) {
22677                exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
22678            }
22679            my $Ret = readSystemDescriptor(readFile($DumpSystem));
22680            foreach (@{$Ret->{"Tools"}})
22681            {
22682                push_U($SystemPaths{"bin"}, $_);
22683                $TargetTools{$_} = 1;
22684            }
22685            if($Ret->{"CrossPrefix"}) {
22686                $CrossPrefix = $Ret->{"CrossPrefix"};
22687            }
22688        }
22689        elsif($SystemRoot_Opt)
22690        { # -sysroot "/" option
22691          # default target: /usr/lib, /usr/include
22692          # search libs: /usr/lib and /lib
22693            if(not -e $SystemRoot."/usr/lib") {
22694                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
22695            }
22696            if(not -e $SystemRoot."/lib") {
22697                exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
22698            }
22699            if(not -e $SystemRoot."/usr/include") {
22700                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
22701            }
22702            readSystemDescriptor("
22703                <name>
22704                    $DumpSystem
22705                </name>
22706                <headers>
22707                    $SystemRoot/usr/include
22708                </headers>
22709                <libs>
22710                    $SystemRoot/usr/lib
22711                </libs>
22712                <search_libs>
22713                    $SystemRoot/lib
22714                </search_libs>");
22715        }
22716        else {
22717            exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
22718        }
22719        detect_default_paths("bin|gcc"); # to check symbols
22720        if($OStarget eq "windows")
22721        { # to run dumpbin.exe
22722          # and undname.exe
22723            check_win32_env();
22724        }
22725        dumpSystem(getSysOpts());
22726        exit(0);
22727    }
22728    if($CmpSystems)
22729    { # --cmp-systems
22730        detect_default_paths("bin"); # to extract dumps
22731        loadModule("SysCheck");
22732        cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
22733        exit(0);
22734    }
22735    if($GenerateTemplate)
22736    {
22737        writeFile("VERSION.xml", $DescriptorTemplate."\n");
22738        printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
22739        exit(0);
22740    }
22741    if(not $TargetLibraryName) {
22742        exitStatus("Error", "library name is not selected (-l option)");
22743    }
22744    else
22745    { # validate library name
22746        if($TargetLibraryName=~/[\*\/\\]/) {
22747            exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
22748        }
22749    }
22750    if(not $TargetLibraryFName) {
22751        $TargetLibraryFName = $TargetLibraryName;
22752    }
22753    if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
22754        exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
22755    }
22756    if($SymbolsListPath)
22757    {
22758        if(not -f $SymbolsListPath) {
22759            exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
22760        }
22761        foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
22762            $SymbolsList{$Interface} = 1;
22763        }
22764    }
22765    if($SkipSymbolsListPath)
22766    {
22767        if(not -f $SkipSymbolsListPath) {
22768            exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'");
22769        }
22770        foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) {
22771            $SkipSymbolsList{$Interface} = 1;
22772        }
22773    }
22774    if($SkipHeadersPath)
22775    {
22776        if(not -f $SkipHeadersPath) {
22777            exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
22778        }
22779        foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
22780        { # register for both versions
22781            $SkipHeadersList{1}{$Path} = 1;
22782            $SkipHeadersList{2}{$Path} = 1;
22783            my ($CPath, $Type) = classifyPath($Path);
22784            $SkipHeaders{1}{$Type}{$CPath} = 1;
22785            $SkipHeaders{2}{$Type}{$CPath} = 1;
22786        }
22787    }
22788    if($ParamNamesPath)
22789    {
22790        if(not -f $ParamNamesPath) {
22791            exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
22792        }
22793        foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
22794        {
22795            if($Line=~s/\A(\w+)\;//)
22796            {
22797                my $Interface = $1;
22798                if($Line=~/;(\d+);/)
22799                {
22800                    while($Line=~s/(\d+);(\w+)//) {
22801                        $AddIntParams{$Interface}{$1}=$2;
22802                    }
22803                }
22804                else
22805                {
22806                    my $Num = 0;
22807                    foreach my $Name (split(/;/, $Line)) {
22808                        $AddIntParams{$Interface}{$Num++}=$Name;
22809                    }
22810                }
22811            }
22812        }
22813    }
22814    if($AppPath)
22815    {
22816        if(not -f $AppPath) {
22817            exitStatus("Access_Error", "can't access file \'$AppPath\'");
22818        }
22819        foreach my $Interface (readSymbols_App($AppPath)) {
22820            $SymbolsList_App{$Interface} = 1;
22821        }
22822    }
22823    if($DumpAPI)
22824    { # --dump-abi
22825      # make an API dump
22826        create_ABI_Dump();
22827        exit($COMPILE_ERRORS);
22828    }
22829    # default: compare APIs
22830    #  -d1 <path>
22831    #  -d2 <path>
22832    compareInit();
22833    if($JoinReport or $DoubleReport)
22834    {
22835        compareAPIs("Binary");
22836        compareAPIs("Source");
22837    }
22838    elsif($BinaryOnly) {
22839        compareAPIs("Binary");
22840    }
22841    elsif($SourceOnly) {
22842        compareAPIs("Source");
22843    }
22844    exitReport();
22845}
22846
22847scenario();
22848