blob: 5186881e6875a9bea8ee45ef7fc22c5e58650aa7 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003# ABI Compliance Checker (ACC) 1.98.5
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004# A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005#
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006# Copyright (C) 2009-2010 The Linux Foundation
7# Copyright (C) 2009-2011 Institute for System Programming, RAS
8# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9# Copyright (C) 2011-2012 ROSA Laboratory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010#
11# Written by Andrey Ponomarenko
12#
13# PLATFORMS
14# =========
15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16#
17# REQUIREMENTS
18# ============
19# Linux
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020# - G++ (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040021# - GNU Binutils (readelf, c++filt, objdump)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040022# - Perl 5 (5.8 or newer)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040023# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040024#
25# Mac OS X
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040026# - Xcode (g++, c++filt, otool, nm)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040027# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040028#
29# MS Windows
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040030# - MinGW (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040031# - MS Visual C++ (dumpbin, undname, cl)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040032# - Active Perl 5 (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040033# - Sigcheck v1.71 or newer
34# - Info-ZIP 3.0 (zip, unzip)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040035# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040036# - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
37# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
38#
39# This program is free software: you can redistribute it and/or modify
40# it under the terms of the GNU General Public License or the GNU Lesser
41# General Public License as published by the Free Software Foundation.
42#
43# This program is distributed in the hope that it will be useful,
44# but WITHOUT ANY WARRANTY; without even the implied warranty of
45# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46# GNU General Public License for more details.
47#
48# You should have received a copy of the GNU General Public License
49# and the GNU Lesser General Public License along with this program.
50# If not, see <http://www.gnu.org/licenses/>.
51###########################################################################
52use Getopt::Long;
53Getopt::Long::Configure ("posix_default", "no_ignore_case");
54use File::Path qw(mkpath rmtree);
55use File::Temp qw(tempdir);
56use File::Copy qw(copy move);
57use Cwd qw(abs_path cwd);
58use Data::Dumper;
Andrey Ponomarenko2fba6302012-03-29 17:44:47 +040059use Config;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040060use Fcntl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040061
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040062my $TOOL_VERSION = "1.98.5";
63my $ABI_DUMP_VERSION = "2.19.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040064my $OLDEST_SUPPORTED_VERSION = "1.18";
65my $XML_REPORT_VERSION = "1.0";
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040066my $XML_ABI_DUMP_VERSION = "1.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040067my $OSgroup = get_OSgroup();
68my $ORIG_DIR = cwd();
69my $TMP_DIR = tempdir(CLEANUP=>1);
70
71# Internal modules
72my $MODULES_DIR = get_Modules();
73push(@INC, get_dirname($MODULES_DIR));
74# Rules DB
75my %RULES_PATH = (
76 "Binary" => $MODULES_DIR."/RulesBin.xml",
77 "Source" => $MODULES_DIR."/RulesSrc.xml");
78
79my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
80$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
81$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
82%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
83%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
84$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
85$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
86$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040087$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040088$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040089$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040090$ExtraInfo, $ExtraDump, $Force);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040091
92my $CmdName = get_filename($0);
93my %OS_LibExt = (
94 "dynamic" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040095 "linux"=>"so",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040096 "macos"=>"dylib",
97 "windows"=>"dll",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040098 "symbian"=>"dso",
99 "default"=>"so"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400100 },
101 "static" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400102 "linux"=>"a",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400103 "windows"=>"lib",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400104 "symbian"=>"lib",
105 "default"=>"a"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400106 }
107);
108
109my %OS_Archive = (
110 "windows"=>"zip",
111 "default"=>"tar.gz"
112);
113
114my %ERROR_CODE = (
115 # Compatible verdict
116 "Compatible"=>0,
117 "Success"=>0,
118 # Incompatible verdict
119 "Incompatible"=>1,
120 # Undifferentiated error code
121 "Error"=>2,
122 # System command is not found
123 "Not_Found"=>3,
124 # Cannot access input files
125 "Access_Error"=>4,
126 # Cannot compile header files
127 "Cannot_Compile"=>5,
128 # Header compiled with errors
129 "Compile_Error"=>6,
130 # Invalid input ABI dump
131 "Invalid_Dump"=>7,
132 # Incompatible version of ABI dump
133 "Dump_Version"=>8,
134 # Cannot find a module
135 "Module_Error"=>9,
136 # Empty intersection between
137 # headers and shared objects
138 "Empty_Intersection"=>10,
139 # Empty set of symbols in headers
140 "Empty_Set"=>11
141);
142
143my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400144 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400145 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
146 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400147);
148
149my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400150A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400151Copyright (C) 2012 ROSA Laboratory
152License: GNU LGPL or GNU GPL
153
154Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400155Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400156
157OLD.xml and NEW.xml are XML-descriptors:
158
159 <version>
160 1.0
161 </version>
162
163 <headers>
164 /path/to/headers/
165 </headers>
166
167 <libs>
168 /path/to/libraries/
169 </libs>
170
171More info: $CmdName --help\n";
172
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400173if($#ARGV==-1)
174{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400175 printMsg("INFO", $ShortUsage);
176 exit(0);
177}
178
179foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400180{ # correct comma separated options
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400181 if($ARGV[$_-1] eq ",")
182 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400183 $ARGV[$_-2].=",".$ARGV[$_];
184 splice(@ARGV, $_-1, 2);
185 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400186 elsif($ARGV[$_-1]=~/,\Z/)
187 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400188 $ARGV[$_-1].=$ARGV[$_];
189 splice(@ARGV, $_, 1);
190 }
191 elsif($ARGV[$_]=~/\A,/
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400192 and $ARGV[$_] ne ",")
193 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400194 $ARGV[$_-1].=$ARGV[$_];
195 splice(@ARGV, $_, 1);
196 }
197}
198
199GetOptions("h|help!" => \$Help,
200 "i|info!" => \$InfoMsg,
201 "v|version!" => \$ShowVersion,
202 "dumpversion!" => \$DumpVersion,
203# general options
204 "l|lib|library=s" => \$TargetLibraryName,
205 "d1|old|o=s" => \$Descriptor{1}{"Path"},
206 "d2|new|n=s" => \$Descriptor{2}{"Path"},
207 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
208 "old-dumps!" => \$UseOldDumps,
209# extra options
210 "d|descriptor-template!" => \$GenerateTemplate,
211 "app|application=s" => \$AppPath,
212 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400213 "cross-gcc|gcc-path=s" => \$CrossGcc,
214 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400215 "sysroot=s" => \$SystemRoot_Opt,
216 "v1|version1|vnum=s" => \$TargetVersion{1},
217 "v2|version2=s" => \$TargetVersion{2},
218 "s|strict!" => \$StrictCompat,
219 "symbols-list=s" => \$SymbolsListPath,
220 "skip-headers=s" => \$SkipHeadersPath,
221 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
222 "objects-only!" => \$CheckObjectsOnly_Opt,
223 "check-impl|check-implementation!" => \$CheckImpl,
224 "show-retval!" => \$ShowRetVal,
225 "use-dumps!" => \$UseDumps,
226 "nostdinc!" => \$NoStdInc,
227 "dump-system=s" => \$DumpSystem,
228 "sysinfo=s" => \$TargetSysInfo,
229 "cmp-systems!" => \$CmpSystems,
230 "libs-list=s" => \$TargetLibsPath,
231 "headers-list=s" => \$TargetHeadersPath,
232 "header=s" => \$TargetHeader,
233 "ext|extended!" => \$ExtendedCheck,
234 "q|quiet!" => \$Quiet,
235 "stdout!" => \$StdOut,
236 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400237 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400238 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400239 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400240 "binary|bin|abi!" => \$BinaryOnly,
241 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400242# other options
243 "test!" => \$TestTool,
244 "test-dump!" => \$TestDump,
245 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400246 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400247 "p|params=s" => \$ParamNamesPath,
248 "relpath1|relpath=s" => \$RelativeDirectory{1},
249 "relpath2=s" => \$RelativeDirectory{2},
250 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400251 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400252 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400253 "bin-report-path=s" => \$BinaryReportPath,
254 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400255 "log-path=s" => \$LoggingPath,
256 "log1-path=s" => \$OutputLogPath{1},
257 "log2-path=s" => \$OutputLogPath{2},
258 "logging-mode=s" => \$LogMode,
259 "list-affected!" => \$ListAffected,
260 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400261 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400262 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400263 "open!" => \$OpenReport,
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400264 "extra-info=s" => \$ExtraInfo,
265 "extra-dump!" => \$ExtraDump,
266 "force!" => \$Force
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400267) or ERR_MESSAGE();
268
269sub ERR_MESSAGE()
270{
271 printMsg("INFO", "\n".$ShortUsage);
272 exit($ERROR_CODE{"Error"});
273}
274
275my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
276my $SLIB_TYPE = $LIB_TYPE;
277if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
278{ # show as "shared" library
279 $SLIB_TYPE = "shared";
280}
281my $LIB_EXT = getLIB_EXT($OSgroup);
282my $AR_EXT = getAR_EXT($OSgroup);
283my $BYTE_SIZE = 8;
284my $COMMON_LOG_PATH = "logs/run.log";
285
286my $HelpMessage="
287NAME:
288 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400289 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400290
291DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400292 ABI Compliance Checker (ACC) is a tool for checking backward binary and
293 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
294 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
295 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
296 and/or source-level compatibility: changes in calling stack, v-table changes,
297 removed symbols, renamed fields, etc. Binary incompatibility may result in
298 crashing or incorrect behavior of applications built with an old version of
299 a library if they run on a new one. Source incompatibility may result in
300 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400301
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400302 The tool is intended for developers of software libraries and maintainers
303 of operating systems who are interested in ensuring backward compatibility,
304 i.e. allow old applications to run or to be recompiled with newer library
305 versions.
306
307 Also the tool can be used by ISVs for checking applications portability to
308 new library versions. Found issues can be taken into account when adapting
309 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400310
311 This tool is free software: you can redistribute it and/or modify it
312 under the terms of the GNU LGPL or GNU GPL.
313
314USAGE:
315 $CmdName [options]
316
317EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400318 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400319
320 OLD.xml and NEW.xml are XML-descriptors:
321
322 <version>
323 1.0
324 </version>
325
326 <headers>
327 /path1/to/header(s)/
328 /path2/to/header(s)/
329 ...
330 </headers>
331
332 <libs>
333 /path1/to/library(ies)/
334 /path2/to/library(ies)/
335 ...
336 </libs>
337
338INFORMATION OPTIONS:
339 -h|-help
340 Print this help.
341
342 -i|-info
343 Print complete info.
344
345 -v|-version
346 Print version information.
347
348 -dumpversion
349 Print the tool version ($TOOL_VERSION) and don't do anything else.
350
351GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400352 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400353 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400354
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400355 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400356 Descriptor of 1st (old) library version.
357 It may be one of the following:
358
359 1. XML-descriptor (VERSION.xml file):
360
361 <version>
362 1.0
363 </version>
364
365 <headers>
366 /path1/to/header(s)/
367 /path2/to/header(s)/
368 ...
369 </headers>
370
371 <libs>
372 /path1/to/library(ies)/
373 /path2/to/library(ies)/
374 ...
375 </libs>
376
377 ... (XML-descriptor template
378 can be generated by -d option)
379
380 2. ABI dump generated by -dump option
381 3. Directory with headers and/or $SLIB_TYPE libraries
382 4. Single header file
383 5. Single $SLIB_TYPE library
384 6. Comma separated list of headers and/or libraries
385
386 If you are using an 2-6 descriptor types then you should
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400387 specify version numbers with -v1 and -v2 options too.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400388
389 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400390 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400391
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400392 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400393 Descriptor of 2nd (new) library version.
394
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400395 -dump|-dump-abi PATH
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400396 Create library ABI dump for the input XML descriptor. You can
397 transfer it anywhere and pass instead of the descriptor. Also
398 it can be used for debugging the tool.
399
400 Supported ABI dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400401
402 -old-dumps
403 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
404
405sub HELP_MESSAGE() {
406 printMsg("INFO", $HelpMessage."
407MORE INFO:
408 $CmdName --info\n");
409}
410
411sub INFO_MESSAGE()
412{
413 printMsg("INFO", "$HelpMessage
414EXTRA OPTIONS:
415 -d|-descriptor-template
416 Create XML-descriptor template ./VERSION.xml
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 This option allows to specify the application that should be checked
420 for portability to the new library version.
421
422 -static-libs
423 Check static libraries instead of the shared ones. The <libs> section
424 of the XML-descriptor should point to static libraries location.
425
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427 Path to the cross GCC compiler to use instead of the usual (host) GCC.
428
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400429 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400430 GCC toolchain prefix.
431
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400432 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400433 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400434 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400435
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400436 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400437 Specify 1st library version outside the descriptor. This option is needed
438 if you have prefered an alternative descriptor type (see -d1 option).
439
440 In general case you should specify it in the XML-descriptor:
441 <version>
442 VERSION
443 </version>
444
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400445 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400446 Specify 2nd library version outside the descriptor.
447
448 -s|-strict
449 Treat all compatibility warnings as problems. Add a number of \"Low\"
450 severity problems to the return value of the tool.
451
452 -headers-only
453 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
454 provide a low quality compatibility report with false positives and
455 without detecting of added/removed symbols.
456
457 Alternatively you can write \"none\" word to the <libs> section
458 in the XML-descriptor:
459 <libs>
460 none
461 </libs>
462
463 -objects-only
464 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
465 provide a low quality compatibility report with false positives and
466 without analysis of changes in parameters and data types.
467
468 Alternatively you can write \"none\" word to the <headers> section
469 in the XML-descriptor:
470 <headers>
471 none
472 </headers>
473
474 -check-impl|-check-implementation
475 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
476 detect changes in the implementation. Add \'Problems with Implementation\'
477 section to the report.
478
479 -show-retval
480 Show the symbol's return type in the report.
481
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400482 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400483 This option allows to specify a file with a list of symbols (mangled
484 names in C++) that should be checked, other symbols will not be checked.
485
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400486 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400487 The file with the list of header files, that should not be checked.
488
489 -use-dumps
490 Make dumps for two versions of a library and compare dumps. This should
491 increase the performance of the tool and decrease the system memory usage.
492
493 -nostdinc
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400494 Do not search in GCC standard system directories for header files.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400495
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 -dump-system NAME -sysroot DIR
497 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400498 create XML descriptors and make ABI dumps for each library. The result
499 set of ABI dumps can be compared (--cmp-systems) with the other one
500 created for other version of operating system in order to check them for
501 compatibility. Do not forget to specify -cross-gcc option if your target
502 system requires some specific version of GCC compiler (different from
503 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400504 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400505
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400506 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400507 The same as the previous option but takes an XML descriptor of the target
508 system as input, where you should describe it:
509
510 /* Primary sections */
511
512 <name>
513 /* Name of the system */
514 </name>
515
516 <headers>
517 /* The list of paths to header files and/or
518 directories with header files, one per line */
519 </headers>
520
521 <libs>
522 /* The list of paths to shared libraries and/or
523 directories with shared libraries, one per line */
524 </libs>
525
526 /* Optional sections */
527
528 <search_headers>
529 /* List of directories to be searched
530 for header files to automatically
531 generate include paths, one per line */
532 </search_headers>
533
534 <search_libs>
535 /* List of directories to be searched
536 for shared libraries to resolve
537 dependencies, one per line */
538 </search_libs>
539
540 <tools>
541 /* List of directories with tools used
542 for analysis (GCC toolchain), one per line */
543 </tools>
544
545 <cross_prefix>
546 /* GCC toolchain prefix.
547 Examples:
548 arm-linux-gnueabi
549 arm-none-symbianelf */
550 </cross_prefix>
551
552 <gcc_options>
553 /* Additional GCC options, one per line */
554 </gcc_options>
555
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400556 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400557 This option may be used with -dump-system to dump ABI of operating
558 systems and configure the dumping process.
559 Default:
560 modules/Targets/{unix, symbian, windows}
561
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400562 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400563 Compare two system ABI dumps. Create compatibility reports for each
564 library and the common HTML report including the summary of test
565 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400566 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400567
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400568 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400569 The file with a list of libraries, that should be dumped by
570 the -dump-system option or should be checked by the -cmp-systems option.
571
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400572 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400573 Check/Dump ABI of this header only.
574
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400575 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400576 The file with a list of headers, that should be checked/dumped.
577
578 -ext|-extended
579 If your library A is supposed to be used by other library B and you
580 want to control the ABI of B, then you should enable this option. The
581 tool will check for changes in all data types, even if they are not
582 used by any function in the library A. Such data types are not part
583 of the A library ABI, but may be a part of the ABI of the B library.
584
585 The short scheme is:
586 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
587
588 -q|-quiet
589 Print all messages to the file instead of stdout and stderr.
590 Default path (can be changed by -log-path option):
591 $COMMON_LOG_PATH
592
593 -stdout
594 Print analysis results (compatibility reports and ABI dumps) to stdout
595 instead of creating a file. This would allow piping data to other programs.
596
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400597 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400598 Change format of compatibility report.
599 Formats:
600 htm - HTML format (default)
601 xml - XML format
602
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400603 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400604 Change format of ABI dump.
605 Formats:
606 perl - Data::Dumper format (default)
607 xml - XML format
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400610 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400611
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400613 Set library language (C or C++). You can use this option if the tool
614 cannot auto-detect a language. This option may be useful for checking
615 C-library headers (--lang=C) in --headers-only or --extended modes.
616
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400617 -binary|-bin|-abi
618 Show \"Binary\" compatibility problems only.
619 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400620 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400621
622 -source|-src|-api
623 Show \"Source\" compatibility problems only.
624 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400625 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400626
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400627OTHER OPTIONS:
628 -test
629 Run internal tests. Create two binary incompatible versions of a sample
630 library and run the tool to check them for compatibility. This option
631 allows to check if the tool works correctly in the current environment.
632
633 -test-dump
634 Test ability to create, read and compare ABI dumps.
635
636 -debug
637 Debugging mode. Print debug info on the screen. Save intermediate
638 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400639 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400640
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400641 Also consider using --dump option for debugging the tool.
642
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400643 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400644 If your header files are written in C language and can be compiled
645 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
646 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400647
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400648 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400649 Path to file with the function parameter names. It can be used
650 for improving report view if the library header files have no
651 parameter names. File format:
652
653 func1;param1;param2;param3 ...
654 func2;param1;param2;param3 ...
655 ...
656
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400657 -relpath PATH
658 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400659 for dumping the library ABI (see -dump option).
660
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400661 -relpath1 PATH
662 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400664 -relpath2 PATH
665 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400668 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400671
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400672 -sort
673 Enable sorting of data in ABI dumps.
674
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400676 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400677 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400678 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400679
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400682 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400683 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400684
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400686 Path to \"Source\" compatibility report.
687 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400688 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400689
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691 Log path for all messages.
692 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400693 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400694
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696 Log path for 1st version of a library.
697 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400698 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400699
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400700 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400701 Log path for 2nd version of a library.
702 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400703 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400704
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400705 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400706 Change logging mode.
707 Modes:
708 w - overwrite old logs (default)
709 a - append old logs
710 n - do not write any logs
711
712 -list-affected
713 Generate file with the list of incompatible
714 symbols beside the HTML compatibility report.
715 Use 'c++filt \@file' command from GNU binutils
716 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400717 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400718 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400719 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400721 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400722 The component name in the title and summary of the HTML report.
723 Default:
724 library
725
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400726 -l-full|-lib-full NAME
727 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400728 will be displayed a name specified by -l option.
729
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400730 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400731 Open report(s) in the browser (firefox, opera, etc.).
732
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400733 -open
734 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400735
736 -extra-info DIR
737 Dump extra info to DIR.
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400738
739 -extra-dump
740 Create extended ABI dump containing all symbols
741 from the translation unit.
742
743 -force
744 Try to use this option if the tool doesn't work.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400745
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400746REPORT:
747 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400748 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749
750 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400751 logs/LIB_NAME/V1/log.txt
752 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400753
754EXIT CODES:
755 0 - Compatible. The tool has run without any errors.
756 non-zero - Incompatible or the tool has run with errors.
757
758REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400759 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400760
761MORE INFORMATION:
762 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400763 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400764}
765
766my $DescriptorTemplate = "
767<?xml version=\"1.0\" encoding=\"utf-8\"?>
768<descriptor>
769
770/* Primary sections */
771
772<version>
773 /* Version of the library */
774</version>
775
776<headers>
777 /* The list of paths to header files and/or
778 directories with header files, one per line */
779</headers>
780
781<libs>
782 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
783 directories with shared libraries, one per line */
784</libs>
785
786/* Optional sections */
787
788<include_paths>
789 /* The list of include paths that will be provided
790 to GCC to compile library headers, one per line.
791 NOTE: If you define this section then the tool
792 will not automatically generate include paths */
793</include_paths>
794
795<add_include_paths>
796 /* The list of include paths that will be added
797 to the automatically generated include paths, one per line */
798</add_include_paths>
799
800<skip_include_paths>
801 /* The list of include paths that will be removed from the
802 list of automatically generated include paths, one per line */
803</skip_include_paths>
804
805<gcc_options>
806 /* Additional GCC options, one per line */
807</gcc_options>
808
809<include_preamble>
810 /* The list of header files that will be
811 included before other headers, one per line.
812 Examples:
813 1) tree.h for libxml2
814 2) ft2build.h for freetype2 */
815</include_preamble>
816
817<defines>
818 /* The list of defines that will be added at the
819 headers compiling stage, one per line:
820 #define A B
821 #define C D */
822</defines>
823
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400824<add_namespaces>
825 /* The list of namespaces that should be added to the alanysis
826 if the tool cannot find them automatically, one per line */
827</add_namespaces>
828
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400829<skip_types>
830 /* The list of data types, that
831 should not be checked, one per line */
832</skip_types>
833
834<skip_symbols>
835 /* The list of functions (mangled/symbol names in C++),
836 that should not be checked, one per line */
837</skip_symbols>
838
839<skip_namespaces>
840 /* The list of C++ namespaces, that
841 should not be checked, one per line */
842</skip_namespaces>
843
844<skip_constants>
845 /* The list of constants that should
846 not be checked, one name per line */
847</skip_constants>
848
849<skip_headers>
850 /* The list of header files and/or directories
851 with header files that should not be checked, one per line */
852</skip_headers>
853
854<skip_libs>
855 /* The list of shared libraries and/or directories
856 with shared libraries that should not be checked, one per line */
857</skip_libs>
858
859<skip_including>
860 /* The list of header files, that cannot be included
861 directly (or non-self compiled ones), one per line */
862</skip_including>
863
864<search_headers>
865 /* List of directories to be searched
866 for header files to automatically
867 generate include paths, one per line. */
868</search_headers>
869
870<search_libs>
871 /* List of directories to be searched
872 for shared librariess to resolve
873 dependencies, one per line */
874</search_libs>
875
876<tools>
877 /* List of directories with tools used
878 for analysis (GCC toolchain), one per line */
879</tools>
880
881<cross_prefix>
882 /* GCC toolchain prefix.
883 Examples:
884 arm-linux-gnueabi
885 arm-none-symbianelf */
886</cross_prefix>
887
888</descriptor>";
889
890my %Operator_Indication = (
891 "not" => "~",
892 "assign" => "=",
893 "andassign" => "&=",
894 "orassign" => "|=",
895 "xorassign" => "^=",
896 "or" => "|",
897 "xor" => "^",
898 "addr" => "&",
899 "and" => "&",
900 "lnot" => "!",
901 "eq" => "==",
902 "ne" => "!=",
903 "lt" => "<",
904 "lshift" => "<<",
905 "lshiftassign" => "<<=",
906 "rshiftassign" => ">>=",
907 "call" => "()",
908 "mod" => "%",
909 "modassign" => "%=",
910 "subs" => "[]",
911 "land" => "&&",
912 "lor" => "||",
913 "rshift" => ">>",
914 "ref" => "->",
915 "le" => "<=",
916 "deref" => "*",
917 "mult" => "*",
918 "preinc" => "++",
919 "delete" => " delete",
920 "vecnew" => " new[]",
921 "vecdelete" => " delete[]",
922 "predec" => "--",
923 "postinc" => "++",
924 "postdec" => "--",
925 "plusassign" => "+=",
926 "plus" => "+",
927 "minus" => "-",
928 "minusassign" => "-=",
929 "gt" => ">",
930 "ge" => ">=",
931 "new" => " new",
932 "multassign" => "*=",
933 "divassign" => "/=",
934 "div" => "/",
935 "neg" => "-",
936 "pos" => "+",
937 "memref" => "->*",
938 "compound" => "," );
939
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400940my %UnknownOperator;
941
942my %NodeType= (
943 "array_type" => "Array",
944 "binfo" => "Other",
945 "boolean_type" => "Intrinsic",
946 "complex_type" => "Intrinsic",
947 "const_decl" => "Other",
948 "enumeral_type" => "Enum",
949 "field_decl" => "Other",
950 "function_decl" => "Other",
951 "function_type" => "FunctionType",
952 "identifier_node" => "Other",
953 "integer_cst" => "Other",
954 "integer_type" => "Intrinsic",
955 "method_type" => "MethodType",
956 "namespace_decl" => "Other",
957 "parm_decl" => "Other",
958 "pointer_type" => "Pointer",
959 "real_cst" => "Other",
960 "real_type" => "Intrinsic",
961 "record_type" => "Struct",
962 "reference_type" => "Ref",
963 "string_cst" => "Other",
964 "template_decl" => "Other",
965 "template_type_parm" => "Other",
966 "tree_list" => "Other",
967 "tree_vec" => "Other",
968 "type_decl" => "Other",
969 "union_type" => "Union",
970 "var_decl" => "Other",
971 "void_type" => "Intrinsic",
972 # "nop_expr" => "Other",
973 # "addr_expr" => "Other",
974 "offset_type" => "Other" );
975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400976my %CppKeywords_C = map {$_=>1} (
977 # C++ 2003 keywords
978 "public",
979 "protected",
980 "private",
981 "default",
982 "template",
983 "new",
984 #"asm",
985 "dynamic_cast",
986 "auto",
987 "try",
988 "namespace",
989 "typename",
990 "using",
991 "reinterpret_cast",
992 "friend",
993 "class",
994 "virtual",
995 "const_cast",
996 "mutable",
997 "static_cast",
998 "export",
999 # C++0x keywords
1000 "noexcept",
1001 "nullptr",
1002 "constexpr",
1003 "static_assert",
1004 "explicit",
1005 # cannot be used as a macro name
1006 # as it is an operator in C++
1007 "and",
1008 #"and_eq",
1009 "not",
1010 #"not_eq",
1011 "or"
1012 #"or_eq",
1013 #"bitand",
1014 #"bitor",
1015 #"xor",
1016 #"xor_eq",
1017 #"compl"
1018);
1019
1020my %CppKeywords_F = map {$_=>1} (
1021 "delete",
1022 "catch",
1023 "alignof",
1024 "thread_local",
1025 "decltype",
1026 "typeid"
1027);
1028
1029my %CppKeywords_O = map {$_=>1} (
1030 "bool",
1031 "register",
1032 "inline",
1033 "operator"
1034);
1035
1036my %CppKeywords_A = map {$_=>1} (
1037 "this",
1038 "throw"
1039);
1040
1041foreach (keys(%CppKeywords_C),
1042keys(%CppKeywords_F),
1043keys(%CppKeywords_O)) {
1044 $CppKeywords_A{$_}=1;
1045}
1046
1047# Header file extensions as described by gcc
1048my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1049
1050my %IntrinsicMangling = (
1051 "void" => "v",
1052 "bool" => "b",
1053 "wchar_t" => "w",
1054 "char" => "c",
1055 "signed char" => "a",
1056 "unsigned char" => "h",
1057 "short" => "s",
1058 "unsigned short" => "t",
1059 "int" => "i",
1060 "unsigned int" => "j",
1061 "long" => "l",
1062 "unsigned long" => "m",
1063 "long long" => "x",
1064 "__int64" => "x",
1065 "unsigned long long" => "y",
1066 "__int128" => "n",
1067 "unsigned __int128" => "o",
1068 "float" => "f",
1069 "double" => "d",
1070 "long double" => "e",
1071 "__float80" => "e",
1072 "__float128" => "g",
1073 "..." => "z"
1074);
1075
1076my %StdcxxMangling = (
1077 "3std"=>"St",
1078 "3std9allocator"=>"Sa",
1079 "3std12basic_string"=>"Sb",
1080 "3std12basic_stringIcE"=>"Ss",
1081 "3std13basic_istreamIcE"=>"Si",
1082 "3std13basic_ostreamIcE"=>"So",
1083 "3std14basic_iostreamIcE"=>"Sd"
1084);
1085
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04001086my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001087
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001088my %ConstantSuffix = (
1089 "unsigned int"=>"u",
1090 "long"=>"l",
1091 "unsigned long"=>"ul",
1092 "long long"=>"ll",
1093 "unsigned long long"=>"ull"
1094);
1095
1096my %ConstantSuffixR =
1097reverse(%ConstantSuffix);
1098
1099my %OperatorMangling = (
1100 "~" => "co",
1101 "=" => "aS",
1102 "|" => "or",
1103 "^" => "eo",
1104 "&" => "an",#ad (addr)
1105 "==" => "eq",
1106 "!" => "nt",
1107 "!=" => "ne",
1108 "<" => "lt",
1109 "<=" => "le",
1110 "<<" => "ls",
1111 "<<=" => "lS",
1112 ">" => "gt",
1113 ">=" => "ge",
1114 ">>" => "rs",
1115 ">>=" => "rS",
1116 "()" => "cl",
1117 "%" => "rm",
1118 "[]" => "ix",
1119 "&&" => "aa",
1120 "||" => "oo",
1121 "*" => "ml",#de (deref)
1122 "++" => "pp",#
1123 "--" => "mm",#
1124 "new" => "nw",
1125 "delete" => "dl",
1126 "new[]" => "na",
1127 "delete[]" => "da",
1128 "+=" => "pL",
1129 "+" => "pl",#ps (pos)
1130 "-" => "mi",#ng (neg)
1131 "-=" => "mI",
1132 "*=" => "mL",
1133 "/=" => "dV",
1134 "&=" => "aN",
1135 "|=" => "oR",
1136 "%=" => "rM",
1137 "^=" => "eO",
1138 "/" => "dv",
1139 "->*" => "pm",
1140 "->" => "pt",#rf (ref)
1141 "," => "cm",
1142 "?" => "qu",
1143 "." => "dt",
1144 "sizeof"=> "sz"#st
1145);
1146
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001147my %Intrinsic_Keywords = map {$_=>1} (
1148 "true",
1149 "false",
1150 "_Bool",
1151 "_Complex",
1152 "const",
1153 "int",
1154 "long",
1155 "void",
1156 "short",
1157 "float",
1158 "volatile",
1159 "restrict",
1160 "unsigned",
1161 "signed",
1162 "char",
1163 "double",
1164 "class",
1165 "struct",
1166 "union",
1167 "enum"
1168);
1169
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001170my %GlibcHeader = map {$_=>1} (
1171 "aliases.h",
1172 "argp.h",
1173 "argz.h",
1174 "assert.h",
1175 "cpio.h",
1176 "ctype.h",
1177 "dirent.h",
1178 "envz.h",
1179 "errno.h",
1180 "error.h",
1181 "execinfo.h",
1182 "fcntl.h",
1183 "fstab.h",
1184 "ftw.h",
1185 "glob.h",
1186 "grp.h",
1187 "iconv.h",
1188 "ifaddrs.h",
1189 "inttypes.h",
1190 "langinfo.h",
1191 "limits.h",
1192 "link.h",
1193 "locale.h",
1194 "malloc.h",
1195 "math.h",
1196 "mntent.h",
1197 "monetary.h",
1198 "nl_types.h",
1199 "obstack.h",
1200 "printf.h",
1201 "pwd.h",
1202 "regex.h",
1203 "sched.h",
1204 "search.h",
1205 "setjmp.h",
1206 "shadow.h",
1207 "signal.h",
1208 "spawn.h",
1209 "stdarg.h",
1210 "stdint.h",
1211 "stdio.h",
1212 "stdlib.h",
1213 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001214 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001215 "tar.h",
1216 "termios.h",
1217 "time.h",
1218 "ulimit.h",
1219 "unistd.h",
1220 "utime.h",
1221 "wchar.h",
1222 "wctype.h",
1223 "wordexp.h" );
1224
1225my %GlibcDir = map {$_=>1} (
1226 "arpa",
1227 "bits",
1228 "gnu",
1229 "netinet",
1230 "net",
1231 "nfs",
1232 "rpc",
1233 "sys",
1234 "linux" );
1235
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001236my %WinHeaders = map {$_=>1} (
1237 "dos.h",
1238 "process.h",
1239 "winsock.h",
1240 "config-win.h",
1241 "mem.h",
1242 "windows.h",
1243 "winsock2.h",
1244 "crtdbg.h",
1245 "ws2tcpip.h"
1246);
1247
1248my %ObsoleteHeaders = map {$_=>1} (
1249 "iostream.h",
1250 "fstream.h"
1251);
1252
1253my %ConfHeaders = map {$_=>1} (
1254 "atomic",
1255 "conf.h",
1256 "config.h",
1257 "configure.h",
1258 "build.h",
1259 "setup.h"
1260);
1261
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001262my %LocalIncludes = map {$_=>1} (
1263 "/usr/local/include",
1264 "/usr/local" );
1265
1266my %OS_AddPath=(
1267# These paths are needed if the tool cannot detect them automatically
1268 "macos"=>{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001269 "include"=>[
1270 "/Library",
1271 "/Developer/usr/include"
1272 ],
1273 "lib"=>[
1274 "/Library",
1275 "/Developer/usr/lib"
1276 ],
1277 "bin"=>[
1278 "/Developer/usr/bin"
1279 ]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001280 },
1281 "beos"=>{
1282 # Haiku has GCC 2.95.3 by default
1283 # try to find GCC>=3.0 in /boot/develop/abi
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001284 "include"=>[
1285 "/boot/common",
1286 "/boot/develop"
1287 ],
1288 "lib"=>[
1289 "/boot/common/lib",
1290 "/boot/system/lib",
1291 "/boot/apps"
1292 ],
1293 "bin"=>[
1294 "/boot/common/bin",
1295 "/boot/system/bin",
1296 "/boot/develop/abi"
1297 ]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001299);
1300
1301my %Slash_Type=(
1302 "default"=>"/",
1303 "windows"=>"\\"
1304);
1305
1306my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1307
1308# Global Variables
1309my %COMMON_LANGUAGE=(
1310 1 => "C",
1311 2 => "C" );
1312
1313my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001314my $MAX_CPPFILT_FILE_SIZE = 50000;
1315my $CPPFILT_SUPPORT_FILE;
1316
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001317my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1318
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001319my $STDCXX_TESTING = 0;
1320my $GLIBC_TESTING = 0;
1321
1322my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1323my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001324my $TargetComponent;
1325
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001326my $CheckUndefined = 0;
1327
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001328# Set Target Component Name
1329if($TargetComponent_Opt) {
1330 $TargetComponent = lc($TargetComponent_Opt);
1331}
1332else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001333{ # default: library
1334 # other components: header, system, ...
1335 $TargetComponent = "library";
1336}
1337
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001338my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1339
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my $SystemRoot;
1341
1342my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001343my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001344my %LOG_PATH;
1345my %DEBUG_PATH;
1346my %Cache;
1347my %LibInfo;
1348my $COMPILE_ERRORS = 0;
1349my %CompilerOptions;
1350my %CheckedDyLib;
1351my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1352
1353# Constants (#defines)
1354my %Constants;
1355my %SkipConstants;
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04001356my %EnumConstants;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001357
1358# Types
1359my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001361my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001362my %SkipTypes = (
1363 "1"=>{},
1364 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001365my %CheckedTypes;
1366my %TName_Tid;
1367my %EnumMembName_Id;
1368my %NestedNameSpaces = (
1369 "1"=>{},
1370 "2"=>{} );
1371my %UsedType;
1372my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001373my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001374my %ClassVTable;
1375my %ClassVTable_Content;
1376my %VTableClass;
1377my %AllocableClass;
1378my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001379my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001380my %Class_SubClasses;
1381my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001382my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001383
1384# Typedefs
1385my %Typedef_BaseName;
1386my %Typedef_Tr;
1387my %Typedef_Eq;
1388my %StdCxxTypedef;
1389my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001390my %MissedBase;
1391my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001392my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001393
1394# Symbols
1395my %SymbolInfo;
1396my %tr_name;
1397my %mangled_name_gcc;
1398my %mangled_name;
1399my %SkipSymbols = (
1400 "1"=>{},
1401 "2"=>{} );
1402my %SkipNameSpaces = (
1403 "1"=>{},
1404 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001405my %AddNameSpaces = (
1406 "1"=>{},
1407 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001408my %SymbolsList;
1409my %SymbolsList_App;
1410my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001411my %Symbol_Library = (
1412 "1"=>{},
1413 "2"=>{} );
1414my %Library_Symbol = (
1415 "1"=>{},
1416 "2"=>{} );
1417my %DepSymbol_Library = (
1418 "1"=>{},
1419 "2"=>{} );
1420my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001421 "1"=>{},
1422 "2"=>{} );
1423my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001424my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001425my %AddIntParams;
1426my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001427my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001428my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001429
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001430# Extra Info
1431my %UndefinedSymbols;
1432
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001433# Headers
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001434my %Include_Preamble = (
1435 "1"=>[],
1436 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001437my %Registered_Headers;
1438my %HeaderName_Paths;
1439my %Header_Dependency;
1440my %Include_Neighbors;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001441my %Include_Paths = (
1442 "1"=>[],
1443 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001444my %INC_PATH_AUTODETECT = (
1445 "1"=>1,
1446 "2"=>1 );
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001447my %Add_Include_Paths = (
1448 "1"=>[],
1449 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001450my %Skip_Include_Paths;
1451my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001452my %Header_ErrorRedirect;
1453my %Header_Includes;
1454my %Header_ShouldNotBeUsed;
1455my %RecursiveIncludes;
1456my %Header_Include_Prefix;
1457my %SkipHeaders;
1458my %SkipHeadersList=(
1459 "1"=>{},
1460 "2"=>{} );
1461my %SkipLibs;
1462my %Include_Order;
1463my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001464my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001465my %TUnit_Funcs;
1466my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001467
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001468my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001469 "1"=>0,
1470 "2"=>0 );
1471my %AutoPreambleMode = (
1472 "1"=>0,
1473 "2"=>0 );
1474my %MinGWMode = (
1475 "1"=>0,
1476 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001477my %Cpp0xMode = (
1478 "1"=>0,
1479 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001480
1481# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001482my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001483my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001484my %RegisteredSONAMEs;
1485my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001486
1487# System Objects
1488my %SystemObjects;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001489my @DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001490my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001491
1492# System Headers
1493my %SystemHeaders;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001494my @DefaultCppPaths;
1495my @DefaultGccPaths;
1496my @DefaultIncPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001497my %DefaultCppHeader;
1498my %DefaultGccHeader;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001499my @UsersIncPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001500
1501# Merging
1502my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001503my $Version;
1504my %AddedInt;
1505my %RemovedInt;
1506my %AddedInt_Virt;
1507my %RemovedInt_Virt;
1508my %VirtualReplacement;
1509my %ChangedTypedef;
1510my %CompatRules;
1511my %IncompleteRules;
1512my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001513my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001514my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001515my %ReturnedClass;
1516my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001517my %SourceAlternative;
1518my %SourceAlternative_B;
1519my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001520
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001521# Calling Conventions
1522my %UseConv_Real = (
1523 "1"=>0,
1524 "2"=>0 );
1525
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001526# OS Compliance
1527my %TargetLibs;
1528my %TargetHeaders;
1529
1530# OS Specifics
1531my $OStarget = $OSgroup;
1532my %TargetTools;
1533
1534# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001535my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001536
1537# Recursion locks
1538my @RecurLib;
1539my @RecurSymlink;
1540my @RecurTypes;
1541my @RecurInclude;
1542my @RecurConstant;
1543
1544# System
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001545my %SystemPaths = (
1546 "include"=>[],
1547 "lib"=>[],
1548 "bin"=>[]
1549);
1550my @DefaultBinPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001551my $GCC_PATH;
1552
1553# Symbols versioning
1554my %SymVer = (
1555 "1"=>{},
1556 "2"=>{} );
1557
1558# Problem descriptions
1559my %CompatProblems;
1560my %ProblemsWithConstants;
1561my %ImplProblems;
1562my %TotalAffected;
1563
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001564# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001565my $ContentID = 1;
1566my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1567my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1568my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1569my $ContentSpanEnd = "</span>\n";
1570my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1571my $ContentDivEnd = "</div>\n";
1572my $Content_Counter = 0;
1573
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001574# XML Dump
1575my $TAG_ID = 0;
1576my $INDENT = " ";
1577
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001578# Modes
1579my $JoinReport = 1;
1580my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001581
1582sub get_Modules()
1583{
1584 my $TOOL_DIR = get_dirname($0);
1585 if(not $TOOL_DIR)
1586 { # patch for MS Windows
1587 $TOOL_DIR = ".";
1588 }
1589 my @SEARCH_DIRS = (
1590 # tool's directory
1591 abs_path($TOOL_DIR),
1592 # relative path to modules
1593 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1594 # system directory
1595 "ACC_MODULES_INSTALL_PATH"
1596 );
1597 foreach my $DIR (@SEARCH_DIRS)
1598 {
1599 if(not is_abs($DIR))
1600 { # relative path
1601 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1602 }
1603 if(-d $DIR."/modules") {
1604 return $DIR."/modules";
1605 }
1606 }
1607 exitStatus("Module_Error", "can't find modules");
1608}
1609
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001610my %LoadedModules = ();
1611
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001612sub loadModule($)
1613{
1614 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001615 if(defined $LoadedModules{$Name}) {
1616 return;
1617 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001618 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1619 if(not -f $Path) {
1620 exitStatus("Module_Error", "can't access \'$Path\'");
1621 }
1622 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001623 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001624}
1625
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001626sub readModule($$)
1627{
1628 my ($Module, $Name) = @_;
1629 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
1630 if(not -f $Path) {
1631 exitStatus("Module_Error", "can't access \'$Path\'");
1632 }
1633 return readFile($Path);
1634}
1635
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001636sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001637{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001638 my $Number = $_[0];
1639 if(not $Number) {
1640 $Number = 1;
1641 }
1642 else {
1643 $Number = int($Number)+1;
1644 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001645 if($Number>3) {
1646 return $Number."th";
1647 }
1648 elsif($Number==1) {
1649 return "1st";
1650 }
1651 elsif($Number==2) {
1652 return "2nd";
1653 }
1654 elsif($Number==3) {
1655 return "3rd";
1656 }
1657 else {
1658 return $Number;
1659 }
1660}
1661
1662sub search_Tools($)
1663{
1664 my $Name = $_[0];
1665 return "" if(not $Name);
1666 if(my @Paths = keys(%TargetTools))
1667 {
1668 foreach my $Path (@Paths)
1669 {
1670 if(-f joinPath($Path, $Name)) {
1671 return joinPath($Path, $Name);
1672 }
1673 if($CrossPrefix)
1674 { # user-defined prefix (arm-none-symbianelf, ...)
1675 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1676 if(-f $Candidate) {
1677 return $Candidate;
1678 }
1679 }
1680 }
1681 }
1682 else {
1683 return "";
1684 }
1685}
1686
1687sub synch_Cmd($)
1688{
1689 my $Name = $_[0];
1690 if(not $GCC_PATH)
1691 { # GCC was not found yet
1692 return "";
1693 }
1694 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001695 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001696 return $Candidate;
1697 }
1698 return "";
1699}
1700
1701sub get_CmdPath($)
1702{
1703 my $Name = $_[0];
1704 return "" if(not $Name);
1705 if(defined $Cache{"get_CmdPath"}{$Name}) {
1706 return $Cache{"get_CmdPath"}{$Name};
1707 }
1708 my %BinUtils = map {$_=>1} (
1709 "c++filt",
1710 "objdump",
1711 "readelf"
1712 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001713 if($BinUtils{$Name} and $GCC_PATH)
1714 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001715 if(my $Dir = get_dirname($GCC_PATH)) {
1716 $TargetTools{$Dir}=1;
1717 }
1718 }
1719 my $Path = search_Tools($Name);
1720 if(not $Path and $OSgroup eq "windows") {
1721 $Path = search_Tools($Name.".exe");
1722 }
1723 if(not $Path and $BinUtils{$Name})
1724 {
1725 if($CrossPrefix)
1726 { # user-defined prefix
1727 $Path = search_Cmd($CrossPrefix."-".$Name);
1728 }
1729 }
1730 if(not $Path and $BinUtils{$Name})
1731 {
1732 if(my $Candidate = synch_Cmd($Name))
1733 { # synch with GCC
1734 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001735 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001736 if(-f $Candidate) {
1737 $Path = $Candidate;
1738 }
1739 }
1740 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001741 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001742 $Path = $Candidate;
1743 }
1744 }
1745 }
1746 if(not $Path) {
1747 $Path = search_Cmd($Name);
1748 }
1749 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001750 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001751 $Path=search_Cmd($Name.".exe");
1752 }
1753 if($Path=~/\s/) {
1754 $Path = "\"".$Path."\"";
1755 }
1756 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1757}
1758
1759sub search_Cmd($)
1760{
1761 my $Name = $_[0];
1762 return "" if(not $Name);
1763 if(defined $Cache{"search_Cmd"}{$Name}) {
1764 return $Cache{"search_Cmd"}{$Name};
1765 }
1766 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1767 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1768 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001769 foreach my $Path (@{$SystemPaths{"bin"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001770 {
1771 my $CmdPath = joinPath($Path,$Name);
1772 if(-f $CmdPath)
1773 {
1774 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001775 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001776 }
1777 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1778 }
1779 }
1780 return ($Cache{"search_Cmd"}{$Name} = "");
1781}
1782
1783sub get_CmdPath_Default($)
1784{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001785 return "" if(not $_[0]);
1786 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1787 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001788 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001789 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1790}
1791
1792sub get_CmdPath_Default_I($)
1793{ # search in PATH
1794 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001795 if($Name=~/find/)
1796 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001797 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001798 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001799 }
1800 }
1801 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001802 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001803 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001804 if(checkCmd($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001805 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001806 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001807 if($OSgroup eq "windows")
1808 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001809 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001810 return $Name;
1811 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001812 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001813 foreach my $Path (@DefaultBinPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001814 {
1815 if(-f $Path."/".$Name) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001816 return joinPath($Path, $Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001817 }
1818 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001819 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001820}
1821
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001822sub classifyPath($)
1823{
1824 my $Path = $_[0];
1825 if($Path=~/[\*\[]/)
1826 { # wildcard
1827 $Path=~s/\*/.*/g;
1828 $Path=~s/\\/\\\\/g;
1829 return ($Path, "Pattern");
1830 }
1831 elsif($Path=~/[\/\\]/)
1832 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001833 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001834 return (path_format($Path, $OSgroup), "Path");
1835 }
1836 else {
1837 return ($Path, "Name");
1838 }
1839}
1840
1841sub readDescriptor($$)
1842{
1843 my ($LibVersion, $Content) = @_;
1844 return if(not $LibVersion);
1845 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1846 if(not $Content) {
1847 exitStatus("Error", "$DName is empty");
1848 }
1849 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001850 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001851 }
1852 $Content=~s/\/\*(.|\n)+?\*\///g;
1853 $Content=~s/<\!--(.|\n)+?-->//g;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001854
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001855 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1856 if($TargetVersion{$LibVersion}) {
1857 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1858 }
1859 if(not $Descriptor{$LibVersion}{"Version"}) {
1860 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1861 }
1862 if($Content=~/{RELPATH}/)
1863 {
1864 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1865 $Content =~ s/{RELPATH}/$RelDir/g;
1866 }
1867 else
1868 {
1869 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1870 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1871 }
1872 }
1873
1874 if(not $CheckObjectsOnly_Opt)
1875 {
1876 my $DHeaders = parseTag(\$Content, "headers");
1877 if(not $DHeaders) {
1878 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1879 }
1880 elsif(lc($DHeaders) ne "none")
1881 { # append the descriptor headers list
1882 if($Descriptor{$LibVersion}{"Headers"})
1883 { # multiple descriptors
1884 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1885 }
1886 else {
1887 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1888 }
1889 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1890 {
1891 if(not -e $Path) {
1892 exitStatus("Access_Error", "can't access \'$Path\'");
1893 }
1894 }
1895 }
1896 }
1897 if(not $CheckHeadersOnly_Opt)
1898 {
1899 my $DObjects = parseTag(\$Content, "libs");
1900 if(not $DObjects) {
1901 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1902 }
1903 elsif(lc($DObjects) ne "none")
1904 { # append the descriptor libraries list
1905 if($Descriptor{$LibVersion}{"Libs"})
1906 { # multiple descriptors
1907 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1908 }
1909 else {
1910 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1911 }
1912 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1913 {
1914 if(not -e $Path) {
1915 exitStatus("Access_Error", "can't access \'$Path\'");
1916 }
1917 }
1918 }
1919 }
1920 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1921 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001922 if(not -d $Path) {
1923 exitStatus("Access_Error", "can't access directory \'$Path\'");
1924 }
1925 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001926 push_U($SystemPaths{"include"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001927 }
1928 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1929 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001930 if(not -d $Path) {
1931 exitStatus("Access_Error", "can't access directory \'$Path\'");
1932 }
1933 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001934 push_U($SystemPaths{"lib"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001935 }
1936 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1937 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001938 if(not -d $Path) {
1939 exitStatus("Access_Error", "can't access directory \'$Path\'");
1940 }
1941 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001942 push_U($SystemPaths{"bin"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001943 $TargetTools{$Path}=1;
1944 }
1945 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1946 $CrossPrefix = $Prefix;
1947 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001948 $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //=
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001949 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1950 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001951 if(not -d $Path) {
1952 exitStatus("Access_Error", "can't access directory \'$Path\'");
1953 }
1954 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001955 push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001956 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001957 $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001958 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1959 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 if(not -d $Path) {
1961 exitStatus("Access_Error", "can't access directory \'$Path\'");
1962 }
1963 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001964 push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001965 }
1966 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1967 {
1968 # skip some auto-generated include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001969 $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001970 }
1971 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1972 {
1973 # skip direct including of some headers
1974 my ($CPath, $Type) = classifyPath($Path);
1975 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001976 }
1977 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1978 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1979 $CompilerOptions{$LibVersion} .= " ".$Option;
1980 }
1981 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1982 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1983 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001984 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001985 my ($CPath, $Type) = classifyPath($Path);
1986 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001987 }
1988 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1989 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1990 {
1991 my ($CPath, $Type) = classifyPath($Path);
1992 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1993 }
1994 if(my $DDefines = parseTag(\$Content, "defines"))
1995 {
1996 if($Descriptor{$LibVersion}{"Defines"})
1997 { # multiple descriptors
1998 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1999 }
2000 else {
2001 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
2002 }
2003 }
2004 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
2005 {
2006 if($Order=~/\A(.+):(.+)\Z/) {
2007 $Include_Order{$LibVersion}{$1} = $2;
2008 }
2009 }
2010 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
2011 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002012 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002013 $SkipTypes{$LibVersion}{$Type_Name} = 1;
2014 }
2015 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
2016 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002017 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002018 $SkipSymbols{$LibVersion}{$Symbol} = 1;
2019 }
2020 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
2021 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
2022 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04002023 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
2024 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2025 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002026 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2027 $SkipConstants{$LibVersion}{$Constant} = 1;
2028 }
2029 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2030 {
2031 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002032 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002033 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2034 }
2035 else {
2036 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2037 }
2038 }
2039}
2040
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002041sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002042{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002043 my $CodeRef = shift(@_);
2044 my $Tag = shift(@_);
2045 if(not $Tag or not $CodeRef) {
2046 return undef;
2047 }
2048 my $Sp = 0;
2049 if(@_) {
2050 $Sp = shift(@_);
2051 }
2052 my $Start = index(${$CodeRef}, "<$Tag>");
2053 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002054 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002055 my $End = index(${$CodeRef}, "</$Tag>");
2056 if($End!=-1)
2057 {
2058 my $TS = length($Tag)+3;
2059 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2060 substr($Content, 0, $TS-1, ""); # cut start tag
2061 substr($Content, -$TS, $TS, ""); # cut end tag
2062 if(not $Sp)
2063 {
2064 $Content=~s/\A\s+//g;
2065 $Content=~s/\s+\Z//g;
2066 }
2067 if(substr($Content, 0, 1) ne "<") {
2068 $Content = xmlSpecChars_R($Content);
2069 }
2070 return $Content;
2071 }
2072 }
2073 return undef;
2074}
2075
2076sub parseTag_E($$$)
2077{
2078 my ($CodeRef, $Tag, $Info) = @_;
2079 if(not $Tag or not $CodeRef
2080 or not $Info) {
2081 return undef;
2082 }
2083 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2084 {
2085 my ($Ext, $Content) = ($2, $3);
2086 $Content=~s/\A\s+//g;
2087 $Content=~s/\s+\Z//g;
2088 if($Ext)
2089 {
2090 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2091 {
2092 my ($K, $V) = ($1, $2);
2093 $Info->{$K} = xmlSpecChars_R($V);
2094 }
2095 }
2096 if(substr($Content, 0, 1) ne "<") {
2097 $Content = xmlSpecChars_R($Content);
2098 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002099 return $Content;
2100 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002101 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002102}
2103
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002104sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002105{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002106 my $Tag = shift(@_);
2107 my $Val = shift(@_);
2108 my @Ext = @_;
2109 my $Content = openTag($Tag, @Ext);
2110 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002111 $Content .= xmlSpecChars($Val);
2112 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002113 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002114
2115 return $Content;
2116}
2117
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002118sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002119{
2120 my $Tag = shift(@_);
2121 my @Ext = @_;
2122 my $Content = "";
2123 foreach (1 .. $TAG_ID) {
2124 $Content .= $INDENT;
2125 }
2126 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002127 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002128 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002129 $Content .= "<".$Tag;
2130 my $P = 0;
2131 while($P<=$#Ext-1)
2132 {
2133 $Content .= " ".$Ext[$P];
2134 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2135 $P+=2;
2136 }
2137 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002138 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002139 else {
2140 $Content .= "<".$Tag.">\n";
2141 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002142 return $Content;
2143}
2144
2145sub closeTag($)
2146{
2147 my $Tag = $_[0];
2148 my $Content = "";
2149 $TAG_ID-=1;
2150 foreach (1 .. $TAG_ID) {
2151 $Content .= $INDENT;
2152 }
2153 $Content .= "</".$Tag.">\n";
2154 return $Content;
2155}
2156
2157sub checkTags()
2158{
2159 if($TAG_ID!=0) {
2160 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2161 }
2162}
2163
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002164sub getInfo($)
2165{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002166 my $DumpPath = $_[0];
2167 return if(not $DumpPath or not -f $DumpPath);
2168
2169 readTUDump($DumpPath);
2170
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002171 # processing info
2172 setTemplateParams_All();
2173 getTypeInfo_All();
2174 simplifyNames();
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002175 simplifyConstants();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002176 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002177 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002178
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002179
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002180 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002181 %LibInfo = ();
2182 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002183 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002184 %TemplateDecl = ();
2185 %StdCxxTypedef = ();
2186 %MissedTypedef = ();
2187 %Typedef_Tr = ();
2188 %Typedef_Eq = ();
2189
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002190 # clean cache
2191 delete($Cache{"getTypeAttr"});
2192 delete($Cache{"getTypeDeclId"});
2193
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04002194 if(not $ExtraInfo)
2195 {
2196 # remove unused types
2197 if($BinaryOnly and not $ExtendedCheck)
2198 { # --binary
2199 removeUnused($Version, "All");
2200 }
2201 else {
2202 removeUnused($Version, "Derived");
2203 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002204 }
2205
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002206 if($Debug) {
2207 # debugMangling($Version);
2208 }
2209}
2210
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002211sub readTUDump($)
2212{
2213 my $DumpPath = $_[0];
2214
2215 open(TU_DUMP, $DumpPath);
2216 local $/ = undef;
2217 my $Content = <TU_DUMP>;
2218 close(TU_DUMP);
2219
2220 unlink($DumpPath);
2221
2222 $Content=~s/\n[ ]+/ /g;
2223 my @Lines = split("\n", $Content);
2224
2225 # clean memory
2226 undef $Content;
2227
2228 $MAX_ID = $#Lines+1;
2229
2230 foreach (0 .. $#Lines)
2231 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002232 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002233 { # get a number and attributes of a node
2234 next if(not $NodeType{$2});
2235 $LibInfo{$Version}{"info_type"}{$1}=$2;
2236 $LibInfo{$Version}{"info"}{$1}=$3;
2237 }
2238
2239 # clean memory
2240 delete($Lines[$_]);
2241 }
2242
2243 # clean memory
2244 undef @Lines;
2245}
2246
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002247sub simplifyConstants()
2248{
2249 foreach my $Constant (keys(%{$Constants{$Version}}))
2250 {
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04002251 my $Value = $Constants{$Version}{$Constant}{"Value"};
2252 if(defined $EnumConstants{$Version}{$Value}) {
2253 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Constant}{"Value"};
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002254 }
2255 }
2256}
2257
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002258sub simplifyNames()
2259{
2260 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2261 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002262 if($Typedef_Eq{$Version}{$Base}) {
2263 next;
2264 }
2265 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2266 if($#Translations==0)
2267 {
2268 if(length($Translations[0])<=length($Base)) {
2269 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2270 }
2271 }
2272 else
2273 { # select most appropriate
2274 foreach my $Tr (@Translations)
2275 {
2276 if($Base=~/\A\Q$Tr\E/)
2277 {
2278 $Typedef_Eq{$Version}{$Base} = $Tr;
2279 last;
2280 }
2281 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002282 }
2283 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002284 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002285 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002286 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002287 if(not $TypeName) {
2288 next;
2289 }
2290 next if(index($TypeName,"<")==-1);# template instances only
2291 if($TypeName=~/>(::\w+)+\Z/)
2292 { # skip unused types
2293 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002294 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002295 foreach my $Base (sort {length($b)<=>length($a)}
2296 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002298 next if(not $Base);
2299 next if(index($TypeName,$Base)==-1);
2300 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002301 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002302 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002303 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2304 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2305 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002306 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002307 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2308 {
2309 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2310 {
2311 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2312 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002313 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002314 }
2315 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002316 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002317 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002318 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002319 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002320 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2321 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002322 }
2323}
2324
2325sub setTemplateParams_All()
2326{
2327 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2328 {
2329 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2330 setTemplateParams($_);
2331 }
2332 }
2333}
2334
2335sub setTemplateParams($)
2336{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002337 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002338 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002339 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002340 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002341 my $TmplInst_Id = $2;
2342 setTemplateInstParams($TmplInst_Id);
2343 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2344 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002346 }
2347 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002348 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002349 {
2350 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2351 {
2352 if($IType eq "record_type") {
2353 $TemplateDecl{$Version}{$TypeId}=1;
2354 }
2355 }
2356 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002357}
2358
2359sub setTemplateInstParams($)
2360{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002361 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002362 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002363 my ($Params_InfoId, $ElemId) = ();
2364 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2365 $Params_InfoId = $1;
2366 }
2367 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2368 $ElemId = $1;
2369 }
2370 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002371 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002372 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2373 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2374 {
2375 my ($PPos, $PTypeId) = ($1, $2);
2376 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2377 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002378 if($PType eq "template_type_parm")
2379 {
2380 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002381 return;
2382 }
2383 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002384 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2385 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002386 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002387 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002388 else
2389 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002390 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002391 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002392 }
2393 }
2394 }
2395}
2396
2397sub getTypeDeclId($)
2398{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002399 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002400 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002401 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2402 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2403 }
2404 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2405 {
2406 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2407 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2408 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002409 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002410 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002411 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002412}
2413
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414sub getTypeInfo_All()
2415{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002416 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002417 { # support for GCC < 4.5
2418 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2419 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2420 # FIXME: check GCC versions
2421 addMissedTypes_Pre();
2422 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002423
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002424 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002425 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002426 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2427 if($IType=~/_type\Z/ and $IType ne "function_type"
2428 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002429 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002430 }
2431 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002432
2433 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002434 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 "Name" => "...",
2436 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002437 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002438 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002439 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002440
2441 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002442 { # support for GCC < 4.5
2443 addMissedTypes_Post();
2444 }
2445}
2446
2447sub addMissedTypes_Pre()
2448{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002449 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002450 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2451 { # detecting missed typedefs
2452 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2453 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002454 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002455 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002456 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 if($TypeType eq "Unknown")
2458 { # template_type_parm
2459 next;
2460 }
2461 my $TypeDeclId = getTypeDeclId($TypeId);
2462 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2463 my $TypedefName = getNameByInfo($MissedTDid);
2464 next if(not $TypedefName);
2465 next if($TypedefName eq "__float80");
2466 next if(isAnon($TypedefName));
2467 if(not $TypeDeclId
2468 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002469 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 }
2471 }
2472 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002473 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002474 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002475 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002476 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002478 next;
2479 }
2480 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002482 if(not $TypedefName) {
2483 next;
2484 }
2485 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002486 my %MissedInfo = ( # typedef info
2487 "Name" => $TypedefName,
2488 "NameSpace" => $TypedefNS,
2489 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002490 "Tid" => $Tid
2491 },
2492 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002493 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002494 my ($H, $L) = getLocation($MissedTDid);
2495 $MissedInfo{"Header"} = $H;
2496 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002497 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002498 { # other types
2499 next;
2500 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002501 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002502 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002503 next;
2504 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002505 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002506 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002507 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002508 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002509 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002510 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002511 next;
2512 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002513 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002514 next;
2515 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002516 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002518 next;
2519 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002520 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002521 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002522 next;
2523 }
2524 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002525
2526 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2527
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002528 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002529 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002530 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002531 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002532 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002533
2534 # add missed & remove other
2535 $TypeInfo{$Version} = \%AddTypes;
2536 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002537}
2538
2539sub addMissedTypes_Post()
2540{
2541 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2542 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002543 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2544 {
2545 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2546 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2547 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2548 }
2549 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002550 }
2551}
2552
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002553sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002554{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002555 my $TypeId = $_[0];
2556 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2557 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002558 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002559 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002561}
2562
2563sub getArraySize($$)
2564{
2565 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002566 if(my $Size = getSize($TypeId))
2567 {
2568 my $Elems = $Size/$BYTE_SIZE;
2569 while($BaseName=~s/\s*\[(\d+)\]//) {
2570 $Elems/=$1;
2571 }
2572 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2573 {
2574 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2575 $Elems/=$BasicSize;
2576 }
2577 }
2578 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002579 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002580 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002581}
2582
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002583sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002586 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002587 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2588 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002589 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002590 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2591 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2592 if(not $NodeType)
2593 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002594 return ();
2595 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002596 if($NodeType eq "tree_vec")
2597 {
2598 if($Pos!=$#Positions)
2599 { # select last vector of parameters ( ns<P1>::type<P2> )
2600 next;
2601 }
2602 }
2603 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2604 foreach my $P (@Params)
2605 {
2606 if($P eq "") {
2607 return ();
2608 }
2609 elsif($P ne "\@skip\@") {
2610 @TmplParams = (@TmplParams, $P);
2611 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002612 }
2613 }
2614 return @TmplParams;
2615}
2616
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002617sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002618{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002619 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002620 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002621 if(defined $TypeInfo{$Version}{$TypeId}
2622 and $TypeInfo{$Version}{$TypeId}{"Name"})
2623 { # already created
2624 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002625 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002626 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2627 { # incomplete type
2628 return ();
2629 }
2630 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2631
2632 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002633 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002634
2635 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2636 {
2637 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2638 {
2639 if($Info=~/qual[ ]*:/)
2640 {
2641 if(my $NID = ++$MAX_ID)
2642 {
2643 $MissedBase{$Version}{$TypeId}="$NID";
2644 $MissedBase_R{$Version}{$NID}=$TypeId;
2645 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2646 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2647 }
2648 }
2649 }
2650 $TypeAttr{"Type"} = "Typedef";
2651 }
2652 else {
2653 $TypeAttr{"Type"} = getTypeType($TypeId);
2654 }
2655
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002656 if($TypeAttr{"Type"} eq "Unknown") {
2657 return ();
2658 }
2659 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2660 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002661 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002662 if(my $TName = $TypeAttr{"Name"})
2663 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002664 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002665 $TName_Tid{$Version}{$TName} = $TypeId;
2666 return %TypeAttr;
2667 }
2668 else {
2669 return ();
2670 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002671 }
2672 elsif($TypeAttr{"Type"} eq "Array")
2673 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002674 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2675 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002676 return ();
2677 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002678 if(my $Algn = getAlgn($TypeId)) {
2679 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2680 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002682 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002683 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002684 if(not $BTAttr{"Name"}) {
2685 return ();
2686 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002687 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002688 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002689 if(my $Size = getSize($TypeId)) {
2690 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2691 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002692 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002693 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2694 }
2695 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002696 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002697 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002698 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002699 else
2700 {
2701 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002702 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002703 $TypeAttr{"Name"} = $1."[]".$2;
2704 }
2705 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002706 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002708 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002709 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002710 if($BTAttr{"Header"}) {
2711 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002712 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002713 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002714 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2715 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002717 return ();
2718 }
2719 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2720 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002721 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002722 if($TypeAttr{"Name"})
2723 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002724 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2725 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002726 { # NOTE: register only one int: with built-in decl
2727 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2728 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2729 }
2730 }
2731 return %TypeAttr;
2732 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002733 else {
2734 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002736 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002737 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002738 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002739 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2740 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002741 return ();
2742 }
2743 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002744 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002745 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002746 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002747 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002748 if($MissedTDid ne $TypeDeclId) {
2749 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2750 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002751 }
2752 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002753 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002754 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002755 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002756 return ();
2757 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002758 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002759 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002760 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2761 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002762 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002763 }
2764 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002765 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002766 {
2767 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002768 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002769 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002770 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002771 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2772 }
2773 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002774 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002775 }
2776 }
2777 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002778 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002779 }
2780 if($TypeAttr{"Type"} eq "Typedef")
2781 {
2782 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002783 if(isAnon($TypeAttr{"Name"}))
2784 { # anon typedef to anon type: ._N
2785 return ();
2786 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002787 if(my $NS = getNameSpace($TypeDeclId))
2788 {
2789 my $TypeName = $TypeAttr{"Name"};
2790 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2791 { # "some_type" is the typedef to "struct some_type" in C++
2792 if($3) {
2793 $TypeAttr{"Name"} = $3."::".$TypeName;
2794 }
2795 }
2796 else
2797 {
2798 $TypeAttr{"NameSpace"} = $NS;
2799 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002800
2801 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2802 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2803 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002804 if($BTAttr{"NameSpace"}
2805 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002806 { # types like "std::fpos<__mbstate_t>" are
2807 # not covered by typedefs in the TU dump
2808 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002809 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2810 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002811 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002812 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002813 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002814 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002816 }
2817 }
2818 }
2819 }
2820 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002821 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2822 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002823 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002824 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2825 { # typedef int*const TYPEDEF; // first
2826 # int foo(TYPEDEF p); // const is optimized out
2827 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2828 if($BTAttr{"Name"}=~/</)
2829 {
2830 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2831 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2832 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002833 }
2834 }
2835 }
2836 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2837 }
2838 if(not $TypeAttr{"Size"})
2839 {
2840 if($TypeAttr{"Type"} eq "Pointer") {
2841 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2842 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002843 elsif($BTAttr{"Size"}) {
2844 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002845 }
2846 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002847 if(my $Algn = getAlgn($TypeId)) {
2848 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2849 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002850 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002851 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2852 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002853 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002854 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002855 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002856 { # typedef to "class Class"
2857 # should not be registered in TName_Tid
2858 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2859 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2860 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002861 }
2862 return %TypeAttr;
2863 }
2864}
2865
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002866sub getTreeVec($)
2867{
2868 my %Vector = ();
2869 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2870 {
2871 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2872 { # string length is N-1 because of the null terminator
2873 $Vector{$1} = $2;
2874 }
2875 }
2876 return \%Vector;
2877}
2878
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002879sub get_TemplateParam($$)
2880{
2881 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002882 return () if(not $Type_Id);
2883 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2884 return () if(not $NodeType);
2885 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002886 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002887 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002888 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002889 my $Num = getNodeIntCst($Type_Id);
2890 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002891 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002892 }
2893 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 }
2896 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002897 elsif($NodeType eq "string_cst") {
2898 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002899 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002900 elsif($NodeType eq "tree_vec")
2901 {
2902 my $Vector = getTreeVec($Type_Id);
2903 my @Params = ();
2904 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2905 {
2906 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2907 push(@Params, $P2);
2908 }
2909 }
2910 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002911 }
2912 else
2913 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002914 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002915 my $PName = $ParamAttr{"Name"};
2916 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002917 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002918 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002919 if($PName=~/\>/)
2920 {
2921 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002922 $PName = $Cover;
2923 }
2924 }
2925 if($Pos>=1 and
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04002926 $PName=~/\A$DEFAULT_STD_PARMS\</)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002927 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2928 # template<typename _Key, typename _Compare = std::less<_Key>
2929 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2930 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2931 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2932 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002933 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002934 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002935 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002936 }
2937}
2938
2939sub cover_stdcxx_typedef($)
2940{
2941 my $TypeName = $_[0];
2942 if(my @Covers = sort {length($a)<=>length($b)}
2943 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2944 { # take the shortest typedef
2945 # FIXME: there may be more than
2946 # one typedefs to the same type
2947 return $Covers[0];
2948 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002949 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002950 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2951 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2952 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002953 if(my $Cover = $Covers[0])
2954 {
2955 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2956 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2957 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002958 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002959 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002960}
2961
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002962sub getNodeIntCst($)
2963{
2964 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002965 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002966 if($EnumMembName_Id{$Version}{$CstId}) {
2967 return $EnumMembName_Id{$Version}{$CstId};
2968 }
2969 elsif((my $Value = getTreeValue($CstId)) ne "")
2970 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 if($Value eq "0")
2972 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002973 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002974 return "false";
2975 }
2976 else {
2977 return "0";
2978 }
2979 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002980 elsif($Value eq "1")
2981 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002982 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002983 return "true";
2984 }
2985 else {
2986 return "1";
2987 }
2988 }
2989 else {
2990 return $Value;
2991 }
2992 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002993 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002994}
2995
2996sub getNodeStrCst($)
2997{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002998 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2999 {
3000 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003001 {
3002 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
3003 { # string length is N-1 because of the null terminator
3004 return substr($1, 0, $2-1);
3005 }
3006 else
3007 { # identifier_node
3008 return substr($1, 0, $2);
3009 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003010 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003011 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003012 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003013}
3014
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003015sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003016{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003017 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003018 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
3019 if($Type eq "FieldPtr") {
3020 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
3021 }
3022 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
3023 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003024 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003025 if($Type eq "MethodPtr")
3026 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003027 if(my $Size = getSize($TypeId))
3028 {
3029 $Size/=$BYTE_SIZE;
3030 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003031 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003032 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003033 if(my $Algn = getAlgn($TypeId)) {
3034 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3035 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003036 # Return
3037 if($Type eq "FieldPtr")
3038 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003039 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003040 if($ReturnAttr{"Name"}) {
3041 $MemPtrName .= $ReturnAttr{"Name"};
3042 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003043 $TypeAttr{"Return"} = $PtrId;
3044 }
3045 else
3046 {
3047 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3048 {
3049 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003050 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3051 if(not $ReturnAttr{"Name"})
3052 { # templates
3053 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003055 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003056 $TypeAttr{"Return"} = $ReturnTypeId;
3057 }
3058 }
3059 # Class
3060 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3061 {
3062 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003063 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003064 if($Class{"Name"}) {
3065 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3066 }
3067 else {
3068 $MemPtrName .= " (*)";
3069 }
3070 }
3071 else {
3072 $MemPtrName .= " (*)";
3073 }
3074 # Parameters
3075 if($Type eq "FuncPtr"
3076 or $Type eq "MethodPtr")
3077 {
3078 my @ParamTypeName = ();
3079 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3080 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003081 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003082 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003083 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003084 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003085 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3086 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003087 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003088 my $PTypeId = $1;
3089 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003090 if(not $ParamAttr{"Name"})
3091 { # templates (template_type_parm), etc.
3092 return ();
3093 }
3094 if($ParamAttr{"Name"} eq "void") {
3095 last;
3096 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003097 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003098 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003099 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003100 push(@ParamTypeName, $ParamAttr{"Name"});
3101 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003102 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3103 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003104 }
3105 else {
3106 last;
3107 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003108 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003109 else {
3110 last;
3111 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003112 }
3113 }
3114 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3115 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003116 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 return %TypeAttr;
3118}
3119
3120sub getTreeTypeName($)
3121{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003122 my $TypeId = $_[0];
3123 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003124 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003125 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003126 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003127 if(my $Name = getNameByInfo($TypeId))
3128 { # bit_size_type
3129 return $Name;
3130 }
3131 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003132 return "unsigned int";
3133 }
3134 else {
3135 return "int";
3136 }
3137 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3139 {
3140 return getNameByInfo($1);
3141 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003142 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003143 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003144}
3145
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003146sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003147{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003148 my $Ptd = pointTo($_[0]);
3149 return 0 if(not $Ptd);
3150 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003151 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003152 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3153 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003154 }
3155 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003156 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3157 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003158 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003159 if($InfoT1 eq "pointer_type"
3160 and $InfoT2 eq "function_type") {
3161 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003162 }
3163 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003164 return 0;
3165}
3166
3167sub isMethodPtr($)
3168{
3169 my $Ptd = pointTo($_[0]);
3170 return 0 if(not $Ptd);
3171 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3172 {
3173 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3174 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3175 and $Info=~/ ptrmem /) {
3176 return 1;
3177 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003178 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003179 return 0;
3180}
3181
3182sub isFieldPtr($)
3183{
3184 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3185 {
3186 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3187 and $Info=~/ ptrmem /) {
3188 return 1;
3189 }
3190 }
3191 return 0;
3192}
3193
3194sub pointTo($)
3195{
3196 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3197 {
3198 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3199 return $1;
3200 }
3201 }
3202 return "";
3203}
3204
3205sub getTypeTypeByTypeId($)
3206{
3207 my $TypeId = $_[0];
3208 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3209 {
3210 my $NType = $NodeType{$TType};
3211 if($NType eq "Intrinsic") {
3212 return $NType;
3213 }
3214 elsif(isFuncPtr($TypeId)) {
3215 return "FuncPtr";
3216 }
3217 elsif(isMethodPtr($TypeId)) {
3218 return "MethodPtr";
3219 }
3220 elsif(isFieldPtr($TypeId)) {
3221 return "FieldPtr";
3222 }
3223 elsif($NType ne "Other") {
3224 return $NType;
3225 }
3226 }
3227 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003228}
3229
3230sub getQual($)
3231{
3232 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003233 my %UnQual = (
3234 "r"=>"restrict",
3235 "v"=>"volatile",
3236 "c"=>"const",
3237 "cv"=>"const volatile"
3238 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003239 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3240 {
3241 my ($Qual, $To) = ();
3242 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3243 $Qual = $UnQual{$1};
3244 }
3245 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3246 $To = $1;
3247 }
3248 if($Qual and $To) {
3249 return ($Qual, $To);
3250 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003251 }
3252 return ();
3253}
3254
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003255sub getQualType($)
3256{
3257 if($_[0] eq "const volatile") {
3258 return "ConstVolatile";
3259 }
3260 return ucfirst($_[0]);
3261}
3262
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003263sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003264{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003265 my $TypeId = $_[0];
3266 my $TypeDeclId = getTypeDeclId($TypeId);
3267 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003268 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003269 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3270 return "Typedef";
3271 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003272 }
3273 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3274 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003275 if(($Qual or $To) and $TypeDeclId
3276 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003277 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003278 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003279 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003280 elsif(not $MissedBase_R{$Version}{$TypeId}
3281 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003282 return "Typedef";
3283 }
3284 elsif($Qual)
3285 { # qualified types
3286 return getQualType($Qual);
3287 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003288
3289 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3290 { # typedef struct { ... } name
3291 $TypeTypedef{$Version}{$TypeId} = $1;
3292 }
3293
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003294 my $TypeType = getTypeTypeByTypeId($TypeId);
3295 if($TypeType eq "Struct")
3296 {
3297 if($TypeDeclId
3298 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3299 return "Template";
3300 }
3301 }
3302 return $TypeType;
3303}
3304
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003305sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003306{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003307 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3308 {
3309 my $TDid = getTypeDeclId($_[0]);
3310 if(getNameByInfo($TDid)
3311 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3312 and getTypeId($TDid) eq $_[0]) {
3313 return $1;
3314 }
3315 }
3316 return 0;
3317}
3318
3319sub selectBaseType($)
3320{
3321 my $TypeId = $_[0];
3322 if(defined $MissedTypedef{$Version}{$TypeId})
3323 { # add missed typedefs
3324 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3325 return ($TypeId, "");
3326 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003327 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003328 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3329 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003330
3331 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3332 my $MB = $MissedBase{$Version}{$TypeId};
3333
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003334 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003335 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 and (getTypeId($1) ne $TypeId)
3337 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003338 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003339 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003340 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003341 elsif($MB)
3342 { # add base
3343 return ($MB, "");
3344 }
3345 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003346 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003347 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003348 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003349 elsif($Qual or $To)
3350 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003351 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003352 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003353 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003354 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003355 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003356 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003357 }
3358 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003359 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003360 }
3361 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003362 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003363 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003364 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003365 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366 }
3367 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003368 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003369 }
3370 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003371 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003372 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003373 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003374 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003375 }
3376 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003377 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003378 }
3379 }
3380 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003381 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003382 }
3383}
3384
3385sub getSymbolInfo_All()
3386{
3387 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3388 { # reverse order
3389 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003390 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003391 }
3392 }
3393}
3394
3395sub getVarInfo_All()
3396{
3397 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3398 { # reverse order
3399 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003400 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003401 }
3402 }
3403}
3404
3405sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003406 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003407}
3408
3409sub getVarInfo($)
3410{
3411 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003412 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003413 {
3414 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3415 if($NSInfoType and $NSInfoType eq "function_decl") {
3416 return;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 }
3419 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3420 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3421 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3422 delete($SymbolInfo{$Version}{$InfoId});
3423 return;
3424 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003425 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003426 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003427 delete($SymbolInfo{$Version}{$InfoId});
3428 return;
3429 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003430 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3431 delete($SymbolInfo{$Version}{$InfoId});
3432 return;
3433 }
3434 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003435 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3436 {
3437 if($OSgroup eq "windows")
3438 { # cut the offset
3439 $MnglName=~s/\@\d+\Z//g;
3440 }
3441 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3442 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003444 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 { # validate mangled name
3446 delete($SymbolInfo{$Version}{$InfoId});
3447 return;
3448 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003449 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003450 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003451 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003452 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003453 }
3454 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3455 { # non-public global data
3456 delete($SymbolInfo{$Version}{$InfoId});
3457 return;
3458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003459 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003460 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003461 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003462 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003463 { # typename_type
3464 delete($SymbolInfo{$Version}{$InfoId});
3465 return;
3466 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003467 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3468 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003469 if(defined $Val) {
3470 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3471 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003472 }
3473 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003474 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3475 {
3476 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3477 { # templates
3478 delete($SymbolInfo{$Version}{$InfoId});
3479 return;
3480 }
3481 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003482 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3483 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003484 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003485 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003486 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003487 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003488 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003489 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003490 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003491 if(not $CheckHeadersOnly)
3492 {
3493 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3494 {
3495 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3496 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3497 {
3498 if(link_symbol($ShortName, $Version, "-Deps"))
3499 { # "const" global data is mangled as _ZL... in the TU dump
3500 # but not mangled when compiling a C shared library
3501 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3502 }
3503 }
3504 }
3505 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003506 if($COMMON_LANGUAGE{$Version} eq "C++")
3507 {
3508 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3509 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003510 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003511 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3512 }
3513 }
3514 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3515 { # try to mangle symbol (link with libraries)
3516 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3517 }
3518 if($OStarget eq "windows")
3519 {
3520 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3521 { # link MS C++ symbols from library with GCC symbols from headers
3522 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3523 }
3524 }
3525 }
3526 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3527 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3528 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003529 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3530 {
3531 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3532 { # non-target symbols
3533 delete($SymbolInfo{$Version}{$InfoId});
3534 return;
3535 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003536 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003537 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3538 {
3539 if(defined $MissedTypedef{$Version}{$Rid})
3540 {
3541 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3542 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3543 }
3544 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003545 }
3546 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003547 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003548 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3549 }
3550 if($ShortName=~/\A(_Z|\?)/) {
3551 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3552 }
3553}
3554
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003555sub isConstType($$)
3556{
3557 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003558 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003559 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003560 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003561 }
3562 return ($Base{"Type"} eq "Const");
3563}
3564
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003565sub getTrivialName($$)
3566{
3567 my ($TypeInfoId, $TypeId) = @_;
3568 my %TypeAttr = ();
3569 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3570 if(not $TypeAttr{"Name"}) {
3571 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3572 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003573 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003574 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003575 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003576 if(isAnon($TypeAttr{"Name"}))
3577 {
3578 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003579 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003580 { # searching for a first not anon scope
3581 if($NSId eq $NameSpaceId) {
3582 last;
3583 }
3584 else
3585 {
3586 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3587 if(not $TypeAttr{"NameSpace"}
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003588 or not isAnon($TypeAttr{"NameSpace"})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003589 last;
3590 }
3591 }
3592 $NameSpaceId=$NSId;
3593 }
3594 }
3595 else
3596 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003597 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003598 {
3599 if($NameSpaceId ne $TypeId) {
3600 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003602 }
3603 }
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003604 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3606 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003607 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003608 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003609 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003610 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003611 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003612 if($TypeAttr{"NameSpace"}) {
3613 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3614 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003615 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003616 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3617 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003618 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003619 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003620 if(not @TParams)
3621 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003622 return ("", "");
3623 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003624 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003625 }
3626 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3627}
3628
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003629sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003630{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003631 my $TypeId = $_[0];
3632 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003633
3634 if($TemplateDecl{$Version}{$TypeId})
3635 { # template_decl
3636 return ();
3637 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003638 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3639 {
3640 if($TemplateDecl{$Version}{$ScopeId})
3641 { # template_decl
3642 return ();
3643 }
3644 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003645
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003646 my %TypeAttr = ();
3647 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3648 return ();
3649 }
3650 setTypeAccess($TypeId, \%TypeAttr);
3651 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3652 if(isBuiltIn($TypeAttr{"Header"}))
3653 {
3654 delete($TypeAttr{"Header"});
3655 delete($TypeAttr{"Line"});
3656 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003657 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003658 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3659 if(not $TypeAttr{"Name"}) {
3660 return ();
3661 }
3662 if(not $TypeAttr{"NameSpace"}) {
3663 delete($TypeAttr{"NameSpace"});
3664 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003665 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003666 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003667 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003668 {
3669 foreach my $Pos (0 .. $#TParams) {
3670 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3671 }
3672 }
3673 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003674 if(my $Size = getSize($TypeId))
3675 {
3676 $Size = $Size/$BYTE_SIZE;
3677 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003678 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003679 else
3680 { # declaration only
3681 $TypeAttr{"Forward"} = 1;
3682 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003683 if($TypeAttr{"Type"} eq "Struct"
3684 and detect_lang($TypeId))
3685 {
3686 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003687 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003688 }
3689 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003690 or $TypeAttr{"Type"} eq "Class")
3691 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003692 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003693 if($Skip) {
3694 return ();
3695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003696 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003697 if(my $Algn = getAlgn($TypeId)) {
3698 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003700 setSpec($TypeId, \%TypeAttr);
3701 setTypeMemb($TypeId, \%TypeAttr);
3702 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003703 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3704 {
3705 my @Entries = split(/\n/, $VTable);
3706 foreach (1 .. $#Entries)
3707 {
3708 my $Entry = $Entries[$_];
3709 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3710 $TypeAttr{"VTable"}{$1} = $2;
3711 }
3712 }
3713 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04003714
3715 if($TypeAttr{"Type"} eq "Enum")
3716 {
3717 if(not $TypeAttr{"NameSpace"})
3718 {
3719 foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
3720 {
3721 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
3722 $EnumConstants{$Version}{$MName} = {
3723 "Value"=>$TypeAttr{"Memb"}{$Pos}{"value"},
3724 "Header"=>$TypeAttr{"Header"}
3725 };
3726 }
3727 }
3728 }
3729
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003730 return %TypeAttr;
3731}
3732
3733sub detect_lang($)
3734{
3735 my $TypeId = $_[0];
3736 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003737 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003738 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003739 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3740 }
3741 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003742 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003743 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003744 while($Fncs)
3745 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003746 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003747 return 1;
3748 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003749 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003750 }
3751 }
3752 return 0;
3753}
3754
3755sub setSpec($$)
3756{
3757 my ($TypeId, $TypeAttr) = @_;
3758 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3759 if($Info=~/\s+spec\s+/) {
3760 $TypeAttr->{"Spec"} = 1;
3761 }
3762}
3763
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003764sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003765{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003766 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003767 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3768 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3769 {
3770 $Info = $LibInfo{$Version}{"info"}{$1};
3771 my $Pos = 0;
3772 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3773 {
3774 my ($Access, $BInfoId) = ($1, $2);
3775 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003776 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3777 if(not $CType or $CType eq "template_type_parm"
3778 or $CType eq "typename_type")
3779 { # skip
3780 return 1;
3781 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003782 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3783 if($Access=~/prot/)
3784 {
3785 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3786 }
3787 elsif($Access=~/priv/)
3788 {
3789 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3790 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003791 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003792 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003793 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003794 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3795 }
3796 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003797 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003798 }
3799 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003800 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003801}
3802
3803sub getBinfClassId($)
3804{
3805 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3806 $Info=~/type[ ]*:[ ]*@(\d+) /;
3807 return $1;
3808}
3809
3810sub unmangledFormat($$)
3811{
3812 my ($Name, $LibVersion) = @_;
3813 $Name = uncover_typedefs($Name, $LibVersion);
3814 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3815 $Name=~s/\(\w+\)(\d)/$1/;
3816 return $Name;
3817}
3818
3819sub modelUnmangled($$)
3820{
3821 my ($InfoId, $Compiler) = @_;
3822 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3823 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3824 }
3825 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3826 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3827 $PureSignature = "~".$PureSignature;
3828 }
3829 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3830 {
3831 my (@Params, @ParamTypes) = ();
3832 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3833 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3834 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3835 }
3836 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3837 { # checking parameters
3838 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003839 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003840 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003841 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003842 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003843 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003844 }
3845 @ParamTypes = (@ParamTypes, $PTName);
3846 }
3847 if(@ParamTypes) {
3848 $PureSignature .= "(".join(", ", @ParamTypes).")";
3849 }
3850 else
3851 {
3852 if($Compiler eq "MSVC")
3853 {
3854 $PureSignature .= "(void)";
3855 }
3856 else
3857 { # GCC
3858 $PureSignature .= "()";
3859 }
3860 }
3861 $PureSignature = delete_keywords($PureSignature);
3862 }
3863 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3864 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003865 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003866 $PureSignature = $ClassName."::".$PureSignature;
3867 }
3868 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3869 $PureSignature = $NS."::".$PureSignature;
3870 }
3871 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3872 $PureSignature .= " const";
3873 }
3874 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3875 $PureSignature .= " volatile";
3876 }
3877 my $ShowReturn = 0;
3878 if($Compiler eq "MSVC"
3879 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3880 {
3881 $ShowReturn=1;
3882 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003883 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3884 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003885 {
3886 $ShowReturn=1;
3887 }
3888 if($ShowReturn)
3889 { # mangled names for template function specializations include return value
3890 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3891 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003892 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003893 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3894 $PureSignature = $ReturnName." ".$PureSignature;
3895 }
3896 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003897 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003898}
3899
3900sub mangle_symbol($$$)
3901{ # mangling for simple methods
3902 # see gcc-4.6.0/gcc/cp/mangle.c
3903 my ($InfoId, $LibVersion, $Compiler) = @_;
3904 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3905 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3906 }
3907 my $Mangled = "";
3908 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003909 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003910 }
3911 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003912 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003913 }
3914 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3915}
3916
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003917sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003918{
3919 my ($InfoId, $LibVersion) = @_;
3920 return "";
3921}
3922
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003923sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003924{ # see gcc-4.6.0/gcc/cp/mangle.c
3925 my ($InfoId, $LibVersion) = @_;
3926 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003927 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003928 my %Repl = ();# SN_ replacements
3929 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3930 {
3931 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3932 if($MangledClass!~/\AN/) {
3933 $MangledClass = "N".$MangledClass;
3934 }
3935 else {
3936 $MangledClass=~s/E\Z//;
3937 }
3938 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3939 $MangledClass=~s/\AN/NV/;
3940 }
3941 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3942 $MangledClass=~s/\AN/NK/;
3943 }
3944 $Mangled .= $MangledClass;
3945 }
3946 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3947 { # mangled by name due to the absence of structured info
3948 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3949 if($MangledNS!~/\AN/) {
3950 $MangledNS = "N".$MangledNS;
3951 }
3952 else {
3953 $MangledNS=~s/E\Z//;
3954 }
3955 $Mangled .= $MangledNS;
3956 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003957 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003958 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003959 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003960 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003961 foreach (@TPos) {
3962 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3963 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003964 }
3965 elsif($TmplParams)
3966 { # remangling mode
3967 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003968 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003969 }
3970 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3971 $Mangled .= "C1";
3972 }
3973 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3974 $Mangled .= "D0";
3975 }
3976 elsif($ShortName)
3977 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003978 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3979 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003980 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003981 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003982 { # "const" global data is mangled as _ZL...
3983 $Mangled .= "L";
3984 }
3985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003986 if($ShortName=~/\Aoperator(\W.*)\Z/)
3987 {
3988 my $Op = $1;
3989 $Op=~s/\A[ ]+//g;
3990 if(my $OpMngl = $OperatorMangling{$Op}) {
3991 $Mangled .= $OpMngl;
3992 }
3993 else { # conversion operator
3994 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3995 }
3996 }
3997 else {
3998 $Mangled .= length($ShortName).$ShortName;
3999 }
4000 if(@TParams)
4001 { # templates
4002 $Mangled .= "I";
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04004003 foreach my $TParam (@TParams) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004004 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
4005 }
4006 $Mangled .= "E";
4007 }
4008 if(not $ClassId and @TParams) {
4009 add_substitution($ShortName, \%Repl, 0);
4010 }
4011 }
4012 if($ClassId or $NameSpace) {
4013 $Mangled .= "E";
4014 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004015 if(@TParams)
4016 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004017 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004018 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
4019 }
4020 }
4021 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
4022 {
4023 my @Params = ();
4024 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
4025 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
4026 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
4027 }
4028 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4029 { # checking parameters
4030 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
4031 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
4032 }
4033 if(not @Params) {
4034 $Mangled .= "v";
4035 }
4036 }
4037 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
4038 $Mangled = write_stdcxx_substitution($Mangled);
4039 if($Mangled eq "_Z") {
4040 return "";
4041 }
4042 return $Mangled;
4043}
4044
4045sub correct_incharge($$$)
4046{
4047 my ($InfoId, $LibVersion, $Mangled) = @_;
4048 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4049 {
4050 if($MangledNames{$LibVersion}{$Mangled}) {
4051 $Mangled=~s/C1E/C2E/;
4052 }
4053 }
4054 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4055 {
4056 if($MangledNames{$LibVersion}{$Mangled}) {
4057 $Mangled=~s/D0E/D1E/;
4058 }
4059 if($MangledNames{$LibVersion}{$Mangled}) {
4060 $Mangled=~s/D1E/D2E/;
4061 }
4062 }
4063 return $Mangled;
4064}
4065
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004066sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004067{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004068 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004069 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004070 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004071 return $Name;
4072 }
4073 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004074 while(my $CPos = find_center($TParams, "<"))
4075 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004076 $TParams = substr($TParams, $CPos);
4077 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004078 if($TParams=~s/\A<(.+)>\Z/$1/) {
4079 $Name=~s/<\Q$TParams\E>\Z//;
4080 }
4081 else
4082 { # error
4083 $TParams = "";
4084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004085 return ($Name, $TParams);
4086}
4087
4088sub get_sub_ns($)
4089{
4090 my $Name = $_[0];
4091 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004092 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004093 {
4094 push(@NS, substr($Name, 0, $CPos));
4095 $Name = substr($Name, $CPos);
4096 $Name=~s/\A:://;
4097 }
4098 return (join("::", @NS), $Name);
4099}
4100
4101sub mangle_ns($$$)
4102{
4103 my ($Name, $LibVersion, $Repl) = @_;
4104 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4105 {
4106 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4107 $Mangled=~s/\AN(.+)E\Z/$1/;
4108 return $Mangled;
4109
4110 }
4111 else
4112 {
4113 my ($MangledNS, $SubNS) = ("", "");
4114 ($SubNS, $Name) = get_sub_ns($Name);
4115 if($SubNS) {
4116 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4117 }
4118 $MangledNS .= length($Name).$Name;
4119 add_substitution($MangledNS, $Repl, 0);
4120 return $MangledNS;
4121 }
4122}
4123
4124sub mangle_param($$$)
4125{
4126 my ($PTid, $LibVersion, $Repl) = @_;
4127 my ($MPrefix, $Mangled) = ("", "");
4128 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004129 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004130 my $BaseType_Name = $BaseType{"Name"};
4131 if(not $BaseType_Name) {
4132 return "";
4133 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004134 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004135 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004136 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4137 while($Suffix=~/(&|\*|const)\Z/)
4138 {
4139 if($Suffix=~s/[ ]*&\Z//) {
4140 $MPrefix .= "R";
4141 }
4142 if($Suffix=~s/[ ]*\*\Z//) {
4143 $MPrefix .= "P";
4144 }
4145 if($Suffix=~s/[ ]*const\Z//)
4146 {
4147 if($MPrefix=~/R|P/
4148 or $Suffix=~/&|\*/) {
4149 $MPrefix .= "K";
4150 }
4151 }
4152 if($Suffix=~s/[ ]*volatile\Z//) {
4153 $MPrefix .= "V";
4154 }
4155 #if($Suffix=~s/[ ]*restrict\Z//) {
4156 #$MPrefix .= "r";
4157 #}
4158 }
4159 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4160 $Mangled .= $Token;
4161 }
4162 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4163 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004164 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004165 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004166 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004167 foreach (@TPos) {
4168 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4169 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004170 }
4171 elsif($TmplParams)
4172 { # remangling mode
4173 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004174 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004175 }
4176 my $MangledNS = "";
4177 my ($SubNS, $SName) = get_sub_ns($ShortName);
4178 if($SubNS) {
4179 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4180 }
4181 $MangledNS .= length($SName).$SName;
4182 if(@TParams) {
4183 add_substitution($MangledNS, $Repl, 0);
4184 }
4185 $Mangled .= "N".$MangledNS;
4186 if(@TParams)
4187 { # templates
4188 $Mangled .= "I";
4189 foreach my $TParam (@TParams) {
4190 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4191 }
4192 $Mangled .= "E";
4193 }
4194 $Mangled .= "E";
4195 }
4196 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4197 {
4198 if($BaseType{"Type"} eq "MethodPtr") {
4199 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4200 }
4201 else {
4202 $Mangled .= "PF";
4203 }
4204 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4205 my @Params = keys(%{$BaseType{"Param"}});
4206 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4207 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4208 }
4209 if(not @Params) {
4210 $Mangled .= "v";
4211 }
4212 $Mangled .= "E";
4213 }
4214 elsif($BaseType{"Type"} eq "FieldPtr")
4215 {
4216 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4217 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4218 }
4219 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4220 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4221 {
4222 if($Mangled eq $Optimized)
4223 {
4224 if($ShortName!~/::/)
4225 { # remove "N ... E"
4226 if($MPrefix) {
4227 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4228 }
4229 else {
4230 $Mangled=~s/\AN(.+)E\Z/$1/g;
4231 }
4232 }
4233 }
4234 else {
4235 $Mangled = $Optimized;
4236 }
4237 }
4238 add_substitution($Mangled, $Repl, 1);
4239 return $Mangled;
4240}
4241
4242sub mangle_template_param($$$)
4243{ # types + literals
4244 my ($TParam, $LibVersion, $Repl) = @_;
4245 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4246 return mangle_param($TPTid, $LibVersion, $Repl);
4247 }
4248 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4249 { # class_name<1u>::method(...)
4250 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4251 }
4252 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4253 { # class_name<(signed char)1>::method(...)
4254 return "L".$IntrinsicMangling{$1}.$2."E";
4255 }
4256 elsif($TParam eq "true")
4257 { # class_name<true>::method(...)
4258 return "Lb1E";
4259 }
4260 elsif($TParam eq "false")
4261 { # class_name<true>::method(...)
4262 return "Lb0E";
4263 }
4264 else { # internal error
4265 return length($TParam).$TParam;
4266 }
4267}
4268
4269sub add_substitution($$$)
4270{
4271 my ($Value, $Repl, $Rec) = @_;
4272 if($Rec)
4273 { # subtypes
4274 my @Subs = ($Value);
4275 while($Value=~s/\A(R|P|K)//) {
4276 push(@Subs, $Value);
4277 }
4278 foreach (reverse(@Subs)) {
4279 add_substitution($_, $Repl, 0);
4280 }
4281 return;
4282 }
4283 return if($Value=~/\AS(\d*)_\Z/);
4284 $Value=~s/\AN(.+)E\Z/$1/g;
4285 return if(defined $Repl->{$Value});
4286 return if(length($Value)<=1);
4287 return if($StdcxxMangling{$Value});
4288 # check for duplicates
4289 my $Base = $Value;
4290 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4291 {
4292 my $Num = $Repl->{$Type};
4293 my $Replace = macro_mangle($Num);
4294 $Base=~s/\Q$Replace\E/$Type/;
4295 }
4296 if(my $OldNum = $Repl->{$Base})
4297 {
4298 $Repl->{$Value} = $OldNum;
4299 return;
4300 }
4301 my @Repls = sort {$b<=>$a} values(%{$Repl});
4302 if(@Repls) {
4303 $Repl->{$Value} = $Repls[0]+1;
4304 }
4305 else {
4306 $Repl->{$Value} = -1;
4307 }
4308 # register duplicates
4309 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004310 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004311 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4312 {
4313 next if($Base eq $Type);
4314 my $Num = $Repl->{$Type};
4315 my $Replace = macro_mangle($Num);
4316 $Base=~s/\Q$Type\E/$Replace/;
4317 $Repl->{$Base} = $Repl->{$Value};
4318 }
4319}
4320
4321sub macro_mangle($)
4322{
4323 my $Num = $_[0];
4324 if($Num==-1) {
4325 return "S_";
4326 }
4327 else
4328 {
4329 my $Code = "";
4330 if($Num<10)
4331 { # S0_, S1_, S2_, ...
4332 $Code = $Num;
4333 }
4334 elsif($Num>=10 and $Num<=35)
4335 { # SA_, SB_, SC_, ...
4336 $Code = chr(55+$Num);
4337 }
4338 else
4339 { # S10_, S11_, S12_
4340 $Code = $Num-26; # 26 is length of english alphabet
4341 }
4342 return "S".$Code."_";
4343 }
4344}
4345
4346sub write_stdcxx_substitution($)
4347{
4348 my $Mangled = $_[0];
4349 if($StdcxxMangling{$Mangled}) {
4350 return $StdcxxMangling{$Mangled};
4351 }
4352 else
4353 {
4354 my @Repls = keys(%StdcxxMangling);
4355 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4356 foreach my $MangledType (@Repls)
4357 {
4358 my $Replace = $StdcxxMangling{$MangledType};
4359 #if($Mangled!~/$Replace/) {
4360 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4361 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4362 #}
4363 }
4364 }
4365 return $Mangled;
4366}
4367
4368sub write_substitution($$)
4369{
4370 my ($Mangled, $Repl) = @_;
4371 if(defined $Repl->{$Mangled}
4372 and my $MnglNum = $Repl->{$Mangled}) {
4373 $Mangled = macro_mangle($MnglNum);
4374 }
4375 else
4376 {
4377 my @Repls = keys(%{$Repl});
4378 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4379 # FIXME: how to apply replacements? by num or by pos
4380 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4381 foreach my $MangledType (@Repls)
4382 {
4383 my $Replace = macro_mangle($Repl->{$MangledType});
4384 if($Mangled!~/$Replace/) {
4385 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4386 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4387 }
4388 }
4389 }
4390 return $Mangled;
4391}
4392
4393sub delete_keywords($)
4394{
4395 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004396 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004397 return $TypeName;
4398}
4399
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004400sub uncover_typedefs($$)
4401{
4402 my ($TypeName, $LibVersion) = @_;
4403 return "" if(not $TypeName);
4404 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4405 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4406 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004407 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004408 while($TypeName_New ne $TypeName_Pre)
4409 {
4410 $TypeName_Pre = $TypeName_New;
4411 my $TypeName_Copy = $TypeName_New;
4412 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004413 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004414 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004415 if(not $Intrinsic_Keywords{$1}) {
4416 $Words{$1} = 1;
4417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004418 }
4419 foreach my $Word (keys(%Words))
4420 {
4421 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4422 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004423 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004424 if($BaseType_Name=~/\([\*]+\)/)
4425 { # FuncPtr
4426 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4427 {
4428 my $Type_Suffix = $1;
4429 $TypeName_New = $BaseType_Name;
4430 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004431 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004432 }
4433 }
4434 }
4435 else
4436 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004437 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004438 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004439 }
4440 }
4441 }
4442 }
4443 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4444}
4445
4446sub isInternal($)
4447{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004448 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4449 {
4450 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4451 {
4452 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4453 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4454 return 1;
4455 }
4456 }
4457 }
4458 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004459}
4460
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004461sub getDataVal($$)
4462{
4463 my ($InfoId, $TypeId) = @_;
4464 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4465 {
4466 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4467 {
4468 if(defined $LibInfo{$Version}{"info_type"}{$1}
4469 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4470 { # char const* data = "str"
4471 # NOTE: disabled
4472 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4473 {
4474 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4475 {
4476 if(defined $LibInfo{$Version}{"info_type"}{$1}
4477 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4478 {
4479 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4480 {
4481 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4482 {
4483 return getInitVal($1, $TypeId);
4484 }
4485 }
4486 }
4487 }
4488 }
4489 }
4490 else {
4491 return getInitVal($1, $TypeId);
4492 }
4493 }
4494 }
4495 return undef;
4496}
4497
4498sub getInitVal($$)
4499{
4500 my ($InfoId, $TypeId) = @_;
4501 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4502 {
4503 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4504 {
4505 if($InfoType eq "integer_cst")
4506 {
4507 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004508 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004509 { # characters
4510 $Val = chr($Val);
4511 }
4512 return $Val;
4513 }
4514 elsif($InfoType eq "string_cst") {
4515 return getNodeStrCst($InfoId);
4516 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004517 elsif($InfoType eq "var_decl")
4518 {
4519 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4520 return $Name;
4521 }
4522 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004523 }
4524 }
4525 return undef;
4526}
4527
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004528sub set_Class_And_Namespace($)
4529{
4530 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004531 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004532 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004533 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004534 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004535 my $NSInfoId = $1;
4536 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4537 {
4538 if($InfoType eq "namespace_decl") {
4539 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4540 }
4541 elsif($InfoType eq "record_type") {
4542 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4543 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004544 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545 }
4546 }
4547 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4548 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4549 { # identify language
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04004550 if($COMMON_LANGUAGE{$Version} ne "C++")
4551 {
4552 if(my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"})
4553 {
4554 if(index($ShortName, "__")!=0)
4555 { # skip C++ symbols from pthread.h:
4556 # __pthread_cleanup_class, __restore, __defer, __setdoit, etc.
4557 setLanguage($Version, "C++");
4558 }
4559 }
4560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004561 }
4562}
4563
4564sub debugType($$)
4565{
4566 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004567 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004568 printMsg("INFO", Dumper(\%Type));
4569}
4570
4571sub debugMangling($)
4572{
4573 my $LibVersion = $_[0];
4574 my %Mangled = ();
4575 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4576 {
4577 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4578 {
4579 if($Mngl=~/\A(_Z|\?)/) {
4580 $Mangled{$Mngl}=$InfoId;
4581 }
4582 }
4583 }
4584 translateSymbols(keys(%Mangled), $LibVersion);
4585 foreach my $Mngl (keys(%Mangled))
4586 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004587 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4588 my $U2 = $tr_name{$Mngl};
4589 if($U1 ne $U2) {
4590 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004591 }
4592 }
4593}
4594
4595sub linkSymbol($)
4596{ # link symbols from shared libraries
4597 # with the symbols from header files
4598 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004599 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004600 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4601 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004602 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4603 # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004604 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004605 {
4606 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4607 return correct_incharge($InfoId, $Version, $Mangled);
4608 }
4609 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004610 if($CheckHeadersOnly
4611 or not $BinaryOnly)
4612 { # 1. --headers-only mode
4613 # 2. not mangled src-only symbols
4614 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4615 return $Mangled;
4616 }
4617 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004618 }
4619 return "";
4620}
4621
4622sub setLanguage($$)
4623{
4624 my ($LibVersion, $Lang) = @_;
4625 if(not $UserLang) {
4626 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4627 }
4628}
4629
4630sub getSymbolInfo($)
4631{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004632 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004633 if(isInternal($InfoId)) {
4634 return;
4635 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004636 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4637 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004638 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4639 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004640 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004641 return;
4642 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004643 setFuncAccess($InfoId);
4644 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004645 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4646 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004647 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004648 return;
4649 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004650 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004651 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4652 {
4653 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4654 { # templates
4655 delete($SymbolInfo{$Version}{$InfoId});
4656 return;
4657 }
4658 }
4659 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4660 {
4661 if(defined $MissedTypedef{$Version}{$Rid})
4662 {
4663 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4664 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4665 }
4666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004667 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004668 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4669 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004670 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004671 my $Orig = getFuncOrig($InfoId);
4672 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4673 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4674 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004675 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004676 return;
4677 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004678
4679 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004680 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004681 my @TParams = getTParams($Orig, "Func");
4682 if(not @TParams)
4683 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004684 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004685 return;
4686 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004687 foreach my $Pos (0 .. $#TParams) {
4688 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4689 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004690 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004691 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4692 { # operator<< <T>, operator>> <T>
4693 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4694 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004695 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004696 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004697 }
4698 else
4699 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004700 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004701 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004702 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4703 {
4704 if($OSgroup eq "windows")
4705 { # cut the offset
4706 $MnglName=~s/\@\d+\Z//g;
4707 }
4708 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4709
4710 # NOTE: mangling of some symbols may change depending on GCC version
4711 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4712 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4713 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004714
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004715 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004716 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004717 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004718 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004719 return;
4720 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004721 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004723 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004724 if($Skip)
4725 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004726 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004727 return;
4728 }
4729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004730 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004731 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4732 {
4733 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4734 { # templates
4735 delete($SymbolInfo{$Version}{$InfoId});
4736 return;
4737 }
4738 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004739 if(not $CheckHeadersOnly)
4740 {
4741 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4742 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4743 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4744 { # functions (C++): not mangled in library, but are mangled in TU dump
4745 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4746 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4747 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4748 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004749 }
4750 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004751 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4752 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004753 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004754 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004755 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004756 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004758 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004759 }
4760 if($COMMON_LANGUAGE{$Version} eq "C++")
4761 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004762 # C++ or --headers-only mode
4763 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004764 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004765 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4766 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004767 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004768 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004769 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004770 if(my $Mangled = linkSymbol($InfoId)) {
4771 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004772 }
4773 }
4774 if($OStarget eq "windows")
4775 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004776 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004777 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004778 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004779 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004780 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004781 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004782 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004783 }
4784 }
4785 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004786 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004787 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789 return;
4790 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004791 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004792 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004793 { # identify virtual and pure virtual functions
4794 # NOTE: constructors cannot be virtual
4795 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4796 # in the TU dump, so taking it from the original symbol
4797 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4798 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4799 { # NOTE: D2 destructors are not present in a v-table
4800 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4801 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004803 if(isInline($InfoId)) {
4804 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004805 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04004806 if(hasThrow($InfoId)) {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004807 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4808 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004809 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4810 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4811 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004812 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4813 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004814 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004815 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004816 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004817 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004818 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004819 }
4820 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004821 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4822 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04004823 if(not $ExtraDump)
4824 {
4825 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4826 { # non-target symbols
4827 delete($SymbolInfo{$Version}{$InfoId});
4828 return;
4829 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004830 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004831 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004832 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4833 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4834 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4835 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004836 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004837 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4838 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004839 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004840 return;
4841 }
4842 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004843 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004844 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004845 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004846 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004847 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004848 return;
4849 }
4850 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004851 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004852 }
4853 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004854 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4855 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4856 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004857 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004858 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4859 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004860 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004861 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004862 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004863 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004864 }
4865 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004866 if(getFuncLink($InfoId) eq "Static") {
4867 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004868 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004869 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4870 {
4871 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4872 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004873 if($Unmangled=~/\.\_\d/)
4874 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004875 delete($SymbolInfo{$Version}{$InfoId});
4876 return;
4877 }
4878 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004879 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004880 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4881 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4882 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004883 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004884 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4885 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004886 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004887
4888 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4889 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4890 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004891}
4892
4893sub isInline($)
4894{ # "body: undefined" in the tree
4895 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004896 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4897 {
4898 if($Info=~/ undefined /i) {
4899 return 0;
4900 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004901 }
4902 return 1;
4903}
4904
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004905sub hasThrow($)
4906{
4907 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4908 {
4909 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4910 return getTreeAttr_Unql($1, "unql");
4911 }
4912 }
4913 return 1;
4914}
4915
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004916sub getTypeId($)
4917{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004918 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4919 {
4920 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4921 return $1;
4922 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004923 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004924 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004925}
4926
4927sub setTypeMemb($$)
4928{
4929 my ($TypeId, $TypeAttr) = @_;
4930 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004931 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004932 if($TypeType eq "Enum")
4933 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004934 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004935 while($TypeMembInfoId)
4936 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004937 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004938 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4939 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4940 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4941 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004942 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004943 }
4944 }
4945 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4946 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004947 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004948 while($TypeMembInfoId)
4949 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004950 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004951 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004952 if(not $IType or $IType ne "field_decl")
4953 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004954 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004955 next;
4956 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004957 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4958 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004959 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004960 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004961 next;
4962 }
4963 if(not $StructMembName)
4964 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004965 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004966 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004967 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004968 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4969 if(isAnon($UnnamedTName))
4970 { # rename unnamed fields to unnamed0, unnamed1, ...
4971 $StructMembName = "unnamed".($UnnamedPos++);
4972 }
4973 }
4974 }
4975 if(not $StructMembName)
4976 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004977 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004978 next;
4979 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004980 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4981 if(defined $MissedTypedef{$Version}{$MembTypeId})
4982 {
4983 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4984 $MembTypeId = $AddedTid;
4985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004986 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004987 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4988 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004989 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004990 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004991 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4992 }
4993 if($MInfo=~/spec:\s*mutable /)
4994 { # mutable fields
4995 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004996 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004997 if(my $Algn = getAlgn($TypeMembInfoId)) {
4998 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4999 }
5000 if(my $BFSize = getBitField($TypeMembInfoId))
5001 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005002 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005003 }
5004 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005005 { # in bytes
5006 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005008
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005009 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005010 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005011 }
5012 }
5013}
5014
5015sub setFuncParams($)
5016{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005017 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005018 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005019 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005020 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005021 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
5022 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005023 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005024 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005025 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
5026 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005027 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005028 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
5029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005030 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005031 else
5032 { # skip
5033 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005034 }
5035 $ParamInfoId = getNextElem($ParamInfoId);
5036 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005037 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005038 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005039 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005040 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
5041 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
5042 if(not $ParamName)
5043 { # unnamed
5044 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005045 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005046 if(defined $MissedTypedef{$Version}{$ParamTypeId})
5047 {
5048 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
5049 $ParamTypeId = $AddedTid;
5050 }
5051 }
5052 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005053 if(not $PType or $PType eq "Unknown") {
5054 return 1;
5055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005056 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005057 if(not $PTName) {
5058 return 1;
5059 }
5060 if($PTName eq "void") {
5061 last;
5062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005064 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005065 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 $ParamInfoId = getNextElem($ParamInfoId);
5068 next;
5069 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005070 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5071 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005072 if(my $Algn = getAlgn($ParamInfoId)) {
5073 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5074 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005075 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5076 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005077 }
5078 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5079 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005080 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005081 }
5082 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005083 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005084 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005085 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005086 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005087 }
5088 return 0;
5089}
5090
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005091sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005092{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005093 my ($InfoId, $Vtt_Pos) = @_;
5094 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005095 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005096 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005097 $ParamListElemId = getNextElem($ParamListElemId);
5098 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005099 if(not $ParamListElemId)
5100 { # foo(...)
5101 return 1;
5102 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005103 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005104 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005105 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005106 { # actual params: may differ from formal args
5107 # formal int*const
5108 # actual: int*
5109 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005110 {
5111 $Vtt_Pos=-1;
5112 $ParamListElemId = getNextElem($ParamListElemId);
5113 next;
5114 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005115 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5116 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005117 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005118 $HaveVoid = 1;
5119 last;
5120 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005121 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005122 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005123 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005124 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5125 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005126 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5127 }
5128 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005129 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005130 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005131 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5132 {
5133 my $Val = getInitVal($PurpId, $ParamTypeId);
5134 if(defined $Val) {
5135 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005137 }
5138 }
5139 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005140 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005141 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005142 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005143}
5144
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005145sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005146{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005147 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5148 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005149 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5150 return $1;
5151 }
5152 }
5153 return "";
5154}
5155
5156sub getTreeAttr_Chain($)
5157{
5158 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5159 {
5160 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5161 return $1;
5162 }
5163 }
5164 return "";
5165}
5166
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04005167sub getTreeAttr_Unql($)
5168{
5169 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5170 {
5171 if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5172 return $1;
5173 }
5174 }
5175 return "";
5176}
5177
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005178sub getTreeAttr_Scpe($)
5179{
5180 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5181 {
5182 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5183 return $1;
5184 }
5185 }
5186 return "";
5187}
5188
5189sub getTreeAttr_Type($)
5190{
5191 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5192 {
5193 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5194 return $1;
5195 }
5196 }
5197 return "";
5198}
5199
5200sub getTreeAttr_Name($)
5201{
5202 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5203 {
5204 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5205 return $1;
5206 }
5207 }
5208 return "";
5209}
5210
5211sub getTreeAttr_Mngl($)
5212{
5213 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5214 {
5215 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5216 return $1;
5217 }
5218 }
5219 return "";
5220}
5221
5222sub getTreeAttr_Prms($)
5223{
5224 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5225 {
5226 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5227 return $1;
5228 }
5229 }
5230 return "";
5231}
5232
5233sub getTreeAttr_Fncs($)
5234{
5235 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5236 {
5237 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5238 return $1;
5239 }
5240 }
5241 return "";
5242}
5243
5244sub getTreeAttr_Csts($)
5245{
5246 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5247 {
5248 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5249 return $1;
5250 }
5251 }
5252 return "";
5253}
5254
5255sub getTreeAttr_Purp($)
5256{
5257 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5258 {
5259 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5260 return $1;
5261 }
5262 }
5263 return "";
5264}
5265
5266sub getTreeAttr_Valu($)
5267{
5268 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5269 {
5270 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5271 return $1;
5272 }
5273 }
5274 return "";
5275}
5276
5277sub getTreeAttr_Flds($)
5278{
5279 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5280 {
5281 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5282 return $1;
5283 }
5284 }
5285 return "";
5286}
5287
5288sub getTreeAttr_Args($)
5289{
5290 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5291 {
5292 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005293 return $1;
5294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005295 }
5296 return "";
5297}
5298
5299sub getTreeValue($)
5300{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005301 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5302 {
5303 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5304 return $1;
5305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005306 }
5307 return "";
5308}
5309
5310sub getTreeAccess($)
5311{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005312 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005313 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005314 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5315 {
5316 my $Access = $1;
5317 if($Access eq "prot") {
5318 return "protected";
5319 }
5320 elsif($Access eq "priv") {
5321 return "private";
5322 }
5323 }
5324 elsif($Info=~/ protected /)
5325 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005326 return "protected";
5327 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005328 elsif($Info=~/ private /)
5329 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005330 return "private";
5331 }
5332 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005333 return "public";
5334}
5335
5336sub setFuncAccess($)
5337{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005338 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005339 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005340 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005341 }
5342 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005343 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005344 }
5345}
5346
5347sub setTypeAccess($$)
5348{
5349 my ($TypeId, $TypeAttr) = @_;
5350 my $Access = getTreeAccess($TypeId);
5351 if($Access eq "protected") {
5352 $TypeAttr->{"Protected"} = 1;
5353 }
5354 elsif($Access eq "private") {
5355 $TypeAttr->{"Private"} = 1;
5356 }
5357}
5358
5359sub setFuncKind($)
5360{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005361 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5362 {
5363 if($Info=~/pseudo tmpl/) {
5364 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5365 }
5366 elsif($Info=~/ constructor /) {
5367 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5368 }
5369 elsif($Info=~/ destructor /) {
5370 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5371 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005372 }
5373}
5374
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005375sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005376{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005377 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5378 {
5379 if($Info=~/spec[ ]*:[ ]*pure /) {
5380 return "PureVirt";
5381 }
5382 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5383 return "Virt";
5384 }
5385 elsif($Info=~/ pure\s+virtual /)
5386 { # support for old GCC versions
5387 return "PureVirt";
5388 }
5389 elsif($Info=~/ virtual /)
5390 { # support for old GCC versions
5391 return "Virt";
5392 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005393 }
5394 return "";
5395}
5396
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005397sub getFuncLink($)
5398{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005399 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5400 {
5401 if($Info=~/link[ ]*:[ ]*static /) {
5402 return "Static";
5403 }
5404 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005405 return $1;
5406 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005407 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005408 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005409}
5410
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005411sub get_IntNameSpace($$)
5412{
5413 my ($Interface, $LibVersion) = @_;
5414 return "" if(not $Interface or not $LibVersion);
5415 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5416 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5417 }
5418 my $Signature = get_Signature($Interface, $LibVersion);
5419 if($Signature=~/\:\:/)
5420 {
5421 my $FounNameSpace = 0;
5422 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5423 {
5424 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5425 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5426 }
5427 }
5428 }
5429 else {
5430 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5431 }
5432}
5433
5434sub parse_TypeNameSpace($$)
5435{
5436 my ($TypeName, $LibVersion) = @_;
5437 return "" if(not $TypeName or not $LibVersion);
5438 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5439 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5440 }
5441 if($TypeName=~/\:\:/)
5442 {
5443 my $FounNameSpace = 0;
5444 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5445 {
5446 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5447 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5448 }
5449 }
5450 }
5451 else {
5452 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5453 }
5454}
5455
5456sub getNameSpace($)
5457{
5458 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005459 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005460 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005461 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005462 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005463 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005464 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005465 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5466 {
5467 my $NameSpace = getTreeStr($1);
5468 if($NameSpace eq "::")
5469 { # global namespace
5470 return "";
5471 }
5472 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5473 $NameSpace = $BaseNameSpace."::".$NameSpace;
5474 }
5475 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5476 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005477 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005478 else {
5479 return "";
5480 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005481 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005482 elsif($InfoType eq "record_type")
5483 { # inside data type
5484 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5485 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005486 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005488 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005489 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005490}
5491
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005492sub getEnumMembVal($)
5493{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005494 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005495 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005496 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5497 {
5498 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5499 {
5500 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5501 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5502 return getTreeValue($1);
5503 }
5504 else
5505 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5506 return getTreeValue($1);
5507 }
5508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005509 }
5510 }
5511 return "";
5512}
5513
5514sub getSize($)
5515{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005516 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5517 {
5518 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5519 return getTreeValue($1);
5520 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005521 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005522 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005523}
5524
5525sub getAlgn($)
5526{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005527 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5528 {
5529 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5530 return $1;
5531 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005532 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005533 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005534}
5535
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005536sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005537{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005538 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5539 {
5540 if($Info=~/ bitfield /) {
5541 return getSize($_[0]);
5542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005543 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005544 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005545}
5546
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005547sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005548{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005549 if(my $Chan = getTreeAttr_Chan($_[0])) {
5550 return $Chan;
5551 }
5552 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5553 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005554 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005555 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005556}
5557
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005558sub registerHeader($$)
5559{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005560 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005561 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005562 return "";
5563 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005564 if(is_abs($Header) and not -f $Header)
5565 { # incorrect absolute path
5566 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005567 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005568 if(skipHeader($Header, $LibVersion))
5569 { # skip
5570 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005571 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005572 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5573 {
5574 detect_header_includes($Header_Path, $LibVersion);
5575
5576 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5577 { # redirect
5578 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5579 or skipHeader($RHeader_Path, $LibVersion))
5580 { # skip
5581 return "";
5582 }
5583 $Header_Path = $RHeader_Path;
5584 }
5585 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5586 { # skip
5587 return "";
5588 }
5589
5590 if(my $HName = get_filename($Header_Path))
5591 { # register
5592 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5593 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5594 }
5595
5596 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5597 or $Header!~/\.(\w+)\Z/)
5598 { # hpp, hh
5599 setLanguage($LibVersion, "C++");
5600 }
5601
5602 if($CheckHeadersOnly
5603 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5604 { # /usr/include/c++/4.6.1/...
5605 $STDCXX_TESTING = 1;
5606 }
5607
5608 return $Header_Path;
5609 }
5610 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005611}
5612
5613sub register_directory($$$)
5614{
5615 my ($Dir, $WithDeps, $LibVersion) = @_;
5616 $Dir=~s/[\/\\]+\Z//g;
5617 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005618 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 $Dir = get_abs_path($Dir);
5620 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005621 if($WithDeps)
5622 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005623 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5624 return;
5625 }
5626 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5627 $Mode = "DepsOnly";
5628 }
5629 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005630 else
5631 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005632 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5633 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5634 return;
5635 }
5636 }
5637 $Header_Dependency{$LibVersion}{$Dir} = 1;
5638 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5639 if($Mode eq "DepsOnly")
5640 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005641 foreach my $Path (cmd_find($Dir,"d")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005642 $Header_Dependency{$LibVersion}{$Path} = 1;
5643 }
5644 return;
5645 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005646 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005647 {
5648 if($WithDeps)
5649 {
5650 my $SubDir = $Path;
5651 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5652 { # register all sub directories
5653 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5654 }
5655 }
5656 next if(is_not_header($Path));
5657 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005658 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005659 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005660 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005661 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5662 }
5663 }
5664 if(get_filename($Dir) eq "include")
5665 { # search for "lib/include/" directory
5666 my $LibDir = $Dir;
5667 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5668 register_directory($LibDir, $WithDeps, $LibVersion);
5669 }
5670 }
5671}
5672
5673sub parse_redirect($$$)
5674{
5675 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005676 my @Errors = ();
5677 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5678 push(@Errors, $1);
5679 }
5680 my $Redirect = "";
5681 foreach (@Errors)
5682 {
5683 s/\s{2,}/ /g;
5684 if(/(only|must\ include
5685 |update\ to\ include
5686 |replaced\ with
5687 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005688 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005689 {
5690 $Redirect = $2;
5691 last;
5692 }
5693 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5694 {
5695 $Redirect = $2;
5696 last;
5697 }
5698 elsif(/this\ header\ should\ not\ be\ used
5699 |programs\ should\ not\ directly\ include
5700 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5701 |is\ not\ supported\ API\ for\ general\ use
5702 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005703 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005704 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5705 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5706 }
5707 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005708 if($Redirect)
5709 {
5710 $Redirect=~s/\A<//g;
5711 $Redirect=~s/>\Z//g;
5712 }
5713 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005714}
5715
5716sub parse_includes($$)
5717{
5718 my ($Content, $Path) = @_;
5719 my %Includes = ();
5720 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005721 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005722 my ($Header, $Method) = ($5, $4);
5723 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005724 if($Method eq "\"" or is_abs($Header))
5725 {
5726 if(-e joinPath(get_dirname($Path), $Header))
5727 { # relative path exists
5728 $Includes{$Header} = -1;
5729 }
5730 else
5731 { # include "..." that doesn't exist is equal to include <...>
5732 $Includes{$Header} = 2;
5733 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005734 }
5735 else {
5736 $Includes{$Header} = 1;
5737 }
5738 }
5739 return \%Includes;
5740}
5741
5742sub ignore_path($)
5743{
5744 my $Path = $_[0];
5745 if($Path=~/\~\Z/)
5746 {# skipping system backup files
5747 return 1;
5748 }
5749 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5750 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5751 return 1;
5752 }
5753 return 0;
5754}
5755
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005756sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005757{
5758 my ($ArrRef, $W) = @_;
5759 return if(length($W)<2);
5760 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5761}
5762
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005763sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005764{
5765 my ($H1, $H2) = @_;
5766 $H1=~s/\.[a-z]+\Z//ig;
5767 $H2=~s/\.[a-z]+\Z//ig;
5768 my ($HDir1, $Hname1) = separate_path($H1);
5769 my ($HDir2, $Hname2) = separate_path($H2);
5770 my $Dirname1 = get_filename($HDir1);
5771 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005772 if($_[0] eq $_[1]
5773 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005774 return 0;
5775 }
5776 elsif($H1=~/\A\Q$H2\E/) {
5777 return 1;
5778 }
5779 elsif($H2=~/\A\Q$H1\E/) {
5780 return -1;
5781 }
5782 elsif($HDir1=~/\Q$Hname1\E/i
5783 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005784 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005785 return -1;
5786 }
5787 elsif($HDir2=~/\Q$Hname2\E/i
5788 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005789 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005790 return 1;
5791 }
5792 elsif($Hname1=~/\Q$Dirname1\E/i
5793 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005794 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005795 return -1;
5796 }
5797 elsif($Hname2=~/\Q$Dirname2\E/i
5798 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005799 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005800 return 1;
5801 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005802 elsif($Hname1=~/(config|lib|util)/i
5803 and $Hname2!~/(config|lib|util)/i)
5804 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005805 return -1;
5806 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005807 elsif($Hname2=~/(config|lib|util)/i
5808 and $Hname1!~/(config|lib|util)/i)
5809 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005810 return 1;
5811 }
5812 elsif(checkRelevance($H1)
5813 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005814 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005815 return -1;
5816 }
5817 elsif(checkRelevance($H2)
5818 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005819 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005820 return 1;
5821 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005822 else
5823 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005824 return (lc($H1) cmp lc($H2));
5825 }
5826}
5827
5828sub searchForHeaders($)
5829{
5830 my $LibVersion = $_[0];
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005831
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005832 # gcc standard include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005833 registerGccHeaders();
5834
5835 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
5836 { # c++ standard include paths
5837 registerCppHeaders();
5838 }
5839
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005840 # processing header paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005841 foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}},
5842 @{$Descriptor{$LibVersion}{"AddIncludePaths"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005843 {
5844 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005845 if($SystemRoot)
5846 {
5847 if(is_abs($Path)) {
5848 $Path = $SystemRoot.$Path;
5849 }
5850 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005851 if(not -e $Path) {
5852 exitStatus("Access_Error", "can't access \'$Path\'");
5853 }
5854 elsif(-f $Path) {
5855 exitStatus("Access_Error", "\'$Path\' - not a directory");
5856 }
5857 elsif(-d $Path)
5858 {
5859 $Path = get_abs_path($Path);
5860 register_directory($Path, 0, $LibVersion);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005861 if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
5862 push(@{$Add_Include_Paths{$LibVersion}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005863 }
5864 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005865 push(@{$Include_Paths{$LibVersion}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 }
5867 }
5868 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005869 if(@{$Include_Paths{$LibVersion}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005870 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5871 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005872
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005873 # registering directories
5874 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5875 {
5876 next if(not -e $Path);
5877 $Path = get_abs_path($Path);
5878 $Path = path_format($Path, $OSgroup);
5879 if(-d $Path) {
5880 register_directory($Path, 1, $LibVersion);
5881 }
5882 elsif(-f $Path)
5883 {
5884 my $Dir = get_dirname($Path);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005885 if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005886 and not $LocalIncludes{$Dir})
5887 {
5888 register_directory($Dir, 1, $LibVersion);
5889 if(my $OutDir = get_dirname($Dir))
5890 { # registering the outer directory
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005891 if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005892 and not $LocalIncludes{$OutDir}) {
5893 register_directory($OutDir, 0, $LibVersion);
5894 }
5895 }
5896 }
5897 }
5898 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005899
5900 # clean memory
5901 %RegisteredDirs = ();
5902
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005903 # registering headers
5904 my $Position = 0;
5905 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5906 {
5907 if(is_abs($Dest) and not -e $Dest) {
5908 exitStatus("Access_Error", "can't access \'$Dest\'");
5909 }
5910 $Dest = path_format($Dest, $OSgroup);
5911 if(is_header($Dest, 1, $LibVersion))
5912 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005913 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005914 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5915 }
5916 }
5917 elsif(-d $Dest)
5918 {
5919 my @Registered = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005920 foreach my $Path (cmd_find($Dest,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005921 {
5922 next if(ignore_path($Path));
5923 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005924 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005925 push(@Registered, $HPath);
5926 }
5927 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005928 @Registered = sort {sortHeaders($a, $b)} @Registered;
5929 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005930 foreach my $Path (@Registered) {
5931 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5932 }
5933 }
5934 else {
5935 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5936 }
5937 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005938 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5939 { # preparing preamble headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005940 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005941 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005942 if(is_abs($Header) and not -f $Header) {
5943 exitStatus("Access_Error", "can't access file \'$Header\'");
5944 }
5945 $Header = path_format($Header, $OSgroup);
5946 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5947 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005948 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005949 push_U($Include_Preamble{$LibVersion}, $Header_Path);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005950 }
5951 else {
5952 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5953 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005954 }
5955 }
5956 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5957 { # set relative paths (for duplicates)
5958 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5959 { # search for duplicates
5960 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5961 my $Prefix = get_dirname($FirstPath);
5962 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5963 { # detect a shortest distinguishing prefix
5964 my $NewPrefix = $1;
5965 my %Identity = ();
5966 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5967 {
5968 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5969 $Identity{$Path} = $1;
5970 }
5971 }
5972 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5973 { # all names are differend with current prefix
5974 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5975 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5976 }
5977 last;
5978 }
5979 $Prefix = $NewPrefix; # increase prefix
5980 }
5981 }
5982 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005983
5984 # clean memory
5985 %HeaderName_Paths = ();
5986
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005987 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5988 { # ordering headers according to descriptor
5989 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5990 my ($Pos, $PairPos) = (-1, -1);
5991 my ($Path, $PairPath) = ();
5992 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5993 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5994 foreach my $Header_Path (@Paths)
5995 {
5996 if(get_filename($Header_Path) eq $PairName)
5997 {
5998 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5999 $PairPath = $Header_Path;
6000 }
6001 if(get_filename($Header_Path) eq $HeaderName)
6002 {
6003 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
6004 $Path = $Header_Path;
6005 }
6006 }
6007 if($PairPos!=-1 and $Pos!=-1
6008 and int($PairPos)<int($Pos))
6009 {
6010 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
6011 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
6012 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
6013 }
6014 }
6015 if(not keys(%{$Registered_Headers{$LibVersion}})) {
6016 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
6017 }
6018}
6019
6020sub detect_real_includes($$)
6021{
6022 my ($AbsPath, $LibVersion) = @_;
6023 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
6024 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
6025 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6026 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6027 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006028 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
6029
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006030 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
6031 return () if(not $Path);
6032 open(PREPROC, $Path);
6033 while(<PREPROC>)
6034 {
6035 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
6036 {
6037 my $Include = path_format($1, $OSgroup);
6038 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
6039 next;
6040 }
6041 if($Include eq $AbsPath) {
6042 next;
6043 }
6044 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
6045 }
6046 }
6047 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006048 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6049}
6050
6051sub detect_header_includes($$)
6052{
6053 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006054 return if(not $LibVersion or not $Path);
6055 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
6056 return;
6057 }
6058 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
6059
6060 if(not -e $Path) {
6061 return;
6062 }
6063
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006064 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006065 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
6066 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006067 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006068 {
6069 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006070 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006071 }
6072 if($RedirectPath ne $Path) {
6073 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6074 }
6075 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006076 else
6077 { # can't find
6078 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006080 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006081 if(my $Inc = parse_includes($Content, $Path))
6082 {
6083 foreach my $Include (keys(%{$Inc}))
6084 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006085 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006087 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006088}
6089
6090sub simplify_path($)
6091{
6092 my $Path = $_[0];
6093 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6094 return $Path;
6095}
6096
6097sub fromLibc($)
6098{ # GLIBC header
6099 my $Path = $_[0];
6100 my ($Dir, $Name) = separate_path($Path);
6101 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006102 { # /usr/include/{stdio, ...}.h
6103 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006104 return 1;
6105 }
6106 if(isLibcDir($Dir)) {
6107 return 1;
6108 }
6109 return 0;
6110}
6111
6112sub isLibcDir($)
6113{ # GLIBC directory
6114 my $Dir = $_[0];
6115 my ($OutDir, $Name) = separate_path($Dir);
6116 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6117 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6118 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6119 return 1;
6120 }
6121 return 0;
6122}
6123
6124sub detect_recursive_includes($$)
6125{
6126 my ($AbsPath, $LibVersion) = @_;
6127 return () if(not $AbsPath);
6128 if(isCyclical(\@RecurInclude, $AbsPath)) {
6129 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6130 }
6131 my ($AbsDir, $Name) = separate_path($AbsPath);
6132 if(isLibcDir($AbsDir))
6133 { # GLIBC internals
6134 return ();
6135 }
6136 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6137 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6138 }
6139 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006140
6141 if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING)
6142 { # skip /usr/include/c++/*/ headers
6143 return () if(not $ExtraInfo);
6144 }
6145
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006146 push(@RecurInclude, $AbsPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006147 if(grep { $AbsDir eq $_ } @DefaultGccPaths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006148 or fromLibc($AbsPath))
6149 { # check "real" (non-"model") include paths
6150 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6151 pop(@RecurInclude);
6152 return @Paths;
6153 }
6154 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6155 detect_header_includes($AbsPath, $LibVersion);
6156 }
6157 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6158 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006159 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006160 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006161 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006162 { # for #include "..."
6163 my $Candidate = joinPath($AbsDir, $Include);
6164 if(-f $Candidate) {
6165 $HPath = simplify_path($Candidate);
6166 }
6167 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006168 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006169 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006170 { # search for the nearest header
6171 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6172 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6173 if(-f $Candidate) {
6174 $HPath = $Candidate;
6175 }
6176 }
6177 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006178 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006179 }
6180 next if(not $HPath);
6181 if($HPath eq $AbsPath) {
6182 next;
6183 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006184
6185 if($Debug)
6186 { # boundary headers
6187 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6188 #{
6189 # print STDERR "$AbsPath -> $HPath\n";
6190 #}
6191 }
6192
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006193 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6194 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006195 { # only include <...>, skip include "..." prefixes
6196 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6197 }
6198 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6199 {
6200 if($IncPath eq $AbsPath) {
6201 next;
6202 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006203 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6204 if($RIncType==-1)
6205 { # include "..."
6206 $RIncType = $IncType;
6207 }
6208 elsif($RIncType==2)
6209 {
6210 if($IncType!=-1) {
6211 $RIncType = $IncType;
6212 }
6213 }
6214 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006215 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6216 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6217 }
6218 }
6219 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6220 {
6221 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6222 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6223 { # distinguish math.h from glibc and math.h from the tested library
6224 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6225 last;
6226 }
6227 }
6228 }
6229 pop(@RecurInclude);
6230 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6231}
6232
6233sub find_in_framework($$$)
6234{
6235 my ($Header, $Framework, $LibVersion) = @_;
6236 return "" if(not $Header or not $Framework or not $LibVersion);
6237 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6238 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6239 }
6240 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6241 {
6242 if(get_filename($Dependency) eq $Framework
6243 and -f get_dirname($Dependency)."/".$Header) {
6244 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6245 }
6246 }
6247 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6248}
6249
6250sub find_in_defaults($)
6251{
6252 my $Header = $_[0];
6253 return "" if(not $Header);
6254 if(defined $Cache{"find_in_defaults"}{$Header}) {
6255 return $Cache{"find_in_defaults"}{$Header};
6256 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006257 foreach my $Dir (@DefaultIncPaths,
6258 @DefaultGccPaths,
6259 @DefaultCppPaths,
6260 @UsersIncPath)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006261 {
6262 next if(not $Dir);
6263 if(-f $Dir."/".$Header) {
6264 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6265 }
6266 }
6267 return ($Cache{"find_in_defaults"}{$Header}="");
6268}
6269
6270sub cmp_paths($$)
6271{
6272 my ($Path1, $Path2) = @_;
6273 my @Parts1 = split(/[\/\\]/, $Path1);
6274 my @Parts2 = split(/[\/\\]/, $Path2);
6275 foreach my $Num (0 .. $#Parts1)
6276 {
6277 my $Part1 = $Parts1[$Num];
6278 my $Part2 = $Parts2[$Num];
6279 if($GlibcDir{$Part1}
6280 and not $GlibcDir{$Part2}) {
6281 return 1;
6282 }
6283 elsif($GlibcDir{$Part2}
6284 and not $GlibcDir{$Part1}) {
6285 return -1;
6286 }
6287 elsif($Part1=~/glib/
6288 and $Part2!~/glib/) {
6289 return 1;
6290 }
6291 elsif($Part1!~/glib/
6292 and $Part2=~/glib/) {
6293 return -1;
6294 }
6295 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6296 return $CmpRes;
6297 }
6298 }
6299 return 0;
6300}
6301
6302sub checkRelevance($)
6303{
6304 my ($Path) = @_;
6305 return 0 if(not $Path);
6306 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006307 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006308 }
6309 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006310 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006311 my @Tokens = split(/[_\d\W]+/, $Name);
6312 foreach (@Tokens)
6313 {
6314 next if(not $_);
6315 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6316 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6317 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6318 # include/evolution-data-server-1.4/libebook/e-book.h
6319 return 1;
6320 }
6321 }
6322 return 0;
6323}
6324
6325sub checkFamily(@)
6326{
6327 my @Paths = @_;
6328 return 1 if($#Paths<=0);
6329 my %Prefix = ();
6330 foreach my $Path (@Paths)
6331 {
6332 if($SystemRoot) {
6333 $Path = cut_path_prefix($Path, $SystemRoot);
6334 }
6335 if(my $Dir = get_dirname($Path))
6336 {
6337 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6338 $Prefix{$Dir} += 1;
6339 $Prefix{get_dirname($Dir)} += 1;
6340 }
6341 }
6342 foreach (sort keys(%Prefix))
6343 {
6344 if(get_depth($_)>=3
6345 and $Prefix{$_}==$#Paths+1) {
6346 return 1;
6347 }
6348 }
6349 return 0;
6350}
6351
6352sub isAcceptable($$$)
6353{
6354 my ($Header, $Candidate, $LibVersion) = @_;
6355 my $HName = get_filename($Header);
6356 if(get_dirname($Header))
6357 { # with prefix
6358 return 1;
6359 }
6360 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6361 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6362 return 1;
6363 }
6364 if(checkRelevance($Candidate))
6365 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6366 return 1;
6367 }
6368 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6369 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6370 # /usr/include/qt4/Qt/qsslconfiguration.h
6371 return 1;
6372 }
6373 if($OStarget eq "symbian")
6374 {
6375 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6376 return 1;
6377 }
6378 }
6379 return 0;
6380}
6381
6382sub isRelevant($$$)
6383{ # disallow to search for "abstract" headers in too deep directories
6384 my ($Header, $Candidate, $LibVersion) = @_;
6385 my $HName = get_filename($Header);
6386 if($OStarget eq "symbian")
6387 {
6388 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6389 return 0;
6390 }
6391 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006392 if($OStarget ne "bsd")
6393 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006394 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6395 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6396 return 0;
6397 }
6398 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006399 if($OStarget ne "windows")
6400 {
6401 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6402 { # skip /usr/include/wine/msvcrt
6403 return 0;
6404 }
6405 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006406 if(not get_dirname($Header)
6407 and $Candidate=~/[\/\\]wx[\/\\]/)
6408 { # do NOT search in system /wx/ directory
6409 # for headers without a prefix: sstream.h
6410 return 0;
6411 }
6412 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6413 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6414 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6415 return 0;
6416 }
6417 if($Candidate=~/[\/\\]asm-/
6418 and (my $Arch = getArch($LibVersion)) ne "unknown")
6419 { # arch-specific header files
6420 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6421 {# skip ../asm-arm/ if using x86 architecture
6422 return 0;
6423 }
6424 }
6425 my @Candidates = getSystemHeaders($HName, $LibVersion);
6426 if($#Candidates==1)
6427 { # unique header
6428 return 1;
6429 }
6430 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6431 if($#SCandidates==1)
6432 { # unique name
6433 return 1;
6434 }
6435 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6436 if(get_depth($Candidate)-$SystemDepth>=5)
6437 { # abstract headers in too deep directories
6438 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6439 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6440 return 0;
6441 }
6442 }
6443 if($Header eq "parser.h"
6444 and $Candidate!~/\/libxml2\//)
6445 { # select parser.h from xml2 library
6446 return 0;
6447 }
6448 if(not get_dirname($Header)
6449 and keys(%{$SystemHeaders{$HName}})>=3)
6450 { # many headers with the same name
6451 # like thread.h included without a prefix
6452 if(not checkFamily(@Candidates)) {
6453 return 0;
6454 }
6455 }
6456 return 1;
6457}
6458
6459sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006460{ # cache function
6461 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6462 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6463 }
6464 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6465}
6466
6467sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006468{
6469 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006470 if(-f $Header) {
6471 return $Header;
6472 }
6473 if(is_abs($Header) and not -f $Header)
6474 { # incorrect absolute path
6475 return "";
6476 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006477 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006478 { # too abstract configuration headers
6479 return "";
6480 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006481 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006482 if($OSgroup ne "windows")
6483 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006484 if(defined $WinHeaders{lc($HName)}
6485 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006486 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006487 return "";
6488 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006489 }
6490 if($OSgroup ne "macos")
6491 {
6492 if($HName eq "fp.h")
6493 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006494 return "";
6495 }
6496 }
6497 if($OSgroup ne "solaris")
6498 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006499 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006500 return "";
6501 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006502 if($Header eq "sys/atomic.h") {
6503 return "";
6504 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006505 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006506 if($OSgroup ne "hpux")
6507 {
6508 if($Header eq "sys/stream.h") {
6509 return "";
6510 }
6511 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006512 if($ObsoleteHeaders{$HName}) {
6513 return "";
6514 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006515
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006516 foreach my $Path (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006517 { # search in default paths
6518 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006519 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006520 }
6521 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006522 if(not keys(%SystemHeaders))
6523 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006524 detectSystemHeaders();
6525 }
6526 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6527 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6528 {
6529 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006530 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006531 }
6532 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006533 # error
6534 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006535}
6536
6537sub getSystemHeaders($$)
6538{
6539 my ($Header, $LibVersion) = @_;
6540 my @Candidates = ();
6541 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6542 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006543 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006544 next;
6545 }
6546 push(@Candidates, $Candidate);
6547 }
6548 return @Candidates;
6549}
6550
6551sub cut_path_prefix($$)
6552{
6553 my ($Path, $Prefix) = @_;
6554 return $Path if(not $Prefix);
6555 $Prefix=~s/[\/\\]+\Z//;
6556 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6557 return $Path;
6558}
6559
6560sub is_default_include_dir($)
6561{
6562 my $Dir = $_[0];
6563 $Dir=~s/[\/\\]+\Z//;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006564 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006565}
6566
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006567sub identifyHeader($$)
6568{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006569 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006570 if(not $Header) {
6571 return "";
6572 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006574 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6575 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006576 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006577 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006578}
6579
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006580sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006581{ # search for header by absolute path, relative path or name
6582 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006583 if(-f $Header)
6584 { # it's relative or absolute path
6585 return get_abs_path($Header);
6586 }
6587 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6588 and my $HeaderDir = find_in_defaults($Header))
6589 { # search for libc headers in the /usr/include
6590 # for non-libc target library before searching
6591 # in the library paths
6592 return joinPath($HeaderDir,$Header);
6593 }
6594 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6595 { # search in the target library paths
6596 return $Path;
6597 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006598 elsif(defined $DefaultGccHeader{$Header})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006599 { # search in the internal GCC include paths
6600 return $DefaultGccHeader{$Header};
6601 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006602 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006603 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006604 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006605 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006606 elsif(defined $DefaultCppHeader{$Header})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006607 { # search in the default G++ include paths
6608 return $DefaultCppHeader{$Header};
6609 }
6610 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6611 { # search everywhere in the system
6612 return $AnyPath;
6613 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006614 elsif($OSgroup eq "macos")
6615 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6616 if(my $Dir = get_dirname($Header))
6617 {
6618 my $RelPath = "Headers\/".get_filename($Header);
6619 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6620 return joinPath($HeaderDir, $RelPath);
6621 }
6622 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006624 # cannot find anything
6625 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006626}
6627
6628sub getLocation($)
6629{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006630 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6631 {
6632 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006633 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006634 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006635 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006636 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006637}
6638
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006639sub getNameByInfo($)
6640{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006641 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006642 {
6643 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6644 {
6645 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6646 {
6647 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6648 { # short unsigned int (may include spaces)
6649 return $1;
6650 }
6651 }
6652 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006653 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006654 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006655}
6656
6657sub getTreeStr($)
6658{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006659 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006660 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006661 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6662 {
6663 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006664 if($CppMode{$Version}
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006665 and $Str=~/\Ac99_(.+)\Z/)
6666 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006667 if($CppKeywords_A{$1}) {
6668 $Str=$1;
6669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006670 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006671 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006672 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006673 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006674 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006675}
6676
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006677sub getFuncShortName($)
6678{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006679 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006680 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006681 if(index($Info, " operator ")!=-1)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006682 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006683 if(index($Info, " conversion ")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006684 {
6685 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6686 {
6687 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6688 return "operator ".$RName;
6689 }
6690 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006691 }
6692 else
6693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006694 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6695 {
6696 if(my $Ind = $Operator_Indication{$1}) {
6697 return "operator".$Ind;
6698 }
6699 elsif(not $UnknownOperator{$1})
6700 {
6701 printMsg("WARNING", "unknown operator $1");
6702 $UnknownOperator{$1} = 1;
6703 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006704 }
6705 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006706 }
6707 else
6708 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006709 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6710 return getTreeStr($1);
6711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006712 }
6713 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006714 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006715}
6716
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006717sub getFuncReturn($)
6718{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006719 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6720 {
6721 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6722 {
6723 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6724 return $1;
6725 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006726 }
6727 }
6728 return "";
6729}
6730
6731sub getFuncOrig($)
6732{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006733 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6734 {
6735 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6736 return $1;
6737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006738 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006739 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740}
6741
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006742sub unmangleArray(@)
6743{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006744 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006745 { # MSVC mangling
6746 my $UndNameCmd = get_CmdPath("undname");
6747 if(not $UndNameCmd) {
6748 exitStatus("Not_Found", "can't find \"undname\"");
6749 }
6750 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006751 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006752 }
6753 else
6754 { # GCC mangling
6755 my $CppFiltCmd = get_CmdPath("c++filt");
6756 if(not $CppFiltCmd) {
6757 exitStatus("Not_Found", "can't find c++filt in PATH");
6758 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006759 if(not defined $CPPFILT_SUPPORT_FILE)
6760 {
6761 my $Info = `$CppFiltCmd -h 2>&1`;
6762 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6763 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006764 my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":"";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006765 if($CPPFILT_SUPPORT_FILE)
6766 { # new versions of c++filt can take a file
6767 if($#_>$MAX_CPPFILT_FILE_SIZE)
6768 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6769 # this is fixed in the oncoming version of Binutils
6770 my @Half = splice(@_, 0, ($#_+1)/2);
6771 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006772 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006773 else
6774 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006775 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6776 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6777 if($?==139)
6778 { # segmentation fault
6779 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6780 }
6781 return split(/\n/, $Res);
6782 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006783 }
6784 else
6785 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006786 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6787 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006788 my @Half = splice(@_, 0, ($#_+1)/2);
6789 return (unmangleArray(@Half), unmangleArray(@_))
6790 }
6791 else
6792 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006793 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006794 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6795 if($?==139)
6796 { # segmentation fault
6797 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6798 }
6799 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006800 }
6801 }
6802 }
6803}
6804
6805sub get_SignatureNoInfo($$)
6806{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006807 my ($Symbol, $LibVersion) = @_;
6808 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6809 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006810 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006811 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006812 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006813 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006814 { # C++
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04006815 # some standard typedefs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006816 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6817 $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;
6818 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006819 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006820 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006821 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006822 $Signature .= " [data]";
6823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006825 $Signature .= " (...)";
6826 }
6827 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006828 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006829 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006830 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006831 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6832 }
6833 if($SymbolVersion) {
6834 $Signature .= $VersionSpec.$SymbolVersion;
6835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006837}
6838
6839sub get_ChargeLevel($$)
6840{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006841 my ($Symbol, $LibVersion) = @_;
6842 return "" if($Symbol!~/\A(_Z|\?)/);
6843 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6844 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006845 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006846 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006847 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006848 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006849 return "[in-charge]";
6850 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006851 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006852 return "[not-in-charge]";
6853 }
6854 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006855 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006856 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006857 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006858 return "[in-charge]";
6859 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006860 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006861 return "[not-in-charge]";
6862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006863 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 return "[in-charge-deleting]";
6865 }
6866 }
6867 }
6868 else
6869 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006871 return "[in-charge]";
6872 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006873 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006874 return "[not-in-charge]";
6875 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006877 return "[in-charge]";
6878 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006879 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006880 return "[not-in-charge]";
6881 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006882 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 return "[in-charge-deleting]";
6884 }
6885 }
6886 return "";
6887}
6888
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006889sub get_Signature_M($$)
6890{
6891 my ($Symbol, $LibVersion) = @_;
6892 my $Signature_M = $tr_name{$Symbol};
6893 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6894 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006895 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006896 }
6897 return $Signature_M;
6898}
6899
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006900sub get_Signature($$)
6901{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006902 my ($Symbol, $LibVersion) = @_;
6903 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6904 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006905 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006906 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6907 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006908 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006909 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 }
6911 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006912 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6913 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006914 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006915 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6916 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006917 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006918 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006919 $Func_Signature = $NameSpace."::".$ShortName;
6920 }
6921 else {
6922 $Func_Signature = $ShortName;
6923 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006924 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6925 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006926 }
6927 else {
6928 $Func_Signature = $MnglName;
6929 }
6930 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006931 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006932 {
6933 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006934 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006935 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006936 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006937 if(not $ParamTypeName) {
6938 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6939 }
6940 foreach my $Typedef (keys(%ChangedTypedef))
6941 {
6942 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006943 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006944 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006945 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006946 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6947 }
6948 else {
6949 push(@ParamArray, $ParamTypeName);
6950 }
6951 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006952 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6953 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006954 $Func_Signature .= " [data]";
6955 }
6956 else
6957 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006958 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006959 { # add [in-charge]
6960 $Func_Signature .= " ".$ChargeLevel;
6961 }
6962 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006963 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6964 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006965 $Func_Signature .= " const";
6966 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006967 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6968 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006969 $Func_Signature .= " volatile";
6970 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006971 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6972 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006973 {# for static methods
6974 $Func_Signature .= " [static]";
6975 }
6976 }
6977 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006978 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6979 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006980 }
6981 if($SymbolVersion) {
6982 $Func_Signature .= $VersionSpec.$SymbolVersion;
6983 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006984 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006985}
6986
6987sub create_member_decl($$)
6988{
6989 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006990 if($TName=~/\([\*]+\)/)
6991 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006992 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6993 return $TName;
6994 }
6995 else
6996 {
6997 my @ArraySizes = ();
6998 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6999 push(@ArraySizes, $1);
7000 }
7001 return $TName." ".$Member.join("", @ArraySizes);
7002 }
7003}
7004
7005sub getFuncType($)
7006{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007007 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7008 {
7009 if($Info=~/type[ ]*:[ ]*@(\d+) /)
7010 {
7011 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
7012 {
7013 if($Type eq "method_type") {
7014 return "Method";
7015 }
7016 elsif($Type eq "function_type") {
7017 return "Function";
7018 }
7019 else {
7020 return "Other";
7021 }
7022 }
7023 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007024 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007025 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007026}
7027
7028sub getFuncTypeId($)
7029{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007030 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7031 {
7032 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
7033 return $1;
7034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007035 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007036 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007037}
7038
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007039sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007040{ # "._N" or "$_N" in older GCC versions
7041 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007042}
7043
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007044sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007045{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007046 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
7047 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007048 }
7049
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007050 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007051
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007052 if($_[1] ne "S")
7053 {
7054 $N=~s/\A[ ]+//g;
7055 $N=~s/[ ]+\Z//g;
7056 $N=~s/[ ]{2,}/ /g;
7057 }
7058
7059 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007060
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007061 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007062
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007063 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7064 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007065
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007066 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007067
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007068 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007069
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007070 if($_[1] eq "S")
7071 {
7072 if(index($N, "operator")!=-1) {
7073 $N=~s/\b(operator[ ]*)> >/$1>>/;
7074 }
7075 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007076
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007077 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007078}
7079
7080sub get_HeaderDeps($$)
7081{
7082 my ($AbsPath, $LibVersion) = @_;
7083 return () if(not $AbsPath or not $LibVersion);
7084 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7085 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7086 }
7087 my %IncDir = ();
7088 detect_recursive_includes($AbsPath, $LibVersion);
7089 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7090 {
7091 next if(not $HeaderPath);
7092 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7093 my $Dir = get_dirname($HeaderPath);
7094 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7095 {
7096 my $Dep = $Dir;
7097 if($Prefix)
7098 {
7099 if($OSgroup eq "windows")
7100 { # case insensitive seach on windows
7101 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7102 next;
7103 }
7104 }
7105 elsif($OSgroup eq "macos")
7106 { # seach in frameworks
7107 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7108 {
7109 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7110 {# frameworks
7111 my ($HFramework, $HName) = ($1, $2);
7112 $Dep = $HFramework;
7113 }
7114 else
7115 {# mismatch
7116 next;
7117 }
7118 }
7119 }
7120 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7121 { # Linux, FreeBSD
7122 next;
7123 }
7124 }
7125 if(not $Dep)
7126 { # nothing to include
7127 next;
7128 }
7129 if(is_default_include_dir($Dep))
7130 { # included by the compiler
7131 next;
7132 }
7133 if(get_depth($Dep)==1)
7134 { # too short
7135 next;
7136 }
7137 if(isLibcDir($Dep))
7138 { # do NOT include /usr/include/{sys,bits}
7139 next;
7140 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007141 $IncDir{$Dep} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007142 }
7143 }
7144 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7145 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7146}
7147
7148sub sortIncPaths($$)
7149{
7150 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007151 if(not $ArrRef or $#{$ArrRef}<0) {
7152 return $ArrRef;
7153 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007154 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7155 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007156 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007157 return $ArrRef;
7158}
7159
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007160sub sortDeps($$$)
7161{
7162 if($Header_Dependency{$_[2]}{$_[0]}
7163 and not $Header_Dependency{$_[2]}{$_[1]}) {
7164 return 1;
7165 }
7166 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7167 and $Header_Dependency{$_[2]}{$_[1]}) {
7168 return -1;
7169 }
7170 return 0;
7171}
7172
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007173sub joinPath($$) {
7174 return join($SLASH, @_);
7175}
7176
7177sub get_namespace_additions($)
7178{
7179 my $NameSpaces = $_[0];
7180 my ($Additions, $AddNameSpaceId) = ("", 1);
7181 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7182 {
7183 next if($SkipNameSpaces{$Version}{$NS});
7184 next if(not $NS or $NameSpaces->{$NS}==-1);
7185 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7186 next if($NS=~/\A__/i);
7187 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007188 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007189 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7190 my @NS_Parts = split(/::/, $NS);
7191 next if($#NS_Parts==-1);
7192 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7193 foreach my $NS_Part (@NS_Parts)
7194 {
7195 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7196 $TypeDecl_Suffix .= "}";
7197 }
7198 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7199 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7200 $Additions.=" $TypeDecl\n $FuncDecl\n";
7201 $AddNameSpaceId+=1;
7202 }
7203 return $Additions;
7204}
7205
7206sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007207{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007208 my ($Path, $Fmt) = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007209 $Path=~s/[\/\\]+\Z//;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007210 if($Fmt eq "windows")
7211 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007212 $Path=~s/\//\\/g;
7213 $Path=lc($Path);
7214 }
7215 else {
7216 $Path=~s/\\/\//g;
7217 }
7218 return $Path;
7219}
7220
7221sub inc_opt($$)
7222{
7223 my ($Path, $Style) = @_;
7224 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007225 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007226 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007227 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007228 return "-I\"".path_format($Path, "unix")."\"";
7229 }
7230 elsif($OSgroup eq "macos"
7231 and $Path=~/\.framework\Z/)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007232 { # to Apple's GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007233 return "-F".esc(get_dirname($Path));
7234 }
7235 else {
7236 return "-I".esc($Path);
7237 }
7238 }
7239 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007240 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007241 }
7242 return "";
7243}
7244
7245sub platformSpecs($)
7246{
7247 my $LibVersion = $_[0];
7248 my $Arch = getArch($LibVersion);
7249 if($OStarget eq "symbian")
7250 { # options for GCCE compiler
7251 my %Symbian_Opts = map {$_=>1} (
7252 "-D__GCCE__",
7253 "-DUNICODE",
7254 "-fexceptions",
7255 "-D__SYMBIAN32__",
7256 "-D__MARM_INTERWORK__",
7257 "-D_UNICODE",
7258 "-D__S60_50__",
7259 "-D__S60_3X__",
7260 "-D__SERIES60_3X__",
7261 "-D__EPOC32__",
7262 "-D__MARM__",
7263 "-D__EABI__",
7264 "-D__MARM_ARMV5__",
7265 "-D__SUPPORT_CPP_EXCEPTIONS__",
7266 "-march=armv5t",
7267 "-mapcs",
7268 "-mthumb-interwork",
7269 "-DEKA2",
7270 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7271 );
7272 return join(" ", keys(%Symbian_Opts));
7273 }
7274 elsif($OSgroup eq "windows"
7275 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7276 { # add options to MinGW compiler
7277 # to simulate the MSVC compiler
7278 my %MinGW_Opts = map {$_=>1} (
7279 "-D_WIN32",
7280 "-D_STDCALL_SUPPORTED",
7281 "-D__int64=\"long long\"",
7282 "-D__int32=int",
7283 "-D__int16=short",
7284 "-D__int8=char",
7285 "-D__possibly_notnullterminated=\" \"",
7286 "-D__nullterminated=\" \"",
7287 "-D__nullnullterminated=\" \"",
7288 "-D__w64=\" \"",
7289 "-D__ptr32=\" \"",
7290 "-D__ptr64=\" \"",
7291 "-D__forceinline=inline",
7292 "-D__inline=inline",
7293 "-D__uuidof(x)=IID()",
7294 "-D__try=",
7295 "-D__except(x)=",
7296 "-D__declspec(x)=__attribute__((x))",
7297 "-D__pragma(x)=",
7298 "-D_inline=inline",
7299 "-D__forceinline=__inline",
7300 "-D__stdcall=__attribute__((__stdcall__))",
7301 "-D__cdecl=__attribute__((__cdecl__))",
7302 "-D__fastcall=__attribute__((__fastcall__))",
7303 "-D__thiscall=__attribute__((__thiscall__))",
7304 "-D_stdcall=__attribute__((__stdcall__))",
7305 "-D_cdecl=__attribute__((__cdecl__))",
7306 "-D_fastcall=__attribute__((__fastcall__))",
7307 "-D_thiscall=__attribute__((__thiscall__))",
7308 "-DSHSTDAPI_(x)=x",
7309 "-D_MSC_EXTENSIONS",
7310 "-DSECURITY_WIN32",
7311 "-D_MSC_VER=1500",
7312 "-D_USE_DECLSPECS_FOR_SAL",
7313 "-D__noop=\" \"",
7314 "-DDECLSPEC_DEPRECATED=\" \"",
7315 "-D__builtin_alignof(x)=__alignof__(x)",
7316 "-DSORTPP_PASS");
7317 if($Arch eq "x86") {
7318 $MinGW_Opts{"-D_M_IX86=300"}=1;
7319 }
7320 elsif($Arch eq "x86_64") {
7321 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7322 }
7323 elsif($Arch eq "ia64") {
7324 $MinGW_Opts{"-D_M_IA64=300"}=1;
7325 }
7326 return join(" ", keys(%MinGW_Opts));
7327 }
7328 return "";
7329}
7330
7331my %C_Structure = map {$_=>1} (
7332# FIXME: Can't separate union and struct data types before dumping,
7333# so it sometimes cause compilation errors for unknown reason
7334# when trying to declare TYPE* tmp_add_class_N
7335# This is a list of such structures + list of other C structures
7336 "sigval",
7337 "sigevent",
7338 "sigaction",
7339 "sigvec",
7340 "sigstack",
7341 "timeval",
7342 "timezone",
7343 "rusage",
7344 "rlimit",
7345 "wait",
7346 "flock",
7347 "stat",
7348 "_stat",
7349 "stat32",
7350 "_stat32",
7351 "stat64",
7352 "_stat64",
7353 "_stati64",
7354 "if_nameindex",
7355 "usb_device",
7356 "sigaltstack",
7357 "sysinfo",
7358 "timeLocale",
7359 "tcp_debug",
7360 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007361 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007362 "timespec",
7363 "random_data",
7364 "drand48_data",
7365 "_IO_marker",
7366 "_IO_FILE",
7367 "lconv",
7368 "sched_param",
7369 "tm",
7370 "itimerspec",
7371 "_pthread_cleanup_buffer",
7372 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007373 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007374 "mallinfo",
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007375 "timex",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007376 # Mac
7377 "_timex",
7378 "_class_t",
7379 "_category_t",
7380 "_class_ro_t",
7381 "_protocol_t",
7382 "_message_ref_t",
7383 "_super_message_ref_t",
7384 "_ivar_t",
7385 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007386);
7387
7388sub getCompileCmd($$$)
7389{
7390 my ($Path, $Opt, $Inc) = @_;
7391 my $GccCall = $GCC_PATH;
7392 if($Opt) {
7393 $GccCall .= " ".$Opt;
7394 }
7395 $GccCall .= " -x ";
7396 if($OSgroup eq "macos") {
7397 $GccCall .= "objective-";
7398 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007399 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007400 { # compile as "C++" header
7401 # to obtain complete dump using GCC 4.0
7402 $GccCall .= "c++-header";
7403 }
7404 else
7405 { # compile as "C++" source
7406 # GCC 3.3 cannot compile headers
7407 $GccCall .= "c++";
7408 }
7409 if(my $Opts = platformSpecs($Version))
7410 {# platform-specific options
7411 $GccCall .= " ".$Opts;
7412 }
7413 # allow extra qualifications
7414 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007415 $GccCall .= " -fpermissive";
7416 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007417 if($NoStdInc)
7418 {
7419 $GccCall .= " -nostdinc";
7420 $GccCall .= " -nostdinc++";
7421 }
7422 if($CompilerOptions{$Version})
7423 { # user-defined options
7424 $GccCall .= " ".$CompilerOptions{$Version};
7425 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007426 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007427 if($Inc)
7428 { # include paths
7429 $GccCall .= " ".$Inc;
7430 }
7431 return $GccCall;
7432}
7433
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007434sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007435{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007436 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007437 my %HeaderElems = (
7438 # Types
7439 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007440 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007441 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7442 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007443 "time.h" => ["time_t"],
7444 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007445 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7446 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007447 "stdbool.h" => ["_Bool"],
7448 "rpc/xdr.h" => ["bool_t"],
7449 "in_systm.h" => ["n_long", "n_short"],
7450 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007451 "arpa/inet.h" => ["fw_src", "ip_src"],
7452 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007453 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007454 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007455 );
7456 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007457 foreach (keys(%HeaderElems))
7458 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007459 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007460 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007461 }
7462 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007463 my %Types = ();
7464 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7465 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007466 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007467 }
7468 if(keys(%Types))
7469 {
7470 my %AddHeaders = ();
7471 foreach my $Type (keys(%Types))
7472 {
7473 if(my $Header = $AutoPreamble{$Type})
7474 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007475 if(my $Path = identifyHeader($Header, $LibVersion))
7476 {
7477 if(skipHeader($Path, $LibVersion)) {
7478 next;
7479 }
7480 $Path = path_format($Path, $OSgroup);
7481 $AddHeaders{$Path}{"Type"} = $Type;
7482 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007483 }
7484 }
7485 }
7486 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007487 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007488 }
7489 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007490 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007491}
7492
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007493sub checkCTags($)
7494{
7495 my $Path = $_[0];
7496 if(not $Path) {
7497 return;
7498 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007499 my $CTags = undef;
7500
7501 if($OSgroup eq "bsd")
7502 { # use ectags on BSD
7503 $CTags = get_CmdPath("ectags");
7504 if(not $CTags) {
7505 printMsg("WARNING", "can't find \'ectags\' program");
7506 }
7507 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007508 if(not $CTags) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007509 $CTags = get_CmdPath("ctags");
7510 }
7511 if(not $CTags)
7512 {
7513 printMsg("WARNING", "can't find \'ctags\' program");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007514 return;
7515 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007516
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007517 if($OSgroup ne "linux")
7518 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007519 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7520 if($Info!~/exuberant/i)
7521 {
7522 printMsg("WARNING", "incompatible version of \'ctags\' program");
7523 return;
7524 }
7525 }
7526
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007527 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007528 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007529 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007530 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007531 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007532 open(CTAGS, "<", $Out);
7533 while(my $Line = <CTAGS>)
7534 {
7535 chomp($Line);
7536 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007537 if(defined $Intrinsic_Keywords{$Name})
7538 { # noise
7539 next;
7540 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007541 if($Type eq "n")
7542 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007543 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007544 next;
7545 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007546 if(index($Scpe, "struct:")==0) {
7547 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007548 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007549 if(index($Scpe, "namespace:")==0)
7550 {
7551 if($Scpe=~s/\Anamespace://) {
7552 $Name = $Scpe."::".$Name;
7553 }
7554 }
7555 $TUnit_NameSpaces{$Version}{$Name} = 1;
7556 }
7557 elsif($Type eq "p")
7558 {
7559 if(not $Scpe or index($Scpe, "namespace:")==0) {
7560 $TUnit_Funcs{$Version}{$Name} = 1;
7561 }
7562 }
7563 elsif($Type eq "x")
7564 {
7565 if(not $Scpe or index($Scpe, "namespace:")==0) {
7566 $TUnit_Vars{$Version}{$Name} = 1;
7567 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007568 }
7569 }
7570 close(CTAGS);
7571}
7572
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007573sub getDump()
7574{
7575 if(not $GCC_PATH) {
7576 exitStatus("Error", "internal error - GCC path is not set");
7577 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007578 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007579 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007580 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007581 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7582 {
7583 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007584 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007585 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007586 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007587 foreach my $HPath (@{$Include_Preamble{$Version}}) {
7588 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007589 }
7590 my @Headers = keys(%{$Registered_Headers{$Version}});
7591 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007592 foreach my $HPath (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007593 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007594 if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
7595 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n";
7596 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007597 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007598 close(TMP_HEADER);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007599 my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007600
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007601 if($ExtraInfo)
7602 { # extra information for other tools
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007603 if($IncludeString) {
7604 writeFile($ExtraInfo."/include-string", $IncludeString);
7605 }
7606 writeFile($ExtraInfo."/includes", Dumper($RecursiveIncludes{$Version}));
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007607 }
7608
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007609 if(not keys(%{$TargetHeaders{$Version}}))
7610 { # Target headers
7611 addTargetHeaders($Version);
7612 }
7613
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007614 if($Debug)
7615 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007616 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7617 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7618 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007619 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\@DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007620 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007621
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007622 # clean memory
7623 %RecursiveIncludes = ();
7624 %Header_Include_Prefix = ();
7625 %Header_Includes = ();
7626
7627 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007628 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007629 delete($Cache{"detect_header_includes"});
7630 delete($Cache{"selectSystemHeader"});
7631
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007632 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007633 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7634 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007635
7636 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007637 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007638
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007639 if($COMMON_LANGUAGE{$Version} eq "C++") {
7640 checkCTags($Pre);
7641 }
7642
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007643 my $MContent = "";
7644 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7645 if($OStarget eq "windows"
7646 and get_dumpmachine($GCC_PATH)=~/mingw/i
7647 and $MinGWMode{$Version}!=-1)
7648 { # modify headers to compile by MinGW
7649 if(not $MContent)
7650 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007651 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007652 }
7653 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7654 { # __asm { ... }
7655 $MinGWMode{$Version}=1;
7656 }
7657 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7658 { # comments after preprocessing
7659 $MinGWMode{$Version}=1;
7660 }
7661 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7662 { # 0xffui8
7663 $MinGWMode{$Version}=1;
7664 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007665 if($MinGWMode{$Version})
7666 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007667 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007668 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007669 }
7670 }
7671 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007672 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007673 { # rename C++ keywords in C code
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007674 # disable this code by -cpp-compatible option
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007675 if(not $MContent)
7676 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007677 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007678 }
7679 my $RegExp_C = join("|", keys(%CppKeywords_C));
7680 my $RegExp_F = join("|", keys(%CppKeywords_F));
7681 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007682
7683 my $Detected = undef;
7684
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007685 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7686 { # MATCH:
7687 # int foo(int new, int class, int (*new)(int));
7688 # unsigned private: 8;
7689 # DO NOT MATCH:
7690 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007691 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007692 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007693 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007694 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 { # MATCH:
7696 # int delete(...);
7697 # int explicit(...);
7698 # DO NOT MATCH:
7699 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007700 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007701 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007702 }
7703 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7704 { # MATCH:
7705 # int bool;
7706 # DO NOT MATCH:
7707 # bool X;
7708 # return *this;
7709 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007710 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007711 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007712 }
7713 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7714 { # MATCH:
7715 # int operator(...);
7716 # DO NOT MATCH:
7717 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007718 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007719 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007720 }
7721 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7722 { # MATCH:
7723 # int foo(int operator);
7724 # int foo(int operator, int other);
7725 # DO NOT MATCH:
7726 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007727 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007728 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007729 }
7730 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7731 { # MATCH:
7732 # int foo(gboolean *bool);
7733 # DO NOT MATCH:
7734 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007735 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007736 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007737 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007738 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007739 { # MATCH:
7740 # int foo(int* this);
7741 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007742 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007743 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007744 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007745 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007746 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007747 }
7748
7749 if($CppMode{$Version} == 1)
7750 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007751 if($Debug)
7752 {
7753 $Detected=~s/\A\s+//g;
7754 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007755 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007756 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007757
7758 # remove typedef enum NAME NAME;
7759 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7760 my $N = 0;
7761 while($N<=$#FwdTypedefs-1)
7762 {
7763 my $S = $FwdTypedefs[$N];
7764 if($S eq $FwdTypedefs[$N+1])
7765 {
7766 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007767 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007768 }
7769 $N+=2;
7770 }
7771
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007772 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007773 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007774 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007775 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007776 }
7777 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007778 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007779 or $MinGWMode{$Version}==1)
7780 { # compile the corrected preprocessor output
7781 writeFile($MHeaderPath, $MContent);
7782 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007783
7784 # clean memory
7785 undef $MContent;
7786
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007787 if($COMMON_LANGUAGE{$Version} eq "C++")
7788 { # add classes and namespaces to the dump
7789 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007790 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007791 or $MinGWMode{$Version}==1) {
7792 $CHdump .= " -fpreprocessed";
7793 }
7794 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7795 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007796 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007797 chdir($ORIG_DIR);
7798 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7799 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007800 my $Content = readFile($ClassDump);
7801 foreach my $ClassInfo (split(/\n\n/, $Content))
7802 {
7803 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7804 {
7805 my $CName = $1;
7806 next if($CName=~/\A(__|_objc_|_opaque_)/);
7807 $TUnit_NameSpaces{$Version}{$CName} = -1;
7808 if($CName=~/\A[\w:]+\Z/)
7809 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007810 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007811 }
7812 if($CName=~/(\w[\w:]*)::/)
7813 { # namespaces
7814 my $NS = $1;
7815 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7816 $TUnit_NameSpaces{$Version}{$NS} = 1;
7817 }
7818 }
7819 }
7820 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7821 { # read v-tables (advanced approach)
7822 my ($CName, $VTable) = ($1, $2);
7823 $ClassVTable_Content{$Version}{$CName} = $VTable;
7824 }
7825 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007826 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7827 { # add user-defined namespaces
7828 $TUnit_NameSpaces{$Version}{$NS} = 1;
7829 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007830 if($Debug)
7831 { # debug mode
7832 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007833 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007834 }
7835 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007836 }
7837
7838 # add namespaces and classes
7839 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7840 { # GCC on all supported platforms does not include namespaces to the dump by default
7841 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7842 }
7843 # some GCC versions don't include class methods to the TU dump by default
7844 my ($AddClass, $ClassNum) = ("", 0);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007845 my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007846 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7847 {
7848 next if($C_Structure{$CName});
7849 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007850 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007851 if(not $Force and $GCC_44
7852 and $OSgroup eq "linux")
7853 { # optimization for linux with GCC >= 4.4
7854 # disable this code by -force option
7855 if(index($CName, "::")!=-1)
7856 { # should be added by name space
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007857 next;
7858 }
7859 }
7860 else
7861 {
7862 if($CName=~/\A(.+)::[^:]+\Z/
7863 and $TUnit_Classes{$Version}{$1})
7864 { # classes inside other classes
7865 next;
7866 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007867 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007868 if(defined $TUnit_Funcs{$Version}{$CName})
7869 { # the same name for a function and type
7870 next;
7871 }
7872 if(defined $TUnit_Vars{$Version}{$CName})
7873 { # the same name for a variable and type
7874 next;
7875 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007876 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7877 }
7878 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007879 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7880 }
7881 }
7882 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7883 # create TU dump
7884 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007885 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007886 or $MinGWMode{$Version}==1) {
7887 $TUdump .= " -fpreprocessed";
7888 }
7889 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7890 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7891 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007892 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007893 my $Errors = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007894 if($?)
7895 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007896 if($Errors = readFile($TMP_DIR."/tu_errors"))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007897 { # try to recompile
7898 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007899 if($CppMode{$Version}==1
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007900 and index($Errors, "c99_")!=-1)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007901 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007902 $CppMode{$Version}=-1;
7903 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007904 resetLogging($Version);
7905 $TMP_DIR = tempdir(CLEANUP=>1);
7906 return getDump();
7907 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007908 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007909 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007910 { # add auto preamble headers and try again
7911 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007912 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007913 foreach my $Num (0 .. $#Headers)
7914 {
7915 my $Path = $Headers[$Num];
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007916 if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}}))
7917 {
7918 push_U($Include_Preamble{$Version}, $Path);
7919 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007920 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007921 }
7922 resetLogging($Version);
7923 $TMP_DIR = tempdir(CLEANUP=>1);
7924 return getDump();
7925 }
7926 elsif($Cpp0xMode{$Version}!=-1
7927 and ($Errors=~/\Q-std=c++0x\E/
7928 or $Errors=~/is not a class or namespace/))
7929 { # c++0x: enum class
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007930 if(check_gcc($GCC_PATH, "4.6"))
7931 {
7932 $Cpp0xMode{$Version}=-1;
7933 printMsg("INFO", "Enabling c++0x mode");
7934 resetLogging($Version);
7935 $TMP_DIR = tempdir(CLEANUP=>1);
7936 $CompilerOptions{$Version} .= " -std=c++0x";
7937 return getDump();
7938 }
7939 else {
7940 printMsg("WARNING", "Probably c++0x construction detected");
7941 }
7942
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007943 }
7944 elsif($MinGWMode{$Version}==1)
7945 { # disable MinGW mode and try again
7946 $MinGWMode{$Version}=-1;
7947 resetLogging($Version);
7948 $TMP_DIR = tempdir(CLEANUP=>1);
7949 return getDump();
7950 }
7951 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007952 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007953 else {
7954 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007956 printMsg("ERROR", "some errors occurred when compiling headers");
7957 printErrorLog($Version);
7958 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007959 writeLog($Version, "\n"); # new line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007960 }
7961 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007962 unlink($TmpHeaderPath);
7963 unlink($MHeaderPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007964
7965 if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
7966 return $TUs[0];
7967 }
7968 else
7969 {
7970 my $Msg = "can't compile header(s)";
7971 if($Errors=~/error trying to exec \W+cc1plus\W+/) {
7972 $Msg .= "\nDid you install G++?";
7973 }
7974 exitStatus("Cannot_Compile", $Msg);
7975 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007976}
7977
7978sub cmd_file($)
7979{
7980 my $Path = $_[0];
7981 return "" if(not $Path or not -e $Path);
7982 if(my $CmdPath = get_CmdPath("file")) {
7983 return `$CmdPath -b \"$Path\"`;
7984 }
7985 return "";
7986}
7987
7988sub getIncString($$)
7989{
7990 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007991 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007992 my $String = "";
7993 foreach (@{$ArrRef}) {
7994 $String .= " ".inc_opt($_, $Style);
7995 }
7996 return $String;
7997}
7998
7999sub getIncPaths(@)
8000{
8001 my @HeaderPaths = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008002 my @IncPaths = @{$Add_Include_Paths{$Version}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008003 if($INC_PATH_AUTODETECT{$Version})
8004 { # auto-detecting dependencies
8005 my %Includes = ();
8006 foreach my $HPath (@HeaderPaths)
8007 {
8008 foreach my $Dir (get_HeaderDeps($HPath, $Version))
8009 {
8010 if($Skip_Include_Paths{$Version}{$Dir}) {
8011 next;
8012 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008013 if($SystemRoot)
8014 {
8015 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
8016 next;
8017 }
8018 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008019 $Includes{$Dir} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008020 }
8021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008022 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008023 push_U(\@IncPaths, $Dir);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008024 }
8025 }
8026 else
8027 { # user-defined paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008028 @IncPaths = @{$Include_Paths{$Version}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008029 }
8030 return \@IncPaths;
8031}
8032
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008033sub push_U($@)
8034{ # push unique
8035 if(my $Array = shift @_)
8036 {
8037 if(@_)
8038 {
8039 my %Exist = map {$_=>1} @{$Array};
8040 foreach my $Elem (@_)
8041 {
8042 if(not defined $Exist{$Elem})
8043 {
8044 push(@{$Array}, $Elem);
8045 $Exist{$Elem} = 1;
8046 }
8047 }
8048 }
8049 }
8050}
8051
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008052sub callPreprocessor($$$)
8053{
8054 my ($Path, $Inc, $LibVersion) = @_;
8055 return "" if(not $Path or not -f $Path);
8056 my $IncludeString=$Inc;
8057 if(not $Inc) {
8058 $IncludeString = getIncString(getIncPaths($Path), "GCC");
8059 }
8060 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008061 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008062 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008063 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008064}
8065
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008066sub cmd_find(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008067{ # native "find" is much faster than File::Find (~6x)
8068 # also the File::Find doesn't support --maxdepth N option
8069 # so using the cross-platform wrapper for the native one
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008070 my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008071 return () if(not $Path or not -e $Path);
8072 if($OSgroup eq "windows")
8073 {
8074 my $DirCmd = get_CmdPath("dir");
8075 if(not $DirCmd) {
8076 exitStatus("Not_Found", "can't find \"dir\" command");
8077 }
8078 $Path=~s/[\\]+\Z//;
8079 $Path = get_abs_path($Path);
8080 $Path = path_format($Path, $OSgroup);
8081 my $Cmd = $DirCmd." \"$Path\" /B /O";
8082 if($MaxDepth!=1) {
8083 $Cmd .= " /S";
8084 }
8085 if($Type eq "d") {
8086 $Cmd .= " /AD";
8087 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008088 my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008089 if($Name)
8090 { # FIXME: how to search file names in MS shell?
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008091 if(not $UseRegex) {
8092 $Name=~s/\*/.*/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008093 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008094 @Files = grep { /\A$Name\Z/i } @Files;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008095 }
8096 my @AbsPaths = ();
8097 foreach my $File (@Files)
8098 {
8099 if(not is_abs($File)) {
8100 $File = joinPath($Path, $File);
8101 }
8102 if($Type eq "f" and not -f $File)
8103 { # skip dirs
8104 next;
8105 }
8106 push(@AbsPaths, path_format($File, $OSgroup));
8107 }
8108 if($Type eq "d") {
8109 push(@AbsPaths, $Path);
8110 }
8111 return @AbsPaths;
8112 }
8113 else
8114 {
8115 my $FindCmd = get_CmdPath("find");
8116 if(not $FindCmd) {
8117 exitStatus("Not_Found", "can't find a \"find\" command");
8118 }
8119 $Path = get_abs_path($Path);
8120 if(-d $Path and -l $Path
8121 and $Path!~/\/\Z/)
8122 { # for directories that are symlinks
8123 $Path.="/";
8124 }
8125 my $Cmd = $FindCmd." \"$Path\"";
8126 if($MaxDepth) {
8127 $Cmd .= " -maxdepth $MaxDepth";
8128 }
8129 if($Type) {
8130 $Cmd .= " -type $Type";
8131 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008132 if($Name and not $UseRegex)
8133 { # wildcards
8134 $Cmd .= " -name \"$Name\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008135 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008136 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8137 if($?) {
8138 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8139 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008140 my @Files = split(/\n/, $Res);
8141 if($Name and $UseRegex)
8142 { # regex
8143 @Files = grep { /\A$Name\Z/ } @Files;
8144 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008145 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008146 }
8147}
8148
8149sub unpackDump($)
8150{
8151 my $Path = $_[0];
8152 return "" if(not $Path or not -e $Path);
8153 $Path = get_abs_path($Path);
8154 $Path = path_format($Path, $OSgroup);
8155 my ($Dir, $FileName) = separate_path($Path);
8156 my $UnpackDir = $TMP_DIR."/unpack";
8157 rmtree($UnpackDir);
8158 mkpath($UnpackDir);
8159 if($FileName=~s/\Q.zip\E\Z//g)
8160 { # *.zip
8161 my $UnzipCmd = get_CmdPath("unzip");
8162 if(not $UnzipCmd) {
8163 exitStatus("Not_Found", "can't find \"unzip\" command");
8164 }
8165 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008166 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008167 if($?) {
8168 exitStatus("Error", "can't extract \'$Path\'");
8169 }
8170 chdir($ORIG_DIR);
8171 my @Contents = ();
8172 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8173 {
8174 if(/inflating:\s*([^\s]+)/) {
8175 push(@Contents, $1);
8176 }
8177 }
8178 if(not @Contents) {
8179 exitStatus("Error", "can't extract \'$Path\'");
8180 }
8181 return joinPath($UnpackDir, $Contents[0]);
8182 }
8183 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8184 { # *.tar.gz
8185 if($OSgroup eq "windows")
8186 { # -xvzf option is not implemented in tar.exe (2003)
8187 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8188 my $TarCmd = get_CmdPath("tar");
8189 if(not $TarCmd) {
8190 exitStatus("Not_Found", "can't find \"tar\" command");
8191 }
8192 my $GzipCmd = get_CmdPath("gzip");
8193 if(not $GzipCmd) {
8194 exitStatus("Not_Found", "can't find \"gzip\" command");
8195 }
8196 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008197 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008198 if($?) {
8199 exitStatus("Error", "can't extract \'$Path\'");
8200 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008201 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008202 if($?) {
8203 exitStatus("Error", "can't extract \'$Path\'");
8204 }
8205 chdir($ORIG_DIR);
8206 unlink($Dir."/".$FileName.".tar");
8207 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8208 if(not @Contents) {
8209 exitStatus("Error", "can't extract \'$Path\'");
8210 }
8211 return joinPath($UnpackDir, $Contents[0]);
8212 }
8213 else
8214 { # Unix
8215 my $TarCmd = get_CmdPath("tar");
8216 if(not $TarCmd) {
8217 exitStatus("Not_Found", "can't find \"tar\" command");
8218 }
8219 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008220 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008221 if($?) {
8222 exitStatus("Error", "can't extract \'$Path\'");
8223 }
8224 chdir($ORIG_DIR);
8225 # The content file name may be different
8226 # from the package file name
8227 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8228 if(not @Contents) {
8229 exitStatus("Error", "can't extract \'$Path\'");
8230 }
8231 return joinPath($UnpackDir, $Contents[0]);
8232 }
8233 }
8234}
8235
8236sub createArchive($$)
8237{
8238 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008239 if(not $To) {
8240 $To = ".";
8241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008242 if(not $Path or not -e $Path
8243 or not -d $To) {
8244 return "";
8245 }
8246 my ($From, $Name) = separate_path($Path);
8247 if($OSgroup eq "windows")
8248 { # *.zip
8249 my $ZipCmd = get_CmdPath("zip");
8250 if(not $ZipCmd) {
8251 exitStatus("Not_Found", "can't find \"zip\"");
8252 }
8253 my $Pkg = $To."/".$Name.".zip";
8254 unlink($Pkg);
8255 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008256 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008257 if($?)
8258 { # cannot allocate memory (or other problems with "zip")
8259 unlink($Path);
8260 exitStatus("Error", "can't pack the ABI dump: ".$!);
8261 }
8262 chdir($ORIG_DIR);
8263 unlink($Path);
8264 return $Pkg;
8265 }
8266 else
8267 { # *.tar.gz
8268 my $TarCmd = get_CmdPath("tar");
8269 if(not $TarCmd) {
8270 exitStatus("Not_Found", "can't find \"tar\"");
8271 }
8272 my $GzipCmd = get_CmdPath("gzip");
8273 if(not $GzipCmd) {
8274 exitStatus("Not_Found", "can't find \"gzip\"");
8275 }
8276 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8277 unlink($Pkg);
8278 chdir($From);
8279 system($TarCmd, "-czf", $Pkg, $Name);
8280 if($?)
8281 { # cannot allocate memory (or other problems with "tar")
8282 unlink($Path);
8283 exitStatus("Error", "can't pack the ABI dump: ".$!);
8284 }
8285 chdir($ORIG_DIR);
8286 unlink($Path);
8287 return $To."/".$Name.".tar.gz";
8288 }
8289}
8290
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008291sub readBytes($)
8292{
8293 sysopen(FILE, $_[0], O_RDONLY);
8294 sysread(FILE, my $Header, 4);
8295 close(FILE);
8296 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8297 return join("", @Bytes);
8298}
8299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008300sub is_header_file($)
8301{
8302 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8303 return $_[0];
8304 }
8305 return 0;
8306}
8307
8308sub is_not_header($)
8309{
8310 if($_[0]=~/\.\w+\Z/
8311 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8312 return 1;
8313 }
8314 return 0;
8315}
8316
8317sub is_header($$$)
8318{
8319 my ($Header, $UserDefined, $LibVersion) = @_;
8320 return 0 if(-d $Header);
8321 if(-f $Header) {
8322 $Header = get_abs_path($Header);
8323 }
8324 else
8325 {
8326 if(is_abs($Header))
8327 { # incorrect absolute path
8328 return 0;
8329 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008330 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008331 $Header = $HPath;
8332 }
8333 else
8334 { # can't find header
8335 return 0;
8336 }
8337 }
8338 if($Header=~/\.\w+\Z/)
8339 { # have an extension
8340 return is_header_file($Header);
8341 }
8342 else
8343 {
8344 if($UserDefined==2)
8345 { # specified on the command line
8346 if(cmd_file($Header)!~/HTML|XML/i) {
8347 return $Header;
8348 }
8349 }
8350 elsif($UserDefined)
8351 { # specified in the XML-descriptor
8352 # header file without an extension
8353 return $Header;
8354 }
8355 else
8356 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008357 if(index($Header, "/include/")!=-1
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008358 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008359 { # !~/HTML|XML|shared|dynamic/i
8360 return $Header;
8361 }
8362 }
8363 }
8364 return 0;
8365}
8366
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008367sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008368{
8369 my $LibVersion = $_[0];
8370 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8371 {
8372 my $RegDir = get_dirname($RegHeader);
8373 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008374
8375 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8376 detect_recursive_includes($RegHeader, $LibVersion);
8377 }
8378
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008379 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8380 {
8381 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008382 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8383 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8384 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008385 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8386 }
8387 }
8388 }
8389}
8390
8391sub readHeaders($)
8392{
8393 $Version = $_[0];
8394 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8395 my $DumpPath = getDump();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008396 if($Debug)
8397 { # debug mode
8398 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008399 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008400 }
8401 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008402}
8403
8404sub prepareTypes($)
8405{
8406 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008407 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008408 { # support for old ABI dumps
8409 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008410 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008411 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008412 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8413 if($TName=~/\A(\w+)::(\w+)/) {
8414 my ($P1, $P2) = ($1, $2);
8415 if($P1 eq $P2) {
8416 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008417 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008418 else {
8419 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8420 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008421 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008422 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008423 }
8424 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008425 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008426 { # support for old ABI dumps
8427 # V < 2.5: array size == "number of elements"
8428 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008429 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008430 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008431 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008432 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008433 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008434 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008435 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008436 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008437 $Size *= $Base{"Size"};
8438 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008439 }
8440 else
8441 { # array[] is a pointer
8442 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008443 }
8444 }
8445 }
8446 }
8447 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008448 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008449 { # support for old ABI dumps
8450 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008451 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008452 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008453 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008454 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008455 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008456 my %Type = get_Type($TypeId, $LibVersion);
8457 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8458 my %Type2 = get_Type($TypeId_2, $V2);
8459 if($Type{"Size"} ne $Type2{"Size"}) {
8460 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008461 }
8462 }
8463 }
8464 }
8465}
8466
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008467sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008468{
8469 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008470
8471 if(not keys(%{$SymbolInfo{$LibVersion}}))
8472 { # check if input is valid
8473 if(not $ExtendedCheck and not $CheckObjectsOnly)
8474 {
8475 if($CheckHeadersOnly) {
8476 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8477 }
8478 else {
8479 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8480 }
8481 }
8482 }
8483
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008484 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008485 if(not checkDump(1, "2.10")
8486 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008487 { # different formats
8488 $Remangle = 1;
8489 }
8490 if($CheckHeadersOnly)
8491 { # different languages
8492 if($UserLang)
8493 { # --lang=LANG for both versions
8494 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8495 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8496 {
8497 if($UserLang eq "C++")
8498 { # remangle symbols
8499 $Remangle = 1;
8500 }
8501 elsif($UserLang eq "C")
8502 { # remove mangling
8503 $Remangle = -1;
8504 }
8505 }
8506 }
8507 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008508
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008509 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008510 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008511 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008512 { # support for old ABI dumps
8513 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8514 {
8515 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8516 {
8517 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8518 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008519 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008520 if(defined $DVal and $DVal ne "")
8521 {
8522 if($TName eq "char") {
8523 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8524 }
8525 elsif($TName eq "bool") {
8526 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8527 }
8528 }
8529 }
8530 }
8531 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008532 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008533 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008534 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8535 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008536 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008537 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8538 # + support for old ABI dumps
8539 next;
8540 }
8541 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008542 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008543 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008544 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008545 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008546
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008547 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008548 if(not checkDump(1, "2.12")
8549 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008550 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008551 if($ShortName eq "operator>>")
8552 {
8553 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8554 { # corrected mangling of operator>>
8555 $SRemangle = 1;
8556 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008557 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008558 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8559 {
8560 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8561 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8562 { # corrected mangling of const global data
8563 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8564 # and incorrectly mangled by old ACC versions
8565 $SRemangle = 1;
8566 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008567 }
8568 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008569 if(not $CheckHeadersOnly)
8570 { # support for old ABI dumps
8571 if(not checkDump(1, "2.17")
8572 or not checkDump(2, "2.17"))
8573 {
8574 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8575 {
8576 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8577 {
8578 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8579 {
8580 $MnglName = $ShortName;
8581 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8582 }
8583 }
8584 }
8585 }
8586 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008587 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008588 { # support for old ABI dumps: some symbols are not mangled in old dumps
8589 # mangle both sets of symbols (old and new)
8590 # NOTE: remangling all symbols by the same mangler
8591 if($MnglName=~/\A_ZN(V|)K/)
8592 { # mangling may be incorrect on old ABI dumps
8593 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008594 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008595 }
8596 if($MnglName=~/\A_ZN(K|)V/)
8597 { # mangling may be incorrect on old ABI dumps
8598 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008599 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008600 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008601 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8602 or (not $ClassID and $CheckHeadersOnly)
8603 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8604 { # support for old ABI dumps, GCC >= 4.0
8605 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008606 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008607 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008608 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008609 $MangledNames{$LibVersion}{$MnglName} = 1;
8610 }
8611 }
8612 }
8613 elsif($Remangle==-1)
8614 { # remove mangling
8615 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008616 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008617 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008618 if(not $MnglName) {
8619 next;
8620 }
8621 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8622 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008623 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8624
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008625 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008626 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008627 { # support for old dumps
8628 # add "Volatile" attribute
8629 if($MnglName=~/_Z(K|)V/) {
8630 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8631 }
8632 }
8633 # symbol and its symlink have same signatures
8634 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008635 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008636 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008637
8638 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008639 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008640 }
8641 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8642 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8643 }
8644 if($ExtendedCheck)
8645 { # --ext option
8646 addExtension($LibVersion);
8647 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008648
8649 # clean memory
8650 delete($SymbolInfo{$LibVersion});
8651
8652 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008653 { # detect allocable classes with public exported constructors
8654 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008655 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008656 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008657 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008658 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008659 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8660 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008661 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008662 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008663 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008664 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008665 $AllocableClass{$LibVersion}{$ClassName} = 1;
8666 }
8667 }
8668 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008669 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008670 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008671 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008672 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008673 if($CheckHeadersOnly)
8674 {
8675 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8676 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8677 { # all symbols except non-virtual inline
8678 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8679 }
8680 }
8681 else {
8682 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008683 }
8684 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008685 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008686 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008687 }
8688 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008689 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008690 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008691 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008692 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008693 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008694 if(defined $Base{"Type"}
8695 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008696 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008697 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008698 if($Name=~/<([^<>\s]+)>/)
8699 {
8700 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8701 $ReturnedClass{$LibVersion}{$Tid} = 1;
8702 }
8703 }
8704 else {
8705 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8706 }
8707 }
8708 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008709 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008710 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008711 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008712 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008713 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008714 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008715 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008716 if($Base{"Type"}=~/Struct|Class/)
8717 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008718 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008719 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8720 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008721 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008722 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008723 }
8724 }
8725 }
8726 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008727
8728 # mapping {short name => symbols}
8729 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008730 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008731 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008732 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008733 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008734 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008735 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008736 {
8737 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008738 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008739 }
8740 }
8741 }
8742 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008743
8744 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008745 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008746 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008747 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008748 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008749 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8750 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008751 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008752 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008753 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008754 $ClassNames{$LibVersion}{$TName} = 1;
8755 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008756 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008757 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8758 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008759 }
8760 }
8761 }
8762 }
8763 }
8764}
8765
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008766sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008767{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008768 my ($TypeId, $LibVersion) = @_;
8769 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008770 return 0;
8771 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008772 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008773 { # already registered
8774 return 1;
8775 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008776 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008777 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008778 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008779 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008780 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008781 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008782 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008783 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008784 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008785 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008786 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008787 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008788 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8789 {
8790 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8791 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008792 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008793 }
8794 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008795 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008796 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008797 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008798 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008799 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008800 }
8801 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008802 if($TInfo{"Type"} eq "FuncPtr"
8803 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008804 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008805 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008806 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008807 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008808 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008809 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008810 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008811 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008812 }
8813 }
8814 }
8815 return 1;
8816 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008817 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008818 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008819 $UsedType{$LibVersion}{$TypeId} = 1;
8820 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008821 return 1;
8822 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008823 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008824 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008825 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008826 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008827 }
8828 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008829 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008830}
8831
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008832sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008833{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008834 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8835
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008836 if($Level eq "Dump")
8837 {
8838 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8839 { # TODO: check if this symbol is from
8840 # base classes of other target symbols
8841 return 1;
8842 }
8843 }
8844
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008845 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8846 { # stdc++ interfaces
8847 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008848 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008849
8850 my $Target = 0;
8851 if(my $Header = $SInfo->{"Header"}) {
8852 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8853 }
8854 if($CheckHeadersOnly)
8855 {
8856 if($Target)
8857 {
8858 if($Level eq "Dump")
8859 { # dumped
8860 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008861 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008862 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008863 return 1;
8864 }
8865 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008866 else {
8867 return 1;
8868 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008869 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008870 elsif($Level eq "Source")
8871 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008872 return 1;
8873 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008874 elsif($Level eq "Binary")
8875 { # checked
8876 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8877 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8878 return 1;
8879 }
8880 }
8881 }
8882 }
8883 else
8884 { # library is available
8885 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8886 { # exported symbols
8887 return 1;
8888 }
8889 if($Level eq "Dump")
8890 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008891 if($BinaryOnly)
8892 {
8893 if($SInfo->{"Data"})
8894 {
8895 if($Target) {
8896 return 1;
8897 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008898 }
8899 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008900 else
8901 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008902 if($Target) {
8903 return 1;
8904 }
8905 }
8906 }
8907 elsif($Level eq "Source")
8908 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008909 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8910 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008911 { # skip LOCAL symbols
8912 if($Target) {
8913 return 1;
8914 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008915 }
8916 }
8917 elsif($Level eq "Binary")
8918 { # checked
8919 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8920 {
8921 if($Target) {
8922 return 1;
8923 }
8924 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008925 }
8926 }
8927 return 0;
8928}
8929
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008930sub cleanDump($)
8931{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008932 my $LibVersion = $_[0];
8933 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8934 {
8935 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8936 if(not $MnglName) {
8937 delete($SymbolInfo{$LibVersion}{$InfoId});
8938 next;
8939 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008940 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008941 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008942 delete($SymbolInfo{$LibVersion}{$InfoId});
8943 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008944 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008945 if($MnglName eq $ShortName)
8946 { # remove duplicate data
8947 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008948 }
8949 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8950 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8951 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008952 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8953 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8954 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008955 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008956 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008957 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008958 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008959 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008960 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008961 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8962 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8963 }
8964 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008965 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8966 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8967 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008968 }
8969}
8970
8971sub selectType($$)
8972{
8973 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008974
8975 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8976 {
8977 if(defined $TypeInfo{$LibVersion}{$Dupl})
8978 {
8979 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8980 { # duplicate
8981 return 0;
8982 }
8983 }
8984 }
8985
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008986 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8987 {
8988 if(not isBuiltIn($THeader))
8989 {
8990 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008991 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008992 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8993 {
8994 if(is_target_header($THeader, $LibVersion))
8995 { # from target headers
8996 if(not selfTypedef($Tid, $LibVersion)) {
8997 return 1;
8998 }
8999 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009000 }
9001 }
9002 }
9003 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009004 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009005}
9006
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009007sub removeUnused($$)
9008{ # remove unused data types from the ABI dump
9009 my ($LibVersion, $Kind) = @_;
9010 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
9011 {
9012 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
9013 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009014 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009015 }
9016 if(my $FCid = $FuncInfo{"Class"})
9017 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009018 register_TypeUsage($FCid, $LibVersion);
9019 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009020 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009021 $UsedType{$LibVersion}{$ThisId} = 1;
9022 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
9023 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009024 }
9025 }
9026 }
9027 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
9028 {
9029 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009030 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009031 }
9032 }
9033 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
9034 {
9035 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
9036 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009037 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009038 }
9039 }
9040 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009041 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
9042 {
9043 if($UsedType{$LibVersion}{$Tid})
9044 { # All & Derived
9045 next;
9046 }
9047
9048 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009049 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009050 if(selectType($Tid, $LibVersion)) {
9051 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009052 }
9053 }
9054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009055 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
9056 { # remove unused types
9057 if($UsedType{$LibVersion}{$Tid})
9058 { # All & Derived
9059 next;
9060 }
9061 # remove type
9062 delete($TypeInfo{$LibVersion}{$Tid});
9063 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009064
9065 # clean memory
9066 %UsedType = ();
9067}
9068
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009069sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009070{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009071 my ($TypeId, $LibVersion) = @_;
9072 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009073 if($Type{"Type"} eq "Typedef")
9074 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009075 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009076 if($Base{"Type"}=~/Class|Struct/)
9077 {
9078 if($Type{"Name"} eq $Base{"Name"}) {
9079 return 1;
9080 }
9081 elsif($Type{"Name"}=~/::(\w+)\Z/)
9082 {
9083 if($Type{"Name"} eq $Base{"Name"}."::".$1)
9084 { # QPointer<QWidget>::QPointer
9085 return 1;
9086 }
9087 }
9088 }
9089 }
9090 return 0;
9091}
9092
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009093sub addExtension($)
9094{
9095 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009096 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009097 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009098 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009099 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009100 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
9101
9102 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
9103 "Header" => "extended.h",
9104 "ShortName" => $Symbol,
9105 "MnglName" => $Symbol,
9106 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
9107 );
9108
9109 $ExtendedSymbols{$Symbol}=1;
9110 $CheckedSymbols{"Binary"}{$Symbol}=1;
9111 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009112 }
9113 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009114 $ExtendedSymbols{"external_func_0"}=1;
9115 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
9116 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009117}
9118
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009119sub findMethod($$$)
9120{
9121 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009122 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009123 {
9124 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9125 return $VirtMethodInClass;
9126 }
9127 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9128 return $VirtMethodInBaseClasses;
9129 }
9130 }
9131 return "";
9132}
9133
9134sub findMethod_Class($$$)
9135{
9136 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009137 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009138 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9139 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9140 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9141 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9142 { # search for interface with the same parameters suffix (overridden)
9143 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9144 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009145 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
9146 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009147 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9148 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009149 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9150 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9151 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9152 return $Candidate;
9153 }
9154 }
9155 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009156 else
9157 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009158 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9159 return $Candidate;
9160 }
9161 }
9162 }
9163 }
9164 return "";
9165}
9166
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009167sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009168{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009169 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009170 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009171 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009172 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9173 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009174 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009175 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009176 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009177 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9178 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009179 { # pure virtual D2-destructors are marked as "virt" in the dump
9180 # virtual D2-destructors are NOT marked as "virt" in the dump
9181 # both destructors are not presented in the v-table
9182 next;
9183 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009184 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009185 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9186 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009187 }
9188}
9189
9190sub registerOverriding($)
9191{
9192 my $LibVersion = $_[0];
9193 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009194 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009195 foreach my $ClassName (@Classes)
9196 {
9197 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9198 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009199 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9200 { # pure virtuals
9201 next;
9202 }
9203 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9204 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009205 {
9206 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9207 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9208 { # both overridden virtual methods
9209 # and implemented pure virtual methods
9210 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9211 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9212 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9213 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009214 }
9215 }
9216 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9217 delete($VirtualTable{$LibVersion}{$ClassName});
9218 }
9219 }
9220}
9221
9222sub setVirtFuncPositions($)
9223{
9224 my $LibVersion = $_[0];
9225 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9226 {
9227 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9228 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9229 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9230 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009231 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9232
9233 # set relative positions
9234 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9235 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9236 { # relative position excluding added and removed virtual functions
9237 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9238 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009239 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009242 }
9243 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009244 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009245 {
9246 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009247 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9248 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009249 }
9250 }
9251}
9252
9253sub get_sub_classes($$$)
9254{
9255 my ($ClassId, $LibVersion, $Recursive) = @_;
9256 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9257 my @Subs = ();
9258 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9259 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009260 if($Recursive)
9261 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009262 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9263 push(@Subs, $SubSubId);
9264 }
9265 }
9266 push(@Subs, $SubId);
9267 }
9268 return @Subs;
9269}
9270
9271sub get_base_classes($$$)
9272{
9273 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009274 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009275 return () if(not defined $ClassType{"Base"});
9276 my @Bases = ();
9277 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9278 keys(%{$ClassType{"Base"}}))
9279 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009280 if($Recursive)
9281 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009282 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9283 push(@Bases, $SubBaseId);
9284 }
9285 }
9286 push(@Bases, $BaseId);
9287 }
9288 return @Bases;
9289}
9290
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009291sub getVTable_Model($$)
9292{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009293 my ($ClassId, $LibVersion) = @_;
9294 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9295 my @Elements = ();
9296 foreach my $BaseId (@Bases, $ClassId)
9297 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009298 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009299 {
9300 if(defined $VirtualTable{$LibVersion}{$BName})
9301 {
9302 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9303 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9304 foreach my $VFunc (@VFunctions) {
9305 push(@Elements, $VFunc);
9306 }
9307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009308 }
9309 }
9310 return @Elements;
9311}
9312
9313sub getVShift($$)
9314{
9315 my ($ClassId, $LibVersion) = @_;
9316 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9317 my $VShift = 0;
9318 foreach my $BaseId (@Bases)
9319 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009320 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009321 {
9322 if(defined $VirtualTable{$LibVersion}{$BName}) {
9323 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9324 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009325 }
9326 }
9327 return $VShift;
9328}
9329
9330sub getShift($$)
9331{
9332 my ($ClassId, $LibVersion) = @_;
9333 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9334 my $Shift = 0;
9335 foreach my $BaseId (@Bases)
9336 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009337 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009338 {
9339 if($Size!=1)
9340 { # not empty base class
9341 $Shift+=$Size;
9342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009343 }
9344 }
9345 return $Shift;
9346}
9347
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009348sub getVTable_Size($$)
9349{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009350 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009351 my $Size = 0;
9352 # three approaches
9353 if(not $Size)
9354 { # real size
9355 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9356 $Size = keys(%VTable);
9357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009358 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009359 if(not $Size)
9360 { # shared library symbol size
9361 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9362 $Size /= $WORD_SIZE{$LibVersion};
9363 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009364 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009365 if(not $Size)
9366 { # model size
9367 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9368 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9369 }
9370 }
9371 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009372}
9373
9374sub isCopyingClass($$)
9375{
9376 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009377 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009378}
9379
9380sub isLeafClass($$)
9381{
9382 my ($ClassId, $LibVersion) = @_;
9383 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9384}
9385
9386sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009387{ # check structured type for public fields
9388 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009389}
9390
9391sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009392{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009393 my ($TypePtr, $Skip, $Start, $End) = @_;
9394 return 0 if(not $TypePtr);
9395 if($End==-1) {
9396 $End = keys(%{$TypePtr->{"Memb"}})-1;
9397 }
9398 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9399 {
9400 if($Skip and $Skip->{$MemPos})
9401 { # skip removed/added fields
9402 next;
9403 }
9404 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9405 {
9406 if(isPublic($TypePtr, $MemPos)) {
9407 return ($MemPos+1);
9408 }
9409 }
9410 }
9411 return 0;
9412}
9413
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414sub isReserved($)
9415{ # reserved fields == private
9416 my $MName = $_[0];
9417 if($MName=~/reserved|padding|f_spare/i) {
9418 return 1;
9419 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009420 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009421 return 1;
9422 }
9423 if($MName=~/(pad\d+)/i) {
9424 return 1;
9425 }
9426 return 0;
9427}
9428
9429sub isPublic($$)
9430{
9431 my ($TypePtr, $FieldPos) = @_;
9432 return 0 if(not $TypePtr);
9433 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9434 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9435 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9436 { # by name in C language
9437 # FIXME: add other methods to detect private members
9438 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9439 if($MName=~/priv|abidata|parent_object/i)
9440 { # C-styled private data
9441 return 0;
9442 }
9443 if(lc($MName) eq "abi")
9444 { # ABI information/reserved field
9445 return 0;
9446 }
9447 if(isReserved($MName))
9448 { # reserved fields
9449 return 0;
9450 }
9451 return 1;
9452 }
9453 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9454 { # by access in C++ language
9455 return 1;
9456 }
9457 return 0;
9458}
9459
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009460sub getVTable_Real($$)
9461{
9462 my ($ClassName, $LibVersion) = @_;
9463 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9464 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009465 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009466 if(defined $Type{"VTable"}) {
9467 return %{$Type{"VTable"}};
9468 }
9469 }
9470 return ();
9471}
9472
9473sub cmpVTables($)
9474{
9475 my $ClassName = $_[0];
9476 my $Res = cmpVTables_Real($ClassName, 1);
9477 if($Res==-1) {
9478 $Res = cmpVTables_Model($ClassName);
9479 }
9480 return $Res;
9481}
9482
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009483sub cmpVTables_Model($)
9484{
9485 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009486 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009487 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009488 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009489 return 1;
9490 }
9491 }
9492 return 0;
9493}
9494
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009495sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009496{
9497 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009498 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9499 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009500 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009501 my %VTable_Old = getVTable_Real($ClassName, 1);
9502 my %VTable_New = getVTable_Real($ClassName, 2);
9503 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009504 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009505 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009506 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009507 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9509 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009510 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009511 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009512 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009513 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009514 my $Entry1 = $VTable_Old{$Offset};
9515 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009516 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009517 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009518 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009519 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009520 $Entry1 = simpleVEntry($Entry1);
9521 $Entry2 = simpleVEntry($Entry2);
9522 if($Entry1 ne $Entry2)
9523 { # register as changed
9524 if($Entry1=~/::([^:]+)\Z/)
9525 {
9526 my $M1 = $1;
9527 if($Entry2=~/::([^:]+)\Z/)
9528 {
9529 my $M2 = $1;
9530 if($M1 eq $M2)
9531 { # overridden
9532 next;
9533 }
9534 }
9535 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009536 if(differentDumps("G"))
9537 {
9538 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9539 {
9540 # GCC 4.6.1: -0x00000000000000010
9541 # GCC 4.7.0: -16
9542 next;
9543 }
9544 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009545 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009546 }
9547 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009548 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009549}
9550
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009551sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009552{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009553 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009554 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9555 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009556 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009557 { # already registered
9558 next;
9559 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009560 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009561 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009562 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009563 foreach my $Symbol (@Affected)
9564 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009565 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009566 "Type_Name"=>$ClassName,
9567 "Type_Type"=>"Class",
9568 "Target"=>$ClassName);
9569 }
9570 }
9571 }
9572}
9573
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009574sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009575{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009576 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009577 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009578 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009579 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009580 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009581 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009582 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009583 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009584 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009585 if($TName_Tid{1}{$ClassName}
9586 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009587 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009588 if(defined $CompleteSignature{1}{$Symbol}
9589 and $CompleteSignature{1}{$Symbol}{"Virt"})
9590 { # override some method in v.1
9591 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009592 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009593 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009594 }
9595 }
9596 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009597 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009598 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009599 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009600 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009601 if($TName_Tid{2}{$ClassName}
9602 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009603 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009604 if(defined $CompleteSignature{2}{$Symbol}
9605 and $CompleteSignature{2}{$Symbol}{"Virt"})
9606 { # override some method in v.2
9607 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009608 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009609 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009610 }
9611 }
9612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009613 if($Level eq "Binary")
9614 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009615 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009616 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9617 { # check replacements, including pure virtual methods
9618 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9619 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009620 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009621 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9622 if($AddedPos==$RemovedPos)
9623 {
9624 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9625 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9626 last; # other methods will be reported as "added" or "removed"
9627 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009628 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009629 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9630 {
9631 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9632 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009633 next;
9634 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009635 my $ProblemType = "Virtual_Replacement";
9636 my @Affected = ($RemovedVFunc);
9637 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9638 { # pure methods
9639 if(not isUsedClass($ClassId, 1, $Level))
9640 { # not a parameter of some exported method
9641 next;
9642 }
9643 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009644
9645 # affected all methods (both virtual and non-virtual ones)
9646 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9647 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009648 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009649 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009650 foreach my $AffectedInt (@Affected)
9651 {
9652 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9653 { # affected exported methods only
9654 next;
9655 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009656 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9657 next;
9658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009659 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9660 "Type_Name"=>$Class_Type{"Name"},
9661 "Type_Type"=>"Class",
9662 "Target"=>get_Signature($AddedVFunc, 2),
9663 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9664 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009665 }
9666 }
9667 }
9668 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009669 if(not checkDump(1, "2.0")
9670 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009671 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009672 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009673 return;
9674 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009675 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009676 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009677 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009678 next if(not $ClassId_Old);
9679 if(not isCreatable($ClassId_Old, 1))
9680 { # skip classes without public constructors (including auto-generated)
9681 # example: class has only a private exported or private inline constructor
9682 next;
9683 }
9684 if($ClassName=~/>/)
9685 { # skip affected template instances
9686 next;
9687 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009688 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009689 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009690 if(not $ClassId_New) {
9691 next;
9692 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009693 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009694 if($Class_New{"Type"}!~/Class|Struct/)
9695 { # became typedef
9696 if($Level eq "Binary") {
9697 next;
9698 }
9699 if($Level eq "Source")
9700 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009701 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009702 if($Class_New{"Type"}!~/Class|Struct/) {
9703 next;
9704 }
9705 $ClassId_New = $Class_New{"Tid"};
9706 }
9707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009708 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9709 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009710
9711 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9712 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9713
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009714 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009715 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9716 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009717 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9718 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009719 my $Shift_Old = getShift($ClassId_Old, 1);
9720 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009721 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009722 my ($Added, $Removed) = (0, 0);
9723 my @StableBases_Old = ();
9724 foreach my $BaseId (@Bases_Old)
9725 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009726 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009727 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009728 push(@StableBases_Old, $BaseId);
9729 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009730 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009731 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009732 { # removed base
9733 # excluding namespace::SomeClass to SomeClass renaming
9734 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009735 if($Level eq "Binary")
9736 { # Binary-level
9737 if($Shift_Old ne $Shift_New)
9738 { # affected fields
9739 if(havePubFields(\%Class_Old)) {
9740 $ProblemKind .= "_And_Shift";
9741 }
9742 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9743 $ProblemKind .= "_And_Size";
9744 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009745 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009746 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9747 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009748 { # affected v-table
9749 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009750 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009751 }
9752 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009753 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009754 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9755 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009756 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9757 {
9758 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9759 if($ProblemKind=~/VTable/) {
9760 $VTableChanged_M{$SubName}=1;
9761 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009762 }
9763 }
9764 foreach my $Interface (@Affected)
9765 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009766 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9767 next;
9768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009769 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009770 "Type_Name"=>$ClassName,
9771 "Type_Type"=>"Class",
9772 "Target"=>$BaseName,
9773 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9774 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9775 "Shift"=>abs($Shift_New-$Shift_Old) );
9776 }
9777 $Removed+=1;
9778 }
9779 }
9780 my @StableBases_New = ();
9781 foreach my $BaseId (@Bases_New)
9782 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009783 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009784 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009785 push(@StableBases_New, $BaseId);
9786 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009787 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009788 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009789 { # added base
9790 # excluding namespace::SomeClass to SomeClass renaming
9791 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009792 if($Level eq "Binary")
9793 { # Binary-level
9794 if($Shift_Old ne $Shift_New)
9795 { # affected fields
9796 if(havePubFields(\%Class_Old)) {
9797 $ProblemKind .= "_And_Shift";
9798 }
9799 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9800 $ProblemKind .= "_And_Size";
9801 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009802 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009803 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9804 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009805 { # affected v-table
9806 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009807 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009808 }
9809 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009810 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009811 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9812 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009813 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9814 {
9815 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9816 if($ProblemKind=~/VTable/) {
9817 $VTableChanged_M{$SubName}=1;
9818 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009819 }
9820 }
9821 foreach my $Interface (@Affected)
9822 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009823 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9824 next;
9825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009826 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009827 "Type_Name"=>$ClassName,
9828 "Type_Type"=>"Class",
9829 "Target"=>$BaseName,
9830 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9831 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9832 "Shift"=>abs($Shift_New-$Shift_Old) );
9833 }
9834 $Added+=1;
9835 }
9836 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009837 if($Level eq "Binary")
9838 { # Binary-level
9839 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009840 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9841 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009842 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009843 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009844 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009845 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009846 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009847 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9848 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009849 if($NewPos!=$OldPos)
9850 { # changed position of the base class
9851 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009852 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009853 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9854 next;
9855 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009856 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9857 "Type_Name"=>$ClassName,
9858 "Type_Type"=>"Class",
9859 "Target"=>$BaseName,
9860 "Old_Value"=>$OldPos-1,
9861 "New_Value"=>$NewPos-1 );
9862 }
9863 }
9864 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9865 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9866 { # became non-virtual base
9867 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9868 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009869 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9870 next;
9871 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009872 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9873 "Type_Name"=>$ClassName,
9874 "Type_Type"=>"Class",
9875 "Target"=>$BaseName );
9876 }
9877 }
9878 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9879 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9880 { # became virtual base
9881 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9882 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009883 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9884 next;
9885 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009886 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9887 "Type_Name"=>$ClassName,
9888 "Type_Type"=>"Class",
9889 "Target"=>$BaseName );
9890 }
9891 }
9892 }
9893 }
9894 # detect size changes in base classes
9895 if($Shift_Old!=$Shift_New)
9896 { # size of allocable class
9897 foreach my $BaseId (@StableBases_Old)
9898 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009899 my %BaseType = get_Type($BaseId, 1);
9900 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009901 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009902 if($Size_Old ne $Size_New
9903 and $Size_Old and $Size_New)
9904 {
9905 my $ProblemType = "";
9906 if(isCopyingClass($BaseId, 1)) {
9907 $ProblemType = "Size_Of_Copying_Class";
9908 }
9909 elsif($AllocableClass{1}{$BaseType{"Name"}})
9910 {
9911 if($Size_New>$Size_Old)
9912 { # increased size
9913 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009914 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009915 else
9916 { # decreased size
9917 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9918 if(not havePubFields(\%Class_Old))
9919 { # affected class has no public members
9920 next;
9921 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009922 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009923 }
9924 next if(not $ProblemType);
9925 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9926 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009927 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9928 next;
9929 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009930 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9931 "Type_Name"=>$BaseType{"Name"},
9932 "Type_Type"=>"Class",
9933 "Target"=>$BaseType{"Name"},
9934 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9935 "New_Size"=>$Size_New*$BYTE_SIZE );
9936 }
9937 }
9938 }
9939 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009940 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009941 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009942 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009943 { # compare virtual tables size in base classes
9944 my $VShift_Old = getVShift($ClassId_Old, 1);
9945 my $VShift_New = getVShift($ClassId_New, 2);
9946 if($VShift_Old ne $VShift_New)
9947 { # changes in the base class or changes in the list of base classes
9948 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9949 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9950 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009951 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009952 foreach my $BaseId (@AllBases_Old)
9953 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009954 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009955 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009956 { # lost base
9957 next;
9958 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009959 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9960 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009961 if($VSize_Old!=$VSize_New)
9962 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009963 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009964 { # TODO: affected non-virtual methods?
9965 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009966 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9967 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009968 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009969 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009970 { # skip interfaces that have not changed the absolute virtual position
9971 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009972 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009973 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9974 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009975 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009976 $VTableChanged_M{$BaseType{"Name"}} = 1;
9977 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009978 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9979 { # the reason of the layout change: added virtual functions
9980 next if($VirtualReplacement{$VirtFunc});
9981 my $ProblemType = "Added_Virtual_Method";
9982 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9983 $ProblemType = "Added_Pure_Virtual_Method";
9984 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009985 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009986 "Type_Name"=>$BaseType{"Name"},
9987 "Type_Type"=>"Class",
9988 "Target"=>get_Signature($VirtFunc, 2) );
9989 }
9990 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9991 { # the reason of the layout change: removed virtual functions
9992 next if($VirtualReplacement{$VirtFunc});
9993 my $ProblemType = "Removed_Virtual_Method";
9994 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9995 $ProblemType = "Removed_Pure_Virtual_Method";
9996 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009997 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009998 "Type_Name"=>$BaseType{"Name"},
9999 "Type_Type"=>"Class",
10000 "Target"=>get_Signature($VirtFunc, 1) );
10001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010002 }
10003 }
10004 }
10005 }
10006 }
10007 }
10008 }
10009}
10010
10011sub isCreatable($$)
10012{
10013 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010014 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010015 or isCopyingClass($ClassId, $LibVersion)) {
10016 return 1;
10017 }
10018 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
10019 { # Fix for incomplete data: if this class has
10020 # a base class then it should also has a constructor
10021 return 1;
10022 }
10023 if($ReturnedClass{$LibVersion}{$ClassId})
10024 { # returned by some method of this class
10025 # or any other class
10026 return 1;
10027 }
10028 return 0;
10029}
10030
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010031sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010032{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010033 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010034 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
10035 { # parameter of some exported method
10036 return 1;
10037 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010038 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
10039 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010040 { # method from target class
10041 return 1;
10042 }
10043 return 0;
10044}
10045
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010046sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010047{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010048 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010049 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010050 # - virtual
10051 # - pure-virtual
10052 # - non-virtual
10053 if($CompleteSignature{1}{$Interface}{"Data"})
10054 { # global data is not affected
10055 return;
10056 }
10057 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010058 if(not $Class_Id) {
10059 return;
10060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010061 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010062 if(cmpVTables_Real($CName, 1)==0)
10063 { # no changes
10064 return;
10065 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010066 $CheckedTypes{$Level}{$CName} = 1;
10067 if($Level eq "Binary")
10068 { # Binary-level
10069 if($CompleteSignature{1}{$Interface}{"PureVirt"}
10070 and not isUsedClass($Class_Id, 1, $Level))
10071 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010072 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010073 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010074 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010075 }
10076 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
10077 {
10078 if(defined $VirtualTable{2}{$CName}{$Func}
10079 and defined $CompleteSignature{2}{$Func})
10080 {
10081 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
10082 and $CompleteSignature{2}{$Func}{"PureVirt"})
10083 { # became pure virtual
10084 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
10085 "Type_Name"=>$CName,
10086 "Type_Type"=>"Class",
10087 "Target"=>get_Signature_M($Func, 1) );
10088 $VTableChanged_M{$CName} = 1;
10089 }
10090 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
10091 and not $CompleteSignature{2}{$Func}{"PureVirt"})
10092 { # became non-pure virtual
10093 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
10094 "Type_Name"=>$CName,
10095 "Type_Type"=>"Class",
10096 "Target"=>get_Signature_M($Func, 1) );
10097 $VTableChanged_M{$CName} = 1;
10098 }
10099 }
10100 }
10101 if($Level eq "Binary")
10102 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010103 # check virtual table structure
10104 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
10105 {
10106 next if($Interface eq $AddedVFunc);
10107 next if($VirtualReplacement{$AddedVFunc});
10108 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
10109 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
10110 { # pure virtual methods affect all others (virtual and non-virtual)
10111 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010112 "Type_Name"=>$CName,
10113 "Type_Type"=>"Class",
10114 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010115 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010116 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010117 elsif(not defined $VirtualTable{1}{$CName}
10118 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010119 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010120 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010121 { # became polymorphous class, added v-table pointer
10122 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010123 "Type_Name"=>$CName,
10124 "Type_Type"=>"Class",
10125 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010126 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010127 }
10128 else
10129 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010130 my $VSize_Old = getVTable_Size($CName, 1);
10131 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010132 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010133 if(isCopyingClass($Class_Id, 1))
10134 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10135 my $ProblemType = "Added_Virtual_Method";
10136 if(isLeafClass($Class_Id, 1)) {
10137 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10138 }
10139 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10140 "Type_Name"=>$CName,
10141 "Type_Type"=>"Class",
10142 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010143 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010144 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010145 else
10146 {
10147 my $ProblemType = "Added_Virtual_Method";
10148 if(isLeafClass($Class_Id, 1)) {
10149 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10150 }
10151 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10152 "Type_Name"=>$CName,
10153 "Type_Type"=>"Class",
10154 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010155 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010157 }
10158 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010159 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10160 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010161 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010162 if(defined $VirtualTable{1}{$CName}
10163 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010164 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010165 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10166 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10167 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010168 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010169 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10170 foreach my $ASymbol (@Affected)
10171 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010172 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10173 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010174 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010175 next;
10176 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010177 }
10178 $CheckedSymbols{$Level}{$ASymbol} = 1;
10179 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10180 "Type_Name"=>$CName,
10181 "Type_Type"=>"Class",
10182 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010183 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010185 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010186 }
10187 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010188 else {
10189 # safe
10190 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010191 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010192 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10193 {
10194 next if($VirtualReplacement{$RemovedVFunc});
10195 if($RemovedVFunc eq $Interface
10196 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10197 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010198 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010199 next;
10200 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010201 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010202 { # became non-polymorphous class, removed v-table pointer
10203 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10204 "Type_Name"=>$CName,
10205 "Type_Type"=>"Class",
10206 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010207 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010208 }
10209 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10210 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10211 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010212 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010213 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010214 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10215 next;
10216 }
10217 my $VPos_New = -1;
10218 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010219 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010220 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10221 }
10222 else
10223 {
10224 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010225 next;
10226 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010227 }
10228 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10229 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10230 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10231 {
10232 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10233 foreach my $ASymbol (@Affected)
10234 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010235 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10236 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010237 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010238 next;
10239 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010240 }
10241 my $ProblemType = "Removed_Virtual_Method";
10242 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10243 $ProblemType = "Removed_Pure_Virtual_Method";
10244 }
10245 $CheckedSymbols{$Level}{$ASymbol} = 1;
10246 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10247 "Type_Name"=>$CName,
10248 "Type_Type"=>"Class",
10249 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010250 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010252 }
10253 }
10254 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010255 }
10256 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010257 else
10258 { # Source-level
10259 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010260 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010261 next if($Interface eq $AddedVFunc);
10262 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010263 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010264 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10265 "Type_Name"=>$CName,
10266 "Type_Type"=>"Class",
10267 "Target"=>get_Signature($AddedVFunc, 2) );
10268 }
10269 }
10270 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10271 {
10272 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10273 {
10274 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10275 "Type_Name"=>$CName,
10276 "Type_Type"=>"Class",
10277 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010278 }
10279 }
10280 }
10281}
10282
10283sub find_MemberPair_Pos_byName($$)
10284{
10285 my ($Member_Name, $Pair_Type) = @_;
10286 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10287 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10288 {
10289 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10290 {
10291 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10292 $Name=~s/\A[_]+|[_]+\Z//g;
10293 if($Name eq $Member_Name) {
10294 return $MemberPair_Pos;
10295 }
10296 }
10297 }
10298 return "lost";
10299}
10300
10301sub find_MemberPair_Pos_byVal($$)
10302{
10303 my ($Member_Value, $Pair_Type) = @_;
10304 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10305 {
10306 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10307 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10308 return $MemberPair_Pos;
10309 }
10310 }
10311 return "lost";
10312}
10313
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010314my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010315 "High"=>3,
10316 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010317 "Low"=>1,
10318 "Safe"=>-1
10319);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010320
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010321sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010322{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010323 my ($S1, $S2) = @_;
10324 if(cmpSeverities($S1, $S2)) {
10325 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010326 }
10327 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010328 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010329 }
10330}
10331
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010332sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010333{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010334 my ($S1, $S2) = @_;
10335 if(not $S1) {
10336 return 0;
10337 }
10338 elsif(not $S2) {
10339 return 1;
10340 }
10341 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010342}
10343
10344sub getProblemSeverity($$)
10345{
10346 my ($Level, $Kind) = @_;
10347 return $CompatRules{$Level}{$Kind}{"Severity"};
10348}
10349
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010350sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010351{
10352 foreach (@RecurTypes)
10353 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010354 if( $_->{"T1"} eq $_[0]
10355 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010356 {
10357 return 1;
10358 }
10359 }
10360 return 0;
10361}
10362
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010363sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010364{
10365 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010366 "T1" => $_[0], #Tid1
10367 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010368 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010369 push(@RecurTypes, \%TypeIDs);
10370}
10371
10372sub isRenamed($$$$$)
10373{
10374 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10375 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10376 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010377 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010378 if(not defined $Type2->{"Memb"}{$MemPos}) {
10379 return "";
10380 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010381 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010382 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010383
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010384 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10385 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010386 if($MemberPair_Pos_Rev eq "lost")
10387 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010388 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10389 { # base type match
10390 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010391 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010392 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10393 { # exact type match
10394 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010395 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010396 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10397 { # size match
10398 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010399 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010400 if(isReserved($Pair_Name))
10401 { # reserved fields
10402 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010403 }
10404 }
10405 return "";
10406}
10407
10408sub isLastElem($$)
10409{
10410 my ($Pos, $TypeRef) = @_;
10411 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10412 if($Name=~/last|count|max|total/i)
10413 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10414 return 1;
10415 }
10416 elsif($Name=~/END|NLIMITS\Z/)
10417 { # __RLIMIT_NLIMITS
10418 return 1;
10419 }
10420 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10421 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10422 { # NImageFormats, NColorRoles
10423 return 1;
10424 }
10425 return 0;
10426}
10427
10428sub nonComparable($$)
10429{
10430 my ($T1, $T2) = @_;
10431 if($T1->{"Name"} ne $T2->{"Name"}
10432 and not isAnon($T1->{"Name"})
10433 and not isAnon($T2->{"Name"}))
10434 { # different names
10435 if($T1->{"Type"} ne "Pointer"
10436 or $T2->{"Type"} ne "Pointer")
10437 { # compare base types
10438 return 1;
10439 }
10440 if($T1->{"Name"}!~/\Avoid\s*\*/
10441 and $T2->{"Name"}=~/\Avoid\s*\*/)
10442 {
10443 return 1;
10444 }
10445 }
10446 elsif($T1->{"Type"} ne $T2->{"Type"})
10447 { # different types
10448 if($T1->{"Type"} eq "Class"
10449 and $T2->{"Type"} eq "Struct")
10450 { # "class" to "struct"
10451 return 0;
10452 }
10453 elsif($T2->{"Type"} eq "Class"
10454 and $T1->{"Type"} eq "Struct")
10455 { # "struct" to "class"
10456 return 0;
10457 }
10458 else
10459 { # "class" to "enum"
10460 # "union" to "class"
10461 # ...
10462 return 1;
10463 }
10464 }
10465 return 0;
10466}
10467
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010468sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010469{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010470 my ($Type1_Id, $Type2_Id, $Level) = @_;
10471 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010472 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010473 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010474 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010475 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010476 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010477 my %Type1 = get_Type($Type1_Id, 1);
10478 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010479 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10480 return ();
10481 }
10482 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010483 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10484 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010485 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010486 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10487 { # including a case when "class Class { ... };" changed to "class Class;"
10488 return ();
10489 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010490 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010491 { # skip recursive declarations
10492 return ();
10493 }
10494 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10495 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10496 return () if($SkipTypes{1}{$Type1{"Name"}});
10497
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010498 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10499 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010500 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10501 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10502 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010503 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010504 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10505 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010506 if($Base_1{"Name"} ne $Base_2{"Name"})
10507 {
10508 if(differentDumps("G")
10509 or differentDumps("V"))
10510 { # different GCC versions or different dumps
10511 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10512 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10513 # std::__va_list and __va_list
10514 $Base_1{"Name"}=~s/\A(\w+::)+//;
10515 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010516 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10517 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010518 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010519 }
10520 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10521 and $Base_1{"Name"} ne $Base_2{"Name"})
10522 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010523 if($Level eq "Binary"
10524 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010525 {
10526 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10527 "Target"=>$Typedef_1{"Name"},
10528 "Type_Name"=>$Typedef_1{"Name"},
10529 "Type_Type"=>"Typedef",
10530 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10531 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10532 }
10533 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10534 "Target"=>$Typedef_1{"Name"},
10535 "Type_Name"=>$Typedef_1{"Name"},
10536 "Type_Type"=>"Typedef",
10537 "Old_Value"=>$Base_1{"Name"},
10538 "New_Value"=>$Base_2{"Name"} );
10539 }
10540 }
10541 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10542 { # different types (reported in detectTypeChange(...))
10543 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10544 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10545 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10546 { # different type of the type
10547 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10548 "Target"=>$Type1_Pure{"Name"},
10549 "Type_Name"=>$Type1_Pure{"Name"},
10550 "Type_Type"=>$Type1_Pure{"Type"},
10551 "Old_Value"=>lc($Type1_Pure{"Type"}),
10552 "New_Value"=>lc($Type2_Pure{"Type"}) );
10553 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010554 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010555 return %SubProblems;
10556 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010557 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010558 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10559 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10560 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10561 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010562 if($Level eq "Binary"
10563 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010564 {
10565 my $ProblemKind = "DataType_Size";
10566 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010567 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010568 {
10569 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10570 $ProblemKind = "Size_Of_Copying_Class";
10571 }
10572 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10573 {
10574 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10575 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10576 }
10577 else {
10578 # descreased size of allocable class
10579 # it has no special effects
10580 }
10581 }
10582 }
10583 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10584 "Target"=>$Type1_Pure{"Name"},
10585 "Type_Name"=>$Type1_Pure{"Name"},
10586 "Type_Type"=>$Type1_Pure{"Type"},
10587 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10588 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10589 "InitialType_Type"=>$Type1_Pure{"Type"} );
10590 }
10591 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010592 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10593 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10594 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010595 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010596 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10597 {
10598 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10599 {
10600 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10601 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10602 }
10603 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10604 }
10605 }
10606 }
10607 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10608 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10609 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10610 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10611 { # detect removed and renamed fields
10612 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10613 next if(not $Member_Name);
10614 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);
10615 if($MemberPair_Pos eq "lost")
10616 {
10617 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10618 {
10619 if(isUnnamed($Member_Name))
10620 { # support for old-version dumps
10621 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010622 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010623 next;
10624 }
10625 }
10626 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10627 { # renamed
10628 $RenamedField{$Member_Pos}=$RenamedTo;
10629 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10630 }
10631 else
10632 { # removed
10633 $RemovedField{$Member_Pos}=1;
10634 }
10635 }
10636 elsif($Type1_Pure{"Type"} eq "Enum")
10637 {
10638 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10639 next if($Member_Value1 eq "");
10640 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10641 if($MemberPair_Pos ne "lost")
10642 { # renamed
10643 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10644 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10645 if($MemberPair_Pos_Rev eq "lost")
10646 {
10647 $RenamedField{$Member_Pos}=$RenamedTo;
10648 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10649 }
10650 else {
10651 $RemovedField{$Member_Pos}=1;
10652 }
10653 }
10654 else
10655 { # removed
10656 $RemovedField{$Member_Pos}=1;
10657 }
10658 }
10659 }
10660 else
10661 { # related
10662 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10663 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10664 }
10665 }
10666 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10667 { # detect added fields
10668 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10669 next if(not $Member_Name);
10670 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);
10671 if($MemberPair_Pos eq "lost")
10672 {
10673 if(isUnnamed($Member_Name))
10674 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010675 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010676 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010677 next;
10678 }
10679 }
10680 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10681 {
10682 if(not $RenamedField_Rev{$Member_Pos})
10683 { # added
10684 $AddedField{$Member_Pos}=1;
10685 }
10686 }
10687 }
10688 }
10689 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10690 { # detect moved fields
10691 my (%RelPos, %RelPosName, %AbsPos) = ();
10692 my $Pos = 0;
10693 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10694 { # relative positions in 1st version
10695 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10696 next if(not $Member_Name);
10697 if(not $RemovedField{$Member_Pos})
10698 { # old type without removed fields
10699 $RelPos{1}{$Member_Name}=$Pos;
10700 $RelPosName{1}{$Pos} = $Member_Name;
10701 $AbsPos{1}{$Pos++} = $Member_Pos;
10702 }
10703 }
10704 $Pos = 0;
10705 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10706 { # relative positions in 2nd version
10707 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10708 next if(not $Member_Name);
10709 if(not $AddedField{$Member_Pos})
10710 { # new type without added fields
10711 $RelPos{2}{$Member_Name}=$Pos;
10712 $RelPosName{2}{$Pos} = $Member_Name;
10713 $AbsPos{2}{$Pos++} = $Member_Pos;
10714 }
10715 }
10716 foreach my $Member_Name (keys(%{$RelPos{1}}))
10717 {
10718 my $RPos1 = $RelPos{1}{$Member_Name};
10719 my $AbsPos1 = $NameToPosA{$Member_Name};
10720 my $Member_Name2 = $Member_Name;
10721 if(my $RenamedTo = $RenamedField{$AbsPos1})
10722 { # renamed
10723 $Member_Name2 = $RenamedTo;
10724 }
10725 my $RPos2 = $RelPos{2}{$Member_Name2};
10726 if($RPos2 ne "" and $RPos1 ne $RPos2)
10727 { # different relative positions
10728 my $AbsPos2 = $NameToPosB{$Member_Name2};
10729 if($AbsPos1 ne $AbsPos2)
10730 { # different absolute positions
10731 my $ProblemType = "Moved_Field";
10732 if(not isPublic(\%Type1_Pure, $AbsPos1))
10733 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010734 if($Level eq "Source") {
10735 next;
10736 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010737 $ProblemType = "Moved_Private_Field";
10738 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010739 if($Level eq "Binary"
10740 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010741 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010742 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010743 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010744 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010745 if($MemSize1 ne $MemSize2) {
10746 $ProblemType .= "_And_Size";
10747 }
10748 }
10749 if($ProblemType eq "Moved_Private_Field") {
10750 next;
10751 }
10752 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10753 "Target"=>$Member_Name,
10754 "Type_Name"=>$Type1_Pure{"Name"},
10755 "Type_Type"=>$Type1_Pure{"Type"},
10756 "Old_Value"=>$RPos1,
10757 "New_Value"=>$RPos2 );
10758 }
10759 }
10760 }
10761 }
10762 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010763 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010764 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10765 next if(not $Member_Name);
10766 if(my $RenamedTo = $RenamedField{$Member_Pos})
10767 { # renamed
10768 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10769 {
10770 if(isPublic(\%Type1_Pure, $Member_Pos))
10771 {
10772 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10773 "Target"=>$Member_Name,
10774 "Type_Name"=>$Type1_Pure{"Name"},
10775 "Type_Type"=>$Type1_Pure{"Type"},
10776 "Old_Value"=>$Member_Name,
10777 "New_Value"=>$RenamedTo );
10778 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010779 elsif(isReserved($Member_Name))
10780 {
10781 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10782 "Target"=>$Member_Name,
10783 "Type_Name"=>$Type1_Pure{"Name"},
10784 "Type_Type"=>$Type1_Pure{"Type"},
10785 "Old_Value"=>$Member_Name,
10786 "New_Value"=>$RenamedTo );
10787 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010788 }
10789 elsif($Type1_Pure{"Type"} eq "Enum")
10790 {
10791 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10792 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10793 "Type_Name"=>$Type1_Pure{"Name"},
10794 "Type_Type"=>$Type1_Pure{"Type"},
10795 "Old_Value"=>$Member_Name,
10796 "New_Value"=>$RenamedTo );
10797 }
10798 }
10799 elsif($RemovedField{$Member_Pos})
10800 { # removed
10801 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10802 {
10803 my $ProblemType = "Removed_Field";
10804 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010805 or isUnnamed($Member_Name))
10806 {
10807 if($Level eq "Source") {
10808 next;
10809 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010810 $ProblemType = "Removed_Private_Field";
10811 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010812 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010813 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010814 {
10815 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10816 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010817 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010818 { # changed offset
10819 $ProblemType .= "_And_Layout";
10820 }
10821 }
10822 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10823 { # affected size
10824 $ProblemType .= "_And_Size";
10825 }
10826 }
10827 if($ProblemType eq "Removed_Private_Field") {
10828 next;
10829 }
10830 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10831 "Target"=>$Member_Name,
10832 "Type_Name"=>$Type1_Pure{"Name"},
10833 "Type_Type"=>$Type1_Pure{"Type"} );
10834 }
10835 elsif($Type2_Pure{"Type"} eq "Union")
10836 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010837 if($Level eq "Binary"
10838 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010839 {
10840 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10841 "Target"=>$Member_Name,
10842 "Type_Name"=>$Type1_Pure{"Name"},
10843 "Type_Type"=>$Type1_Pure{"Type"} );
10844 }
10845 else
10846 {
10847 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10848 "Target"=>$Member_Name,
10849 "Type_Name"=>$Type1_Pure{"Name"},
10850 "Type_Type"=>$Type1_Pure{"Type"} );
10851 }
10852 }
10853 elsif($Type1_Pure{"Type"} eq "Enum")
10854 {
10855 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10856 "Target"=>$Member_Name,
10857 "Type_Name"=>$Type1_Pure{"Name"},
10858 "Type_Type"=>$Type1_Pure{"Type"},
10859 "Old_Value"=>$Member_Name );
10860 }
10861 }
10862 else
10863 { # changed
10864 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10865 if($Type1_Pure{"Type"} eq "Enum")
10866 {
10867 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10868 next if($Member_Value1 eq "");
10869 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10870 next if($Member_Value2 eq "");
10871 if($Member_Value1 ne $Member_Value2)
10872 {
10873 my $ProblemType = "Enum_Member_Value";
10874 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10875 $ProblemType = "Enum_Last_Member_Value";
10876 }
10877 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10878 "Target"=>$Member_Name,
10879 "Type_Name"=>$Type1_Pure{"Name"},
10880 "Type_Type"=>$Type1_Pure{"Type"},
10881 "Old_Value"=>$Member_Value1,
10882 "New_Value"=>$Member_Value2 );
10883 }
10884 }
10885 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10886 {
10887 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10888 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010889 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010890 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10891 $SizeV1 = $BSize1;
10892 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010893 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010894 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10895 $SizeV2 = $BSize2;
10896 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010897 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10898 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010899 if($Level eq "Binary"
10900 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010901 {
10902 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10903 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10904 { # field size change (including anon-structures and unions)
10905 # - same types
10906 # - unnamed types
10907 # - bitfields
10908 my $ProblemType = "Field_Size";
10909 if(not isPublic(\%Type1_Pure, $Member_Pos)
10910 or isUnnamed($Member_Name))
10911 { # should not be accessed by applications, goes to "Low Severity"
10912 # example: "abidata" members in GStreamer types
10913 $ProblemType = "Private_".$ProblemType;
10914 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010915 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010916 { # check an effect
10917 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10918 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010919 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010920 { # changed offset
10921 $ProblemType .= "_And_Layout";
10922 }
10923 }
10924 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10925 $ProblemType .= "_And_Type_Size";
10926 }
10927 }
10928 if($ProblemType eq "Private_Field_Size")
10929 { # private field size with no effect
10930 $ProblemType = "";
10931 }
10932 if($ProblemType)
10933 { # register a problem
10934 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10935 "Target"=>$Member_Name,
10936 "Type_Name"=>$Type1_Pure{"Name"},
10937 "Type_Type"=>$Type1_Pure{"Type"},
10938 "Old_Size"=>$SizeV1,
10939 "New_Size"=>$SizeV2);
10940 }
10941 }
10942 }
10943 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10944 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10945 { # do NOT check bitfield type changes
10946 next;
10947 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010948 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010949 {
10950 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10951 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10952 {
10953 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10954 "Target"=>$Member_Name,
10955 "Type_Name"=>$Type1_Pure{"Name"},
10956 "Type_Type"=>$Type1_Pure{"Type"});
10957 }
10958 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10959 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10960 {
10961 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10962 "Target"=>$Member_Name,
10963 "Type_Name"=>$Type1_Pure{"Name"},
10964 "Type_Type"=>$Type1_Pure{"Type"});
10965 }
10966 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010967 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010968 foreach my $ProblemType (keys(%Sub_SubProblems))
10969 {
10970 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10971 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10972 if($ProblemType eq "Field_Type"
10973 or $ProblemType eq "Field_Type_And_Size")
10974 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010975 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010976 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010977 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010978 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010979 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10980 if($Level eq "Source"
10981 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10982 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010983 }
10984 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010985 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10986 {
10987 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10988 if($Level eq "Source"
10989 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010990 delete($Sub_SubProblems{$ProblemType});
10991 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010992 }
10993 }
10994 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10995 {
10996 if($RA==2) {
10997 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10998 }
10999 else {
11000 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
11001 }
11002 if($Level eq "Source"
11003 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
11004 delete($Sub_SubProblems{$ProblemType});
11005 }
11006 }
11007 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
11008 {
11009 if($RR==2) {
11010 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
11011 }
11012 else {
11013 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
11014 }
11015 if($Level eq "Source"
11016 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
11017 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011018 }
11019 }
11020 }
11021 }
11022 foreach my $ProblemType (keys(%Sub_SubProblems))
11023 {
11024 my $ProblemType_Init = $ProblemType;
11025 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011026 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011027 if(not isPublic(\%Type1_Pure, $Member_Pos)
11028 or isUnnamed($Member_Name)) {
11029 $ProblemType = "Private_".$ProblemType;
11030 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011031 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011032 { # check an effect
11033 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
11034 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011035 if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011036 { # changed offset
11037 $ProblemType .= "_And_Layout";
11038 }
11039 }
11040 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11041 $ProblemType .= "_And_Type_Size";
11042 }
11043 }
11044 }
11045 else
11046 {
11047 if(not isPublic(\%Type1_Pure, $Member_Pos)
11048 or isUnnamed($Member_Name)) {
11049 next;
11050 }
11051 }
11052 if($ProblemType eq "Private_Field_Type_And_Size")
11053 { # private field change with no effect
11054 next;
11055 }
11056 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11057 "Target"=>$Member_Name,
11058 "Type_Name"=>$Type1_Pure{"Name"},
11059 "Type_Type"=>$Type1_Pure{"Type"} );
11060 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
11061 { # other properties
11062 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
11063 }
11064 }
11065 if(not isPublic(\%Type1_Pure, $Member_Pos))
11066 { # do NOT check internal type changes
11067 next;
11068 }
11069 if($MemberType1_Id and $MemberType2_Id)
11070 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011071 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011072 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
11073 {
11074 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
11075 {
11076 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
11077 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
11078 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
11079 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
11080 }
11081 if($Sub_SubLocation!~/\-\>/) {
11082 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
11083 }
11084 }
11085 }
11086 }
11087 }
11088 }
11089 }
11090 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11091 { # checking added members, public and private
11092 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11093 next if(not $Member_Name);
11094 if($AddedField{$Member_Pos})
11095 { # added
11096 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11097 {
11098 my $ProblemType = "Added_Field";
11099 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011100 or isUnnamed($Member_Name))
11101 {
11102 if($Level eq "Source") {
11103 next;
11104 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011105 $ProblemType = "Added_Private_Field";
11106 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011107 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011108 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011109 {
11110 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
11111 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011112 if(getOffset($MNum-1, \%Type2_Pure, $TypeInfo{2}, $WORD_SIZE{2})!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011113 { # changed offset
11114 $ProblemType .= "_And_Layout";
11115 }
11116 }
11117 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11118 $ProblemType .= "_And_Size";
11119 }
11120 }
11121 if($ProblemType eq "Added_Private_Field")
11122 { # skip added private fields
11123 next;
11124 }
11125 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11126 "Target"=>$Member_Name,
11127 "Type_Name"=>$Type1_Pure{"Name"},
11128 "Type_Type"=>$Type1_Pure{"Type"} );
11129 }
11130 elsif($Type2_Pure{"Type"} eq "Union")
11131 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011132 if($Level eq "Binary"
11133 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011134 {
11135 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11136 "Target"=>$Member_Name,
11137 "Type_Name"=>$Type1_Pure{"Name"},
11138 "Type_Type"=>$Type1_Pure{"Type"} );
11139 }
11140 else
11141 {
11142 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11143 "Target"=>$Member_Name,
11144 "Type_Name"=>$Type1_Pure{"Name"},
11145 "Type_Type"=>$Type1_Pure{"Type"} );
11146 }
11147 }
11148 elsif($Type2_Pure{"Type"} eq "Enum")
11149 {
11150 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11151 next if($Member_Value eq "");
11152 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11153 "Target"=>$Member_Name,
11154 "Type_Name"=>$Type2_Pure{"Name"},
11155 "Type_Type"=>$Type2_Pure{"Type"},
11156 "New_Value"=>$Member_Value );
11157 }
11158 }
11159 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011160 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011161 pop(@RecurTypes);
11162 return %SubProblems;
11163}
11164
11165sub isUnnamed($) {
11166 return $_[0]=~/\Aunnamed\d+\Z/;
11167}
11168
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011169sub get_ShortType($$)
11170{
11171 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011172 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011173 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011174 $TypeName=~s/\A$NameSpace\:\://g;
11175 }
11176 return $TypeName;
11177}
11178
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011179sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011180{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011181 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011182 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011183 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11184 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011185 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011186 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11187 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011188 return () if(not $Type{"Type"});
11189 if($Type{"Type"} ne $Type_Type)
11190 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011191 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011192 return () if(not $Type{"BaseType"}{"Tid"});
11193 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011194 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011195 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011196 return %Type;
11197}
11198
11199my %TypeSpecAttributes = (
11200 "Const" => 1,
11201 "Volatile" => 1,
11202 "ConstVolatile" => 1,
11203 "Restrict" => 1,
11204 "Typedef" => 1
11205);
11206
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011207sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011208{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011209 my ($TypeId, $Info) = @_;
11210 if(not $TypeId or not $Info
11211 or not $Info->{$TypeId}) {
11212 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011214 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11215 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11216 }
11217 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011218 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011219 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011220 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011221 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011222 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011223 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011224 return %Type;
11225}
11226
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011227sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011228{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011229 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011230 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011231 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11232 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011233 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011234 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11235 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011236 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011237 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011238 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011239 my $PointerLevel = 0;
11240 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11241 $PointerLevel += 1;
11242 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011243 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11244 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011245 return $PointerLevel;
11246}
11247
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011248sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011249{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011250 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011251 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011252 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11253 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011254 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011255 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11256 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011257 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011258 return %Type if(not $Type{"BaseType"}{"Tid"});
11259 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11260 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011261 return %Type;
11262}
11263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011264sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011266 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011267 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011268 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11269 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011270 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011271 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011272 my $Qual = "";
11273 if($Type{"Type"} eq "Pointer") {
11274 $Qual .= "*";
11275 }
11276 elsif($Type{"Type"} eq "Ref") {
11277 $Qual .= "&";
11278 }
11279 elsif($Type{"Type"} eq "ConstVolatile") {
11280 $Qual .= "const volatile";
11281 }
11282 elsif($Type{"Type"} eq "Const"
11283 or $Type{"Type"} eq "Volatile"
11284 or $Type{"Type"} eq "Restrict") {
11285 $Qual .= lc($Type{"Type"});
11286 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011287 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011288 return $BQual.$Qual;
11289}
11290
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011291sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011292{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011293 my ($TypeId, $Info) = @_;
11294 if(not $TypeId or not $Info
11295 or not $Info->{$TypeId}) {
11296 return ();
11297 }
11298 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011299 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011300 if(my $BTid = $Type{"BaseType"}{"Tid"})
11301 {
11302 if($Info->{$BTid}) {
11303 return %{$Info->{$BTid}};
11304 }
11305 else { # something is going wrong
11306 return ();
11307 }
11308 }
11309 else {
11310 return %Type;
11311 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011312}
11313
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011314sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011315{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011316 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011317 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011318 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11319 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011320}
11321
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011322sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011323{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011324 my $Symbol = $_[0];
11325 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11326}
11327
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011328sub isInLineInst($$$) {
11329 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11330}
11331
11332sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011333{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011334 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011335 if($CheckObjectsOnly)
11336 {
11337 if($Symbol!~/\A(_Z|\?)/) {
11338 return 0;
11339 }
11340 if(my $Signature = $tr_name{$Symbol})
11341 {
11342 if(index($Signature,">")==-1) {
11343 return 0;
11344 }
11345 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11346 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011347 if(index($ShortName,"<")!=-1
11348 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011349 return 1;
11350 }
11351 }
11352 }
11353 }
11354 else
11355 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011356 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011357 {
11358 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11359 {
11360 if(index($ClassName,"<")!=-1) {
11361 return 1;
11362 }
11363 }
11364 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011365 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011366 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011367 if(index($ShortName,"<")!=-1
11368 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011369 return 1;
11370 }
11371 }
11372 }
11373 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011374}
11375
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011376sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011377{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011378 my ($Symbol, $SInfo, $LibVersion) = @_;
11379 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011380 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011381 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011382 { # class specialization
11383 return 1;
11384 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011385 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011386 { # method specialization
11387 return 1;
11388 }
11389 }
11390 return 0;
11391}
11392
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011393sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011394{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011395 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011396 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011397 { # non-public global data
11398 return 0;
11399 }
11400 if($CheckObjectsOnly) {
11401 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11402 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011403 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011404 { # support for old ABI dumps in --headers-only mode
11405 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11406 {
11407 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11408 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011409 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011410 if(not $PType or $PType eq "Unknown") {
11411 return 0;
11412 }
11413 }
11414 }
11415 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011416 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011417 {
11418 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011419 if($SkipSymbols{$LibVersion}{$Symbol})
11420 { # user defined symbols to ignore
11421 return 0;
11422 }
11423 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11424 if(not $NameSpace and $ClassId)
11425 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011426 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011427 }
11428 if($NameSpace)
11429 { # user defined namespaces to ignore
11430 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11431 return 0;
11432 }
11433 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11434 { # nested namespaces
11435 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11436 return 0;
11437 }
11438 }
11439 }
11440 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11441 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011442 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011443 { # --skip-headers or <skip_headers> (not <skip_including>)
11444 if($Skip==1) {
11445 return 0;
11446 }
11447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011448 }
11449 if($SymbolsListPath and not $SymbolsList{$Symbol})
11450 { # user defined symbols
11451 return 0;
11452 }
11453 if($AppPath and not $SymbolsList_App{$Symbol})
11454 { # user defined symbols (in application)
11455 return 0;
11456 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011457 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11458 { # non-target symbols
11459 return 0;
11460 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011461 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011462 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011463 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011464 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011465 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011466 return 0;
11467 }
11468 }
11469 else
11470 {
11471 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011472 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011473 {
11474 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11475 { # inline virtual methods
11476 if($Type=~/InlineVirt/) {
11477 return 1;
11478 }
11479 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11480 if(not $Allocable)
11481 { # check bases
11482 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11483 {
11484 if(not isCopyingClass($DCId, $LibVersion))
11485 { # exists a derived class without default c-tor
11486 $Allocable=1;
11487 last;
11488 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011489 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011490 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011491 if(not $Allocable) {
11492 return 0;
11493 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011494 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011495 else
11496 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011497 return 0;
11498 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011500 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011501 }
11502 }
11503 return 1;
11504}
11505
11506sub mergeImpl()
11507{
11508 my $DiffCmd = get_CmdPath("diff");
11509 if(not $DiffCmd) {
11510 exitStatus("Not_Found", "can't find \"diff\"");
11511 }
11512 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11513 { # implementation changes
11514 next if($CompleteSignature{1}{$Interface}{"Private"});
11515 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11516 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011517 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11518 next;
11519 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011520 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011522 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011523 next if(not $Impl2);
11524 if($Impl1 ne $Impl2)
11525 {
11526 writeFile("$TMP_DIR/impl1", $Impl1);
11527 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011528 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011529 $Diff=~s/(---|\+\+\+).+\n//g;
11530 $Diff=~s/[ ]{3,}/ /g;
11531 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011532 unlink("$TMP_DIR/impl1");
11533 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011534 %{$ImplProblems{$Interface}}=(
11535 "Diff" => get_CodeView($Diff) );
11536 }
11537 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011538
11539 # clean memory
11540 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011541}
11542
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011543sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011544{
11545 my $FuncBody= $_[0];
11546 return "" if(not $FuncBody);
11547 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11548 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11549 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11550 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11551 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11552 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11553 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11554 $FuncBody=~s/\.L\d+/.L/g;
11555 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11556 $FuncBody=~s/[\n]{2,}/\n/g;
11557 return $FuncBody;
11558}
11559
11560sub get_CodeView($)
11561{
11562 my $Code = $_[0];
11563 my $View = "";
11564 foreach my $Line (split(/\n/, $Code))
11565 {
11566 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011567 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011568 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11569 }
11570 else {
11571 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11572 }
11573 }
11574 return "<table class='code_view'>$View</table>\n";
11575}
11576
11577sub getImplementations($$)
11578{
11579 my ($LibVersion, $Path) = @_;
11580 return if(not $LibVersion or not -e $Path);
11581 if($OSgroup eq "macos")
11582 {
11583 my $OtoolCmd = get_CmdPath("otool");
11584 if(not $OtoolCmd) {
11585 exitStatus("Not_Found", "can't find \"otool\"");
11586 }
11587 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011588 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011589 {
11590 if($Line=~/\A\s*_(\w+)\s*:/i) {
11591 $CurInterface = $1;
11592 }
11593 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011594 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011595 }
11596 }
11597 }
11598 else
11599 {
11600 my $ObjdumpCmd = get_CmdPath("objdump");
11601 if(not $ObjdumpCmd) {
11602 exitStatus("Not_Found", "can't find \"objdump\"");
11603 }
11604 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011605 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 {
11607 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11608 $CurInterface = $1;
11609 }
11610 else
11611 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11612 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11613 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011614 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011615 }
11616 }
11617 }
11618 }
11619}
11620
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011621sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011622{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011623 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011624 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11625 {
11626 if(link_symbol($Symbol, 1, "+Deps"))
11627 { # linker can find a new symbol
11628 # in the old-version library
11629 # So, it's not a new symbol
11630 next;
11631 }
11632 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011633 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011634 next;
11635 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011637 }
11638}
11639
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011640sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011641{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011642 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011643 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11644 {
11645 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011646 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011647 }
11648 if(link_symbol($Symbol, 2, "+Deps"))
11649 { # linker can find an old symbol
11650 # in the new-version library
11651 next;
11652 }
11653 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011654 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011655 next;
11656 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011657 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011658 }
11659}
11660
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011661sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011662{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011663 my $Level = $_[0];
11664 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011665 { # checking added symbols
11666 next if($CompleteSignature{2}{$Symbol}{"Private"});
11667 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011668 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011669 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011671 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011672 { # checking removed symbols
11673 next if($CompleteSignature{1}{$Symbol}{"Private"});
11674 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011675 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011676 { # skip v-tables for templates, that should not be imported by applications
11677 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011678 if(my $CName = $VTableClass{$Symbol})
11679 {
11680 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11681 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011682 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011683 next;
11684 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011685 }
11686 }
11687 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011688 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011689 }
11690 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11691 { # symbols for pure virtual methods cannot be called by clients
11692 next;
11693 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011694 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011695 }
11696}
11697
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011698sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011699{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011700 my ($LibVersion, $V) = @_;
11701 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11702 return $Cache{"checkDump"}{$LibVersion}{$V};
11703 }
11704 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011705}
11706
11707sub detectAdded_H($)
11708{
11709 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011710 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11711 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011712 if($Level eq "Source")
11713 { # remove symbol version
11714 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11715 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011716
11717 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11718 { # skip artificial constructors
11719 next;
11720 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011721 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011722 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11723 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011724 next;
11725 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011726 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011727 next;
11728 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011729 if(not defined $CompleteSignature{1}{$Symbol}
11730 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11731 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011732 if($UsedDump{2}{"SrcBin"})
11733 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011734 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011735 { # support for old and different (!) ABI dumps
11736 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11737 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011738 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011739 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011740 {
11741 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11742 {
11743 if($Lang eq "C")
11744 { # support for old ABI dumps: missed extern "C" functions
11745 next;
11746 }
11747 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011748 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011749 else
11750 {
11751 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011752 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011753 next;
11754 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011755 }
11756 }
11757 }
11758 }
11759 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011760 }
11761 }
11762}
11763
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011764sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011765{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011766 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011767 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11768 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011769 if($Level eq "Source")
11770 { # remove symbol version
11771 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11772 $Symbol=$SN;
11773 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011774 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11775 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011776 next;
11777 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011778 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011779 next;
11780 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011781 if(not defined $CompleteSignature{2}{$Symbol}
11782 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011783 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011784 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011785 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011786 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011787 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011788 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11789 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011790 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011791 if($CheckHeadersOnly)
11792 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011793 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11794 {
11795 if($Lang eq "C")
11796 { # support for old ABI dumps: missed extern "C" functions
11797 next;
11798 }
11799 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011801 else
11802 {
11803 if(not link_symbol($Symbol, 1, "-Deps"))
11804 { # skip removed inline symbols
11805 next;
11806 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011807 }
11808 }
11809 }
11810 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011811 if(not checkDump(1, "2.15"))
11812 {
11813 if($Symbol=~/_IT_E\Z/)
11814 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11815 next;
11816 }
11817 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011818 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11819 {
11820 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11821 {
11822 if(defined $Constants{2}{$Short})
11823 {
11824 my $Val = $Constants{2}{$Short}{"Value"};
11825 if(defined $Func_ShortName{2}{$Val})
11826 { # old name defined to new
11827 next;
11828 }
11829 }
11830 }
11831
11832 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011833 $RemovedInt{$Level}{$Symbol} = 1;
11834 if($Level eq "Source")
11835 { # search for a source-compatible equivalent
11836 setAlternative($Symbol, $Level);
11837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011838 }
11839 }
11840}
11841
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011842sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011843{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011844 my $Level = $_[0];
11845 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011846 { # checking added symbols
11847 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011848 next if($CompleteSignature{2}{$Symbol}{"Private"});
11849 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011850 if($Level eq "Binary")
11851 {
11852 if($CompleteSignature{2}{$Symbol}{"InLine"})
11853 {
11854 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11855 { # skip inline non-virtual functions
11856 next;
11857 }
11858 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011859 }
11860 else
11861 { # Source
11862 if($SourceAlternative_B{$Symbol}) {
11863 next;
11864 }
11865 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011866 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011867 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011868 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011869 { # checking removed symbols
11870 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011871 next if($CompleteSignature{1}{$Symbol}{"Private"});
11872 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011873 if($Level eq "Binary")
11874 {
11875 if($CompleteSignature{1}{$Symbol}{"InLine"})
11876 {
11877 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11878 { # skip inline non-virtual functions
11879 next;
11880 }
11881 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011882 }
11883 else
11884 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011885 if(my $Alt = $SourceAlternative{$Symbol})
11886 {
11887 if(defined $CompleteSignature{1}{$Alt}
11888 and $CompleteSignature{1}{$Symbol}{"Const"})
11889 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011890 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011891 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011892 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011893 "Type_Type"=>"Class",
11894 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011895 }
11896 else
11897 { # do NOT show removed symbol
11898 next;
11899 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011900 }
11901 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011902 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903 }
11904}
11905
11906sub addParamNames($)
11907{
11908 my $LibraryVersion = $_[0];
11909 return if(not keys(%AddIntParams));
11910 my $SecondVersion = $LibraryVersion==1?2:1;
11911 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11912 {
11913 next if(not keys(%{$AddIntParams{$Interface}}));
11914 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011915 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011916 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11917 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011918 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011919 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11920 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11921 {
11922 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11923 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11924 }
11925 }
11926 else {
11927 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11928 }
11929 }
11930 }
11931 }
11932}
11933
11934sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011935{ # detect changed typedefs to show
11936 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011937 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11938 {
11939 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011940 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11941 if(not $BName1 or isAnon($BName1)) {
11942 next;
11943 }
11944 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11945 if(not $BName2 or isAnon($BName2)) {
11946 next;
11947 }
11948 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011949 $ChangedTypedef{$Typedef} = 1;
11950 }
11951 }
11952}
11953
11954sub get_symbol_suffix($$)
11955{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011956 my ($Symbol, $Full) = @_;
11957 my ($SN, $SO, $SV) = separate_symbol($Symbol);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040011958 $Symbol=$SN; # remove version
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011959 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011960 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011961 if(not $Full) {
11962 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11963 }
11964 return $Suffix;
11965}
11966
11967sub get_symbol_prefix($$)
11968{
11969 my ($Symbol, $LibVersion) = @_;
11970 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11971 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11972 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011973 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011974 }
11975 return $ShortName;
11976}
11977
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011978sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011979{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011980 my $Symbol = $_[0];
11981 my $PSymbol = $Symbol;
11982 if(not defined $CompleteSignature{2}{$PSymbol}
11983 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11984 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11985 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011986 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011987 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011988 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011989 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011990 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11991 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011992 {
11993 if(defined $CompleteSignature{2}{$PSymbol}
11994 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11995 {
11996 $SourceAlternative{$Symbol} = $PSymbol;
11997 $SourceAlternative_B{$PSymbol} = $Symbol;
11998 if(not defined $CompleteSignature{1}{$PSymbol}
11999 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
12000 $SourceReplacement{$Symbol} = $PSymbol;
12001 }
12002 }
12003 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012004 }
12005 else
12006 {
12007 foreach my $Sp ("KV", "VK", "K", "V")
12008 {
12009 if($PSymbol=~s/\A_ZN$Sp/_ZN/
12010 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
12011 {
12012 if(defined $CompleteSignature{2}{$PSymbol}
12013 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
12014 {
12015 $SourceAlternative{$Symbol} = $PSymbol;
12016 $SourceAlternative_B{$PSymbol} = $Symbol;
12017 if(not defined $CompleteSignature{1}{$PSymbol}
12018 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
12019 $SourceReplacement{$Symbol} = $PSymbol;
12020 }
12021 }
12022 }
12023 $PSymbol = $Symbol;
12024 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012025 }
12026 }
12027 }
12028 return "";
12029}
12030
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012031sub getSymKind($$)
12032{
12033 my ($Symbol, $LibVersion) = @_;
12034 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
12035 {
12036 return "Global_Data";
12037 }
12038 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
12039 {
12040 return "Method";
12041 }
12042 return "Function";
12043}
12044
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012045sub mergeSignatures($)
12046{
12047 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012048 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012049
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012050 mergeBases($Level);
12051
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012052 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012053 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012054 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012055 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012056 next;
12057 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012058 if(defined $CompleteSignature{1}{$Symbol}
12059 and $CompleteSignature{1}{$Symbol}{"Header"})
12060 { # double-check added symbol
12061 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012062 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012063 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012064 next;
12065 }
12066 if($Symbol=~/\A(_Z|\?)/)
12067 { # C++
12068 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
12069 }
12070 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
12071 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012072 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
12073 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012074 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012075 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012076 {
12077 if($TName_Tid{1}{$AffectedClass_Name})
12078 { # class should exist in previous version
12079 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
12080 { # old v-table is NOT copied by old applications
12081 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
12082 "Type_Name"=>$AffectedClass_Name,
12083 "Type_Type"=>"Class",
12084 "Target"=>get_Signature($Symbol, 2),
12085 "Old_Value"=>get_Signature($OverriddenMethod, 2),
12086 "New_Value"=>get_Signature($Symbol, 2) );
12087 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012089 }
12090 }
12091 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012092 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
12093 { # check all removed exported symbols
12094 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012095 next;
12096 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012097 if(defined $CompleteSignature{2}{$Symbol}
12098 and $CompleteSignature{2}{$Symbol}{"Header"})
12099 { # double-check removed symbol
12100 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012101 }
12102 if($CompleteSignature{1}{$Symbol}{"Private"})
12103 { # skip private methods
12104 next;
12105 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012106 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012107 next;
12108 }
12109 $CheckedSymbols{$Level}{$Symbol} = 1;
12110 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
12111 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012112 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
12113 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012114 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012115 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
12116 {
12117 if($TName_Tid{2}{$AffectedClass_Name})
12118 { # class should exist in newer version
12119 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12120 { # old v-table is NOT copied by old applications
12121 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12122 "Type_Name"=>$AffectedClass_Name,
12123 "Type_Type"=>"Class",
12124 "Target"=>get_Signature($OverriddenMethod, 1),
12125 "Old_Value"=>get_Signature($Symbol, 1),
12126 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12127 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012128 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012129 }
12130 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012131 if($Level eq "Binary"
12132 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012133 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012134 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012135 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012136 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012137 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012138 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012139 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012140 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012141 {
12142 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12143 "Target"=>$tr_name{$Symbol},
12144 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012145 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012146 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012147 else
12148 {
12149 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12150 "Target"=>$tr_name{$Symbol},
12151 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012152 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012153 }
12154 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012155 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012156 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012157 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012158 {
12159 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12160 "Target"=>$tr_name{$Symbol},
12161 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012162 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012163 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012164 else
12165 {
12166 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12167 "Target"=>$tr_name{$Symbol},
12168 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012169 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012170 }
12171 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012172 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12173 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12174 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12175 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12176 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012177 {
12178 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012179 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012180 $ProblemType = "Global_Data_Symbol_Changed_Type";
12181 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012182 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12183 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012184 "Old_Type"=>$RTName1,
12185 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012186 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012187 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012188 }
12189 }
12190 }
12191 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012192 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012193 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012194 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012195 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012196 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012197 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012198 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012199 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12200 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012201 if($Symbol=~/(C1E|C2E)/)
12202 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012203 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012204 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012205 }
12206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012207 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12208 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012209 if($Symbol=~/(D0E|D1E|D2E)/)
12210 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012211 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012212 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012213 }
12214 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012215 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012216 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012217 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012218 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012219 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012220 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012221 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012222 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012223 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012224 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012225 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012226 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012227 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012228 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012229 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012230 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012231 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012232 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012233 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012234 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012235 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012236 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012237 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012238 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012239 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012240 { # "volatile" to non-"volatile"
12241
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012242 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012243 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012244 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012245 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012246 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012247 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012248 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012249 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012250 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012251 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012252 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012253 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012254 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012255 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012256 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012257 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012258 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012259 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12260 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012261 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012262 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012263 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012264 }
12265 }
12266 }
12267 }
12268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012269 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12270 { # checking symbols
12271 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12272 if($Level eq "Source")
12273 { # remove symbol version
12274 $Symbol=$SN;
12275 }
12276 else
12277 { # Binary
12278 if(not $SV)
12279 { # symbol without version
12280 if(my $VSym = $SymVer{1}{$Symbol})
12281 { # the symbol is linked with versioned symbol
12282 if($CompleteSignature{2}{$VSym}{"MnglName"})
12283 { # show report for symbol@ver only
12284 next;
12285 }
12286 elsif(not link_symbol($VSym, 2, "-Deps"))
12287 { # changed version: sym@v1 to sym@v2
12288 # do NOT show report for symbol
12289 next;
12290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012291 }
12292 }
12293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012294 my $PSymbol = $Symbol;
12295 if($Level eq "Source"
12296 and my $S = $SourceReplacement{$Symbol})
12297 { # take a source-compatible replacement function
12298 $PSymbol = $S;
12299 }
12300 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012301 { # private symbols
12302 next;
12303 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012304 if(not defined $CompleteSignature{1}{$Symbol}
12305 or not defined $CompleteSignature{2}{$PSymbol})
12306 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012307 next;
12308 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012309 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12310 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12311 { # no mangled name
12312 next;
12313 }
12314 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12315 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012316 { # without a header
12317 next;
12318 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012319
12320 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12321 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12322 { # became pure
12323 next;
12324 }
12325 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12326 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12327 { # became non-pure
12328 next;
12329 }
12330
12331 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12332 { # exported, target, inline virtual and pure virtual
12333 next;
12334 }
12335 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12336 { # exported, target, inline virtual and pure virtual
12337 next;
12338 }
12339
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012340 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012341 {
12342 if($CompleteSignature{1}{$Symbol}{"Data"}
12343 and $CompleteSignature{2}{$PSymbol}{"Data"})
12344 {
12345 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12346 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12347 if(defined $Value1)
12348 {
12349 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12350 if(defined $Value2)
12351 {
12352 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12353 if($Value1 ne $Value2)
12354 {
12355 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12356 "Old_Value"=>$Value1,
12357 "New_Value"=>$Value2,
12358 "Target"=>get_Signature($Symbol, 1) );
12359 }
12360 }
12361 }
12362 }
12363 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012364
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012365 if($CompleteSignature{2}{$PSymbol}{"Private"})
12366 {
12367 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12368 "Target"=>get_Signature_M($PSymbol, 2) );
12369 }
12370 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12371 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12372 {
12373 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12374 "Target"=>get_Signature_M($PSymbol, 2) );
12375 }
12376 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12377 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12378 {
12379 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12380 "Target"=>get_Signature_M($PSymbol, 2) );
12381 }
12382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012383 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012384 mergeVirtualTables($Symbol, $Level);
12385
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012386 if($COMPILE_ERRORS)
12387 { # if some errors occurred at the compiling stage
12388 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012389 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012390 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 { # missed information about parameters in newer version
12392 next;
12393 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012394 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012395 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012396 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012397 next;
12398 }
12399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012400 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012401 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012402 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012403 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12404 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012405 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12406 "Target"=>get_Signature($Symbol, 1)
12407 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012408 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012409 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012410 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12411 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012412 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12413 "Target"=>get_Signature($Symbol, 1)
12414 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012415 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012416 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12417 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012418 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012419 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012420 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012421 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12422 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12423 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012424 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012425 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012426 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12427 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012428 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012429 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012430 my $ProblemType = "Virtual_Method_Position";
12431 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12432 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012434 if(isUsedClass($Class_Id, 1, $Level))
12435 {
12436 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012437 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012438 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012439 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12440 next;
12441 }
12442 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012443 "Type_Name"=>$Class_Type{"Name"},
12444 "Type_Type"=>"Class",
12445 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12446 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12447 "Target"=>get_Signature($Symbol, 1) );
12448 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012449 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012450 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 }
12452 }
12453 }
12454 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012455 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12456 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012457 { # do NOT check type changes in pure virtuals
12458 next;
12459 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012460 $CheckedSymbols{$Level}{$Symbol}=1;
12461 if($Symbol=~/\A(_Z|\?)/
12462 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012463 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012464 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012465 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012466 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012467 }
12468 }
12469 else
12470 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012471 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012472 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012473 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012474 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12475 last if($PType2_Name eq "...");
12476 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12477 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012478 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012479 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012480 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012481 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12482 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012483 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12484 $ParamPos_Prev = "lost";
12485 }
12486 }
12487 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012488 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012489 }
12490 if($ParamPos_Prev eq "lost")
12491 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012492 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012493 {
12494 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012495 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012496 $ProblemType = "Added_Unnamed_Parameter";
12497 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012498 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012499 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012500 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012501 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012502 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012503 }
12504 else
12505 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012506 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012507 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012508 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012509 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12510 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012511 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012512 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012513 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012514 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012515 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012516 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012517 "Param_Type"=>$PType2_Name,
12518 "Old_Value"=>$PName_Old,
12519 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012520 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012521 }
12522 }
12523 else
12524 {
12525 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012526 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012527 $ProblemType = "Added_Middle_Unnamed_Parameter";
12528 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012529 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012530 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012531 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012532 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012533 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012534 }
12535 }
12536 }
12537 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012538 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012539 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012540 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012541 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012542 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012543 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012544 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012545 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012546 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012547 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12548 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012549 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012550 }
12551 }
12552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012553 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012554 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012555 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012556 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12557 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012558 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12559 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012560 my $ParamPos_New = "-1";
12561 if($Parameter_Name=~/\Ap\d+\Z/i)
12562 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012563 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12564 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012565 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12566 $ParamPos_New = "lost";
12567 }
12568 }
12569 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012570 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012571 }
12572 if($ParamPos_New eq "lost")
12573 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012574 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012575 {
12576 my $ProblemType = "Removed_Parameter";
12577 if($Parameter_Name=~/\Ap\d+\Z/) {
12578 $ProblemType = "Removed_Unnamed_Parameter";
12579 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012580 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012581 "Target"=>$Parameter_Name,
12582 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012583 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012584 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012585 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012586 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012587 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012588 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012589 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012590 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012591 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012592 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012593 {
12594 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12595 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012596 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012597 "Target"=>$Parameter_Name,
12598 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012599 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012600 "Old_Value"=>$Parameter_Name,
12601 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012602 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012603 }
12604 }
12605 else
12606 {
12607 my $ProblemType = "Removed_Middle_Parameter";
12608 if($Parameter_Name=~/\Ap\d+\Z/) {
12609 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12610 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012611 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012612 "Target"=>$Parameter_Name,
12613 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012614 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012615 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012616 }
12617 }
12618 }
12619 }
12620 }
12621 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012622 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12623 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12624 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012625 foreach my $SubProblemType (keys(%SubProblems))
12626 {
12627 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12628 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12629 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012630 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012631
12632 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012633 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012634 $NewProblemType = "Global_Data_Type_And_Size";
12635 }
12636 elsif($SubProblemType eq "Return_Type")
12637 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012638 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012639 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012640 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012641 { # const -> non-const global data
12642 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012643 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012644 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012645 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012646 { # non-const -> const global data
12647 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012648 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012649 }
12650 else {
12651 $NewProblemType = "Global_Data_Type";
12652 }
12653 }
12654 else
12655 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012656 if(addedQual($Old_Value, $New_Value, "const"))
12657 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012658 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012659 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012660 }
12661 }
12662 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012663 elsif($SubProblemType eq "Return_Type_Format")
12664 {
12665 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12666 $NewProblemType = "Global_Data_Type_Format";
12667 }
12668 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012669 if($Level eq "Binary"
12670 and not $CompleteSignature{1}{$Symbol}{"Data"})
12671 {
12672 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12673 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12674 { # if one of the architectures is unknown
12675 # then set other arhitecture to unknown too
12676 ($Arch1, $Arch2) = ("unknown", "unknown");
12677 }
12678 my (%Conv1, %Conv2) = ();
12679 if($UseConv_Real{1} and $UseConv_Real{1})
12680 {
12681 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12682 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12683 }
12684 else
12685 {
12686 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12687 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12688 }
12689
12690 if($SubProblemType eq "Return_Type_Became_Void")
12691 {
12692 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12693 { # parameters stack has been affected
12694 if($Conv1{"Method"} eq "stack") {
12695 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12696 }
12697 elsif($Conv1{"Hidden"}) {
12698 $NewProblemType = "Return_Type_Became_Void_And_Register";
12699 }
12700 }
12701 }
12702 elsif($SubProblemType eq "Return_Type_From_Void")
12703 {
12704 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12705 { # parameters stack has been affected
12706 if($Conv2{"Method"} eq "stack") {
12707 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12708 }
12709 elsif($Conv2{"Hidden"}) {
12710 $NewProblemType = "Return_Type_From_Void_And_Register";
12711 }
12712 }
12713 }
12714 elsif($SubProblemType eq "Return_Type"
12715 or $SubProblemType eq "Return_Type_And_Size"
12716 or $SubProblemType eq "Return_Type_Format")
12717 {
12718 if($Conv1{"Method"} ne $Conv2{"Method"})
12719 {
12720 if($Conv1{"Method"} eq "stack")
12721 { # returns in a register instead of a hidden first parameter
12722 $NewProblemType = "Return_Type_From_Stack_To_Register";
12723 }
12724 else {
12725 $NewProblemType = "Return_Type_From_Register_To_Stack";
12726 }
12727 }
12728 else
12729 {
12730 if($Conv1{"Method"} eq "reg")
12731 {
12732 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12733 {
12734 if($Conv1{"Hidden"}) {
12735 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12736 }
12737 elsif($Conv2{"Hidden"}) {
12738 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12739 }
12740 else {
12741 $NewProblemType = "Return_Type_And_Register";
12742 }
12743 }
12744 }
12745 }
12746 }
12747 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012748 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012749 if(defined $AddProblemType) {
12750 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12751 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012752 }
12753 if($ReturnType1_Id and $ReturnType2_Id)
12754 {
12755 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012756 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012757 foreach my $SubProblemType (keys(%SubProblems))
12758 { # add "Global_Data_Size" problem
12759 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12760 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12761 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012762 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012763 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012764 { # add a new problem
12765 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12766 }
12767 }
12768 foreach my $SubProblemType (keys(%SubProblems))
12769 {
12770 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12771 {
12772 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012773 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012774 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012775 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012776 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012777 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012778 }
12779 }
12780 }
12781 }
12782
12783 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012784 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12785 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12786 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012787 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012788 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012789 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12790 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012791 if($ThisPtr1_Id and $ThisPtr2_Id)
12792 {
12793 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012794 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012795 foreach my $SubProblemType (keys(%SubProblems))
12796 {
12797 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12798 {
12799 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012800 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012801 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012802 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012803 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012804 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012805 }
12806 }
12807 }
12808 }
12809 }
12810 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012811 if($Level eq "Binary") {
12812 mergeVTables($Level);
12813 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012814 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12815 $CheckedSymbols{$Level}{$Symbol} = 1;
12816 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012817}
12818
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012819sub rmQuals($$)
12820{
12821 my ($Value, $Qual) = @_;
12822 if(not $Qual) {
12823 return $Value;
12824 }
12825 if($Qual eq "all")
12826 { # all quals
12827 $Qual = "const|volatile|restrict";
12828 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012829 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012830 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012831 }
12832 return $Value;
12833}
12834
12835sub cmpBTypes($$$$)
12836{
12837 my ($T1, $T2, $V1, $V2) = @_;
12838 $T1 = uncover_typedefs($T1, $V1);
12839 $T2 = uncover_typedefs($T2, $V2);
12840 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12841}
12842
12843sub addedQual($$$)
12844{
12845 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012846 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012847}
12848
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012849sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012850{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012851 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012852 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012853}
12854
12855sub removedQual_($$$$$)
12856{
12857 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12858 $Old_Value = uncover_typedefs($Old_Value, $V1);
12859 $New_Value = uncover_typedefs($New_Value, $V2);
12860 if($Old_Value eq $New_Value)
12861 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012862 return 0;
12863 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012864 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012865 { # without a qual
12866 return 0;
12867 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012868 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012869 { # became non-qual
12870 return 1;
12871 }
12872 else
12873 {
12874 my @BQ1 = getQualModel($Old_Value, $Qual);
12875 my @BQ2 = getQualModel($New_Value, $Qual);
12876 foreach (0 .. $#BQ1)
12877 { # removed qual
12878 if($BQ1[$_]==1
12879 and $BQ2[$_]!=1)
12880 {
12881 return 2;
12882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012883 }
12884 }
12885 return 0;
12886}
12887
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012888sub getQualModel($$)
12889{
12890 my ($Value, $Qual) = @_;
12891 if(not $Qual) {
12892 return $Value;
12893 }
12894
12895 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012896 while($Value=~/(\w+)/ and $1 ne $Qual) {
12897 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012898 }
12899 $Value=~s/[^\*\&\w]+//g;
12900
12901 # modeling
12902 # int*const*const == 011
12903 # int**const == 001
12904 my @Model = ();
12905 my @Elems = split(/[\*\&]/, $Value);
12906 if(not @Elems) {
12907 return (0);
12908 }
12909 foreach (@Elems)
12910 {
12911 if($_ eq $Qual) {
12912 push(@Model, 1);
12913 }
12914 else {
12915 push(@Model, 0);
12916 }
12917 }
12918
12919 return @Model;
12920}
12921
12922sub showVal($$$)
12923{
12924 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012925 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012926 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012927 if(substr($Value, 0, 2) eq "_Z")
12928 {
12929 if(my $Unmangled = $tr_name{$Value}) {
12930 return $Unmangled;
12931 }
12932 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012933 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012934 { # strings
12935 return "\"$Value\"";
12936 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012937 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012938 { # characters
12939 return "\'$Value\'";
12940 }
12941 return $Value;
12942}
12943
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012944sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012945{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012946 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012947 if(not $Symbol) {
12948 return;
12949 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012950 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12951 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12952 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12953 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012954 if(not $PType1_Id
12955 or not $PType2_Id) {
12956 return;
12957 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012958 my %Type1 = get_Type($PType1_Id, 1);
12959 my %Type2 = get_Type($PType2_Id, 2);
12960 my %BaseType1 = get_BaseType($PType1_Id, 1);
12961 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012962 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012963 if($Level eq "Binary")
12964 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012965 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012966 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12967 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12968 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12969 {
12970 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012971 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012972 "Param_Pos"=>$ParamPos1 );
12973 }
12974 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12975 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12976 {
12977 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012978 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012979 "Param_Pos"=>$ParamPos1 );
12980 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012981 }
12982 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012983 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012984 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012985 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12986 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012987 if(not checkDump(1, "2.13")
12988 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012989 { # support for old ABI dumps
12990 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012991 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012992 if($Type1{"Name"} eq "bool"
12993 and $Value_Old eq "false" and $Value_New eq "0")
12994 { # int class::method ( bool p = 0 );
12995 # old ABI dumps: "false"
12996 # new ABI dumps: "0"
12997 $Value_Old = "0";
12998 }
12999 }
13000 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013001 if(not checkDump(1, "2.18")
13002 and checkDump(2, "2.18"))
13003 { # support for old ABI dumps
13004 if(not defined $Value_Old
13005 and substr($Value_New, 0, 2) eq "_Z") {
13006 $Value_Old = $Value_New;
13007 }
13008 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013009 if(defined $Value_Old)
13010 {
13011 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
13012 if(defined $Value_New)
13013 {
13014 $Value_New = showVal($Value_New, $PType2_Id, 2);
13015 if($Value_Old ne $Value_New)
13016 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013017 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013018 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013019 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013020 "Old_Value"=>$Value_Old,
13021 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013022 }
13023 }
13024 else
13025 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013026 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013027 "Target"=>$PName1,
13028 "Param_Pos"=>$ParamPos1,
13029 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013030 }
13031 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013032 elsif(defined $Value_New)
13033 {
13034 $Value_New = showVal($Value_New, $PType2_Id, 2);
13035 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
13036 "Target"=>$PName1,
13037 "Param_Pos"=>$ParamPos1,
13038 "New_Value"=>$Value_New );
13039 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013040 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013041 if($PName1 and $PName2 and $PName1 ne $PName2
13042 and $PType1_Id!=-1 and $PType2_Id!=-1
13043 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013044 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013045 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013046 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013047 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013048 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013049 "Old_Value"=>$PName1,
13050 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013051 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013052 }
13053 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013054 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013055 foreach my $SubProblemType (keys(%SubProblems))
13056 { # add new problems, remove false alarms
13057 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13058 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
13059 if($SubProblemType eq "Parameter_Type")
13060 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013061 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013062 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013063 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013064 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013065 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
13066 if($Level eq "Source"
13067 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013068 delete($SubProblems{$SubProblemType});
13069 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013070 }
13071 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
13072 {
13073 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
13074 if($Level eq "Source"
13075 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013076 delete($SubProblems{$SubProblemType});
13077 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013078 }
13079 }
13080 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
13081 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13082 { # int to "int const"
13083 delete($SubProblems{$SubProblemType});
13084 }
13085 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
13086 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13087 { # "int const" to int
13088 delete($SubProblems{$SubProblemType});
13089 }
13090 }
13091 }
13092 foreach my $SubProblemType (keys(%SubProblems))
13093 { # modify/register problems
13094 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13095 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013096 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
13097 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013098 my $NewProblemType = $SubProblemType;
13099 if($Old_Value eq "..." and $New_Value ne "...")
13100 { # change from "..." to "int"
13101 if($ParamPos1==0)
13102 { # ISO C requires a named argument before "..."
13103 next;
13104 }
13105 $NewProblemType = "Parameter_Became_NonVaList";
13106 }
13107 elsif($New_Value eq "..." and $Old_Value ne "...")
13108 { # change from "int" to "..."
13109 if($ParamPos2==0)
13110 { # ISO C requires a named argument before "..."
13111 next;
13112 }
13113 $NewProblemType = "Parameter_Became_VaList";
13114 }
13115 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013116 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013117 { # parameter: "const" to non-"const"
13118 $NewProblemType = "Parameter_Became_Non_Const";
13119 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013120 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013121 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013122 {
13123 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013124 if($Arch1 eq "unknown"
13125 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013126 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013127 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 ($Arch1, $Arch2) = ("unknown", "unknown");
13129 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013130 my (%Conv1, %Conv2) = ();
13131 if($UseConv_Real{1} and $UseConv_Real{1})
13132 { # real
13133 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13134 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13135 }
13136 else
13137 { # model
13138 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13139 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13140 }
13141 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013142 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013143 if($Conv1{"Method"} eq "stack")
13144 {
13145 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13146 $NewProblemType = "Parameter_Type_And_Stack";
13147 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013148 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013149 elsif($Conv1{"Method"} eq "reg")
13150 {
13151 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13152 $NewProblemType = "Parameter_Type_And_Register";
13153 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013154 }
13155 }
13156 else
13157 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013158 if($Conv1{"Method"} eq "stack") {
13159 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013160 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013161 elsif($Conv1{"Method"} eq "register") {
13162 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013163 }
13164 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013165 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13166 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013167 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013168 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013169 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013170 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013171 "New_Signature"=>get_Signature($Symbol, 2) );
13172 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013173 }
13174 @RecurTypes = ();
13175 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013176 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013177 foreach my $SubProblemType (keys(%SubProblems_Merge))
13178 {
13179 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13180 {
13181 my $NewProblemType = $SubProblemType;
13182 if($SubProblemType eq "DataType_Size")
13183 {
13184 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13185 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13186 { # stack has been affected
13187 $NewProblemType = "DataType_Size_And_Stack";
13188 }
13189 }
13190 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013191 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013192 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013193 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013194 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013195 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013196 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013197 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013198 }
13199 }
13200 }
13201}
13202
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013203sub find_ParamPair_Pos_byName($$$)
13204{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013205 my ($Name, $Symbol, $LibVersion) = @_;
13206 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013207 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013208 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13209 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013210 {
13211 return $ParamPos;
13212 }
13213 }
13214 return "lost";
13215}
13216
13217sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13218{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013219 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013220 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013221 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013222 {
13223 next if($Order eq "backward" and $ParamPos>$MediumPos);
13224 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013225 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13226 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013227 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013228 push(@Positions, $ParamPos);
13229 }
13230 }
13231 return @Positions;
13232}
13233
13234sub getTypeIdByName($$)
13235{
13236 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013237 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013238}
13239
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013240sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013241{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013242 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013243 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13244 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013245 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13246 { # equal types
13247 return 0;
13248 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013249 if($Type1_Pure{"Name"} eq "void")
13250 { # from void* to something
13251 return 0;
13252 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013253 if($Type1_Pure{"Name"}=~/\*/
13254 or $Type2_Pure{"Name"}=~/\*/)
13255 { # compared in detectTypeChange()
13256 return 0;
13257 }
13258 my %FloatType = map {$_=>1} (
13259 "float",
13260 "double",
13261 "long double"
13262 );
13263 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13264 { # different types
13265 if($Type1_Pure{"Type"} eq "Intrinsic"
13266 and $Type2_Pure{"Type"} eq "Enum")
13267 { # "int" to "enum"
13268 return 0;
13269 }
13270 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13271 and $Type1_Pure{"Type"} eq "Enum")
13272 { # "enum" to "int"
13273 return 0;
13274 }
13275 else
13276 { # "union" to "struct"
13277 # ...
13278 return 1;
13279 }
13280 }
13281 else
13282 {
13283 if($Type1_Pure{"Type"} eq "Intrinsic")
13284 {
13285 if($FloatType{$Type1_Pure{"Name"}}
13286 or $FloatType{$Type2_Pure{"Name"}})
13287 { # "float" to "double"
13288 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013289 if($Level eq "Source")
13290 { # Safe
13291 return 0;
13292 }
13293 else {
13294 return 1;
13295 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013296 }
13297 }
13298 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13299 {
13300 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13301 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040013302 if(not @Membs2)
13303 { # private
13304 return 0;
13305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013306 if($#Membs1!=$#Membs2)
13307 { # different number of elements
13308 return 1;
13309 }
13310 if($Type1_Pure{"Type"} eq "Enum")
13311 {
13312 foreach my $Pos (@Membs1)
13313 { # compare elements by name and value
13314 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13315 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13316 { # different names
13317 return 1;
13318 }
13319 }
13320 }
13321 else
13322 {
13323 foreach my $Pos (@Membs1)
13324 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013325 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13326 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040013327
13328 $MT1 = uncover_typedefs($MT1, 1);
13329 $MT2 = uncover_typedefs($MT2, 2);
13330
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013331 if($MT1 ne $MT2)
13332 { # different types
Andrey Ponomarenko2956b972012-11-14 19:16:16 +040013333 if(not isAnon($MT1) and not isAnon($MT2)) {
13334 return 1;
13335 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013336 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013337 if($Level eq "Source")
13338 {
13339 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13340 { # different names
13341 return 1;
13342 }
13343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013344 }
13345 }
13346 }
13347 }
13348 return 0;
13349}
13350
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013351sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013352{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013353 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013354 if(not $Type1_Id or not $Type2_Id) {
13355 return ();
13356 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013357 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013358 my %Type1 = get_Type($Type1_Id, 1);
13359 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013360 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13361 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13362 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13363 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013364 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13365 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013366 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13367 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13368 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13369 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13370 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13371 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13372 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013373 if($Type1{"Name"} eq $Type2{"Name"})
13374 {
13375 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13376 { # will be reported in mergeTypes() as typedef problem
13377 return ();
13378 }
13379 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13380 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13381 if(%Typedef_1 and %Typedef_2)
13382 {
13383 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13384 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13385 { # const Typedef
13386 return ();
13387 }
13388 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013389 }
13390 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13391 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013392 if($Level eq "Binary"
13393 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13395 {
13396 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13397 "Old_Value"=>$Type1_Base{"Name"},
13398 "New_Value"=>$Type2_Base{"Name"},
13399 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13400 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13401 "InitialType_Type"=>$Type1_Pure{"Type"});
13402 }
13403 else
13404 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013405 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013406 { # format change
13407 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13408 "Old_Value"=>$Type1_Base{"Name"},
13409 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013410 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13411 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013412 "InitialType_Type"=>$Type1_Pure{"Type"});
13413 }
13414 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13415 {
13416 %{$LocalProblems{$Prefix."_BaseType"}}=(
13417 "Old_Value"=>$Type1_Base{"Name"},
13418 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013419 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13420 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013421 "InitialType_Type"=>$Type1_Pure{"Type"});
13422 }
13423 }
13424 }
13425 }
13426 elsif($Type1{"Name"} ne $Type2{"Name"})
13427 { # type change
13428 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13429 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013430 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013431 and $Type1_Pure{"Name"} eq "void")
13432 {
13433 %{$LocalProblems{"Return_Type_From_Void"}}=(
13434 "New_Value"=>$Type2{"Name"},
13435 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13436 "InitialType_Type"=>$Type1_Pure{"Type"});
13437 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013438 elsif($Prefix eq "Return"
13439 and $Type2_Pure{"Name"} eq "void")
13440 {
13441 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13442 "Old_Value"=>$Type1{"Name"},
13443 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13444 "InitialType_Type"=>$Type1_Pure{"Type"});
13445 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013446 else
13447 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013448 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013449 and $Type1{"Size"} and $Type2{"Size"}
13450 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013451 {
13452 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13453 "Old_Value"=>$Type1{"Name"},
13454 "New_Value"=>$Type2{"Name"},
13455 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13456 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13457 "InitialType_Type"=>$Type1_Pure{"Type"});
13458 }
13459 else
13460 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013461 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013462 { # format change
13463 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13464 "Old_Value"=>$Type1{"Name"},
13465 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013466 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13467 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013468 "InitialType_Type"=>$Type1_Pure{"Type"});
13469 }
13470 elsif(tNameLock($Type1_Id, $Type2_Id))
13471 { # FIXME: correct this condition
13472 %{$LocalProblems{$Prefix."_Type"}}=(
13473 "Old_Value"=>$Type1{"Name"},
13474 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013475 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13476 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013477 "InitialType_Type"=>$Type1_Pure{"Type"});
13478 }
13479 }
13480 }
13481 }
13482 }
13483 if($Type1_PLevel!=$Type2_PLevel)
13484 {
13485 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13486 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13487 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013488 if($Level eq "Source")
13489 {
13490 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013491 "Old_Value"=>$Type1_PLevel,
13492 "New_Value"=>$Type2_PLevel);
13493 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013494 else
13495 {
13496 if($Type2_PLevel>$Type1_PLevel) {
13497 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13498 "Old_Value"=>$Type1_PLevel,
13499 "New_Value"=>$Type2_PLevel);
13500 }
13501 else {
13502 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13503 "Old_Value"=>$Type1_PLevel,
13504 "New_Value"=>$Type2_PLevel);
13505 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013506 }
13507 }
13508 }
13509 if($Type1_Pure{"Type"} eq "Array")
13510 { # base_type[N] -> base_type[N]
13511 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013512 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013513 foreach my $SubProblemType (keys(%SubProblems))
13514 {
13515 $SubProblemType=~s/_Type/_BaseType/g;
13516 next if(defined $LocalProblems{$SubProblemType});
13517 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13518 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13519 }
13520 }
13521 }
13522 return %LocalProblems;
13523}
13524
13525sub tNameLock($$)
13526{
13527 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013528 my $Changed = 0;
13529 if(differentDumps("G"))
13530 { # different GCC versions
13531 $Changed = 1;
13532 }
13533 elsif(differentDumps("V"))
13534 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013535 if(not checkDump(1, "2.13")
13536 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013537 { # latest names update
13538 # 2.6: added restrict qualifier
13539 # 2.13: added missed typedefs to qualified types
13540 $Changed = 1;
13541 }
13542 }
13543 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013544 { # different formats
13545 if($UseOldDumps)
13546 { # old dumps
13547 return 0;
13548 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013549 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13550 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013551
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013552 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13553 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013554
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013555 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013556 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013557 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013558 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013559 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013560 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013561 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013562 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013563 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13564 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13565 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013566 { # equal base types
13567 return 0;
13568 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013569
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013570 if(not checkDump(1, "2.13")
13571 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013572 { # broken array names in ABI dumps < 2.13
13573 if($TT1 eq "Array"
13574 and $TT2 eq "Array")
13575 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013576 return 0;
13577 }
13578 }
13579
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013580 if(not checkDump(1, "2.6")
13581 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013582 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013583 if($TN1!~/\brestrict\b/
13584 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013585 {
13586 return 0;
13587 }
13588 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013589 }
13590 return 1;
13591}
13592
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013593sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013594{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013595 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013596 if(defined $Cache{"differentDumps"}{$Check}) {
13597 return $Cache{"differentDumps"}{$Check};
13598 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013599 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013600 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013601 if($Check eq "G")
13602 {
13603 if(getGccVersion(1) ne getGccVersion(2))
13604 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013605 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013606 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013607 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013608 if($Check eq "V")
13609 {
13610 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13611 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13612 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013613 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013614 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013615 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013616 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013617 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013618}
13619
13620sub formatVersion($$)
13621{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013622 my ($V, $Digits) = @_;
13623 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013624 return join(".", splice(@Elems, 0, $Digits));
13625}
13626
13627sub htmlSpecChars($)
13628{
13629 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013630 if(not $Str) {
13631 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013633 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13634 $Str=~s/</&lt;/g;
13635 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13636 $Str=~s/>/&gt;/g;
13637 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13638 $Str=~s/ /&#160;/g; # &nbsp;
13639 $Str=~s/\@ALONE_SP\@/ /g;
13640 $Str=~s/\n/<br\/>/g;
13641 $Str=~s/\"/&quot;/g;
13642 $Str=~s/\'/&#39;/g;
13643 return $Str;
13644}
13645
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013646sub xmlSpecChars($)
13647{
13648 my $Str = $_[0];
13649 if(not $Str) {
13650 return $Str;
13651 }
13652
13653 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13654 $Str=~s/</&lt;/g;
13655 $Str=~s/>/&gt;/g;
13656
13657 $Str=~s/\"/&quot;/g;
13658 $Str=~s/\'/&#39;/g;
13659
13660 return $Str;
13661}
13662
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013663sub xmlSpecChars_R($)
13664{
13665 my $Str = $_[0];
13666 if(not $Str) {
13667 return $Str;
13668 }
13669
13670 $Str=~s/&amp;/&/g;
13671 $Str=~s/&lt;/</g;
13672 $Str=~s/&gt;/>/g;
13673
13674 $Str=~s/&quot;/"/g;
13675 $Str=~s/&#39;/'/g;
13676
13677 return $Str;
13678}
13679
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013680sub black_name($)
13681{
13682 my $Name = $_[0];
13683 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13684}
13685
13686sub highLight_Signature($)
13687{
13688 my $Signature = $_[0];
13689 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13690}
13691
13692sub highLight_Signature_Italic_Color($)
13693{
13694 my $Signature = $_[0];
13695 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13696}
13697
13698sub separate_symbol($)
13699{
13700 my $Symbol = $_[0];
13701 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13702 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13703 ($Name, $Spec, $Ver) = ($1, $2, $3);
13704 }
13705 return ($Name, $Spec, $Ver);
13706}
13707
13708sub cut_f_attrs($)
13709{
13710 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13711 return $2;
13712 }
13713 return "";
13714}
13715
13716sub highLight_Signature_PPos_Italic($$$$$)
13717{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013718 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13719 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013720 if($CheckObjectsOnly) {
13721 $ItalicParams=$ColorParams=0;
13722 }
13723 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13724 my $Return = "";
13725 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13726 $Return = $2;
13727 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013728 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013729 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013730 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013731 $Signature = htmlSpecChars($Signature);
13732 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013733 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013734 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013735 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013736 }
13737 return $Signature;
13738 }
13739 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13740 $Begin.=" " if($Begin!~/ \Z/);
13741 $End = cut_f_attrs($Signature);
13742 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013743 my ($Short, $Params) = split_Signature($Signature);
13744 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013745 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013746 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013747 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013748 $Part=~s/\A\s+|\s+\Z//g;
13749 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13750 if($Part=~/\([\*]+(\w+)\)/i) {
13751 $ParamName = $1;#func-ptr
13752 }
13753 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13754 $ParamName = $1;
13755 }
13756 if(not $ParamName) {
13757 push(@Parts, $Part_Styled);
13758 next;
13759 }
13760 if($ItalicParams and not $TName_Tid{1}{$Part}
13761 and not $TName_Tid{2}{$Part})
13762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013763 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013764 if($Param_Pos ne ""
13765 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013766 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013767 }
13768 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013769 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013771 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013772 }
13773 $Part_Styled=~s/,(\w)/, $1/g;
13774 push(@Parts, $Part_Styled);
13775 }
13776 if(@Parts)
13777 {
13778 foreach my $Num (0 .. $#Parts)
13779 {
13780 if($Num==$#Parts)
13781 { # add ")" to the last parameter
13782 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13783 }
13784 elsif(length($Parts[$Num])<=45) {
13785 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13786 }
13787 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013788 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013789 }
13790 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013791 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013792 }
13793 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013794 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013796 $Signature=~s!\[\]![&#160;]!g;
13797 $Signature=~s!operator=!operator&#160;=!g;
13798 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13799 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013800}
13801
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013802sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013803{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013804 my $Signature = $_[0];
13805 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13806 {
13807 $Signature=~s/\A\Q$ShortName\E\(//g;
13808 cut_f_attrs($Signature);
13809 $Signature=~s/\)\Z//;
13810 return ($ShortName, $Signature);
13811 }
13812
13813 # error
13814 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013815}
13816
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013817sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013818{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013819 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013820 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013821 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13822 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013823 foreach my $Pos (0 .. length($Params) - 1)
13824 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013825 my $S = substr($Params, $Pos, 1);
13826 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013827 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013828 }
13829 if($S eq "," and
13830 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013831 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013832 if($Comma)
13833 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013834 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013835 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013836 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013837 }
13838 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013839 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013840 }
13841 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013842 if(not $Sp)
13843 { # remove spaces
13844 foreach (@Parts)
13845 {
13846 s/\A //g;
13847 s/ \Z//g;
13848 }
13849 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013850 return @Parts;
13851}
13852
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013853sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854{
13855 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013856 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013857 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013858 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13859 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013860 $Center+=length($1);
13861 }
13862 foreach my $Pos (0 .. length($Sign)-1)
13863 {
13864 my $S = substr($Sign, $Pos, 1);
13865 if($S eq $Target)
13866 {
13867 if($B{"("}==$B{")"}
13868 and $B{"<"}==$B{">"}) {
13869 return $Center;
13870 }
13871 }
13872 if(defined $B{$S}) {
13873 $B{$S}+=1;
13874 }
13875 $Center+=1;
13876 }
13877 return 0;
13878}
13879
13880sub appendFile($$)
13881{
13882 my ($Path, $Content) = @_;
13883 return if(not $Path);
13884 if(my $Dir = get_dirname($Path)) {
13885 mkpath($Dir);
13886 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013887 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013888 print FILE $Content;
13889 close(FILE);
13890}
13891
13892sub writeFile($$)
13893{
13894 my ($Path, $Content) = @_;
13895 return if(not $Path);
13896 if(my $Dir = get_dirname($Path)) {
13897 mkpath($Dir);
13898 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013899 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013900 print FILE $Content;
13901 close(FILE);
13902}
13903
13904sub readFile($)
13905{
13906 my $Path = $_[0];
13907 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013908 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013909 local $/ = undef;
13910 my $Content = <FILE>;
13911 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013912 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013913 $Content=~s/\r/\n/g;
13914 }
13915 return $Content;
13916}
13917
13918sub get_filename($)
13919{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013920 if(defined $Cache{"get_filename"}{$_[0]}) {
13921 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013922 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013923 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13924 return ($Cache{"get_filename"}{$_[0]}=$1);
13925 }
13926 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013927}
13928
13929sub get_dirname($)
13930{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013931 if(defined $Cache{"get_dirname"}{$_[0]}) {
13932 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013933 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013934 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13935 return ($Cache{"get_dirname"}{$_[0]}=$1);
13936 }
13937 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013938}
13939
13940sub separate_path($) {
13941 return (get_dirname($_[0]), get_filename($_[0]));
13942}
13943
13944sub esc($)
13945{
13946 my $Str = $_[0];
13947 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13948 return $Str;
13949}
13950
13951sub readLineNum($$)
13952{
13953 my ($Path, $Num) = @_;
13954 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013955 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013956 foreach (1 ... $Num) {
13957 <FILE>;
13958 }
13959 my $Line = <FILE>;
13960 close(FILE);
13961 return $Line;
13962}
13963
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013964sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013965{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013966 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013967 return () if(not $Path or not -f $Path);
13968 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013969 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13970 {
13971 foreach my $AttrVal (split(/;/, $1))
13972 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013973 if($AttrVal=~/(.+):(.+)/)
13974 {
13975 my ($Name, $Value) = ($1, $2);
13976 $Attributes{$Name} = $Value;
13977 }
13978 }
13979 }
13980 return \%Attributes;
13981}
13982
13983sub is_abs($) {
13984 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13985}
13986
13987sub get_abs_path($)
13988{ # abs_path() should NOT be called for absolute inputs
13989 # because it can change them
13990 my $Path = $_[0];
13991 if(not is_abs($Path)) {
13992 $Path = abs_path($Path);
13993 }
13994 return $Path;
13995}
13996
13997sub get_OSgroup()
13998{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013999 my $N = $Config{"osname"};
14000 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014001 return "macos";
14002 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014003 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014004 return "bsd";
14005 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014006 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014007 return "beos";
14008 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014009 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014010 return "symbian";
14011 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014012 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014013 return "windows";
14014 }
14015 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014016 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014017 }
14018}
14019
14020sub getGccVersion($)
14021{
14022 my $LibVersion = $_[0];
14023 if($GCC_VERSION{$LibVersion})
14024 { # dump version
14025 return $GCC_VERSION{$LibVersion};
14026 }
14027 elsif($UsedDump{$LibVersion}{"V"})
14028 { # old-version dumps
14029 return "unknown";
14030 }
14031 my $GccVersion = get_dumpversion($GCC_PATH); # host version
14032 if(not $GccVersion) {
14033 return "unknown";
14034 }
14035 return $GccVersion;
14036}
14037
14038sub showArch($)
14039{
14040 my $Arch = $_[0];
14041 if($Arch eq "arm"
14042 or $Arch eq "mips") {
14043 return uc($Arch);
14044 }
14045 return $Arch;
14046}
14047
14048sub getArch($)
14049{
14050 my $LibVersion = $_[0];
14051 if($CPU_ARCH{$LibVersion})
14052 { # dump version
14053 return $CPU_ARCH{$LibVersion};
14054 }
14055 elsif($UsedDump{$LibVersion}{"V"})
14056 { # old-version dumps
14057 return "unknown";
14058 }
14059 if(defined $Cache{"getArch"}{$LibVersion}) {
14060 return $Cache{"getArch"}{$LibVersion};
14061 }
14062 my $Arch = get_dumpmachine($GCC_PATH); # host version
14063 if(not $Arch) {
14064 return "unknown";
14065 }
14066 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
14067 $Arch = $1;
14068 }
14069 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
14070 if($OSgroup eq "windows") {
14071 $Arch = "x86" if($Arch=~/win32|mingw32/i);
14072 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
14073 }
14074 $Cache{"getArch"}{$LibVersion} = $Arch;
14075 return $Arch;
14076}
14077
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014078sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014079{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014080 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014081 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014082 if(getArch(1) ne getArch(2)
14083 or getArch(1) eq "unknown"
14084 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014085 { # don't show architecture in the header
14086 $ArchInfo="";
14087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014088 my $Report_Header = "<h1><span class='nowrap'>";
14089 if($Level eq "Source") {
14090 $Report_Header .= "Source compatibility";
14091 }
14092 elsif($Level eq "Binary") {
14093 $Report_Header .= "Binary compatibility";
14094 }
14095 else {
14096 $Report_Header .= "API compatibility";
14097 }
14098 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014099 $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>";
14100 if($AppPath) {
14101 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
14102 }
14103 $Report_Header .= "</h1>\n";
14104 return $Report_Header;
14105}
14106
14107sub get_SourceInfo()
14108{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014109 my ($CheckedHeaders, $CheckedLibs) = ("", "");
14110 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014111 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014112 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
14113 $CheckedHeaders .= "<div class='h_list'>\n";
14114 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14115 {
14116 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
14117 my $Header_Name = get_filename($Identity);
14118 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14119 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
14120 }
14121 $CheckedHeaders .= "</div>\n";
14122 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014123 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014124 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014125 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014126 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
14127 $CheckedLibs .= "<div class='lib_list'>\n";
14128 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14129 {
14130 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14131 $CheckedLibs .= $Library."<br/>\n";
14132 }
14133 $CheckedLibs .= "</div>\n";
14134 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 }
14136 return $CheckedHeaders.$CheckedLibs;
14137}
14138
14139sub get_TypeProblems_Count($$$)
14140{
14141 my ($TypeChanges, $TargetPriority, $Level) = @_;
14142 my $Type_Problems_Count = 0;
14143 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14144 {
14145 my %Kinds_Target = ();
14146 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14147 {
14148 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14149 {
14150 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14151 my $Priority = getProblemSeverity($Level, $Kind);
14152 next if($Priority ne $TargetPriority);
14153 if($Kinds_Target{$Kind}{$Target}) {
14154 next;
14155 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014156 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014157 { # select a problem with the highest priority
14158 next;
14159 }
14160 $Kinds_Target{$Kind}{$Target} = 1;
14161 $Type_Problems_Count += 1;
14162 }
14163 }
14164 }
14165 return $Type_Problems_Count;
14166}
14167
14168sub get_Summary($)
14169{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014170 my $Level = $_[0];
14171 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14172 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14173 %{$RESULT{$Level}} = (
14174 "Problems"=>0,
14175 "Warnings"=>0,
14176 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014177 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014178 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014179 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014180 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014181 {
14182 if(not defined $CompatRules{$Level}{$Kind})
14183 { # unknown rule
14184 if(not $UnknownRules{$Level}{$Kind})
14185 { # only one warning
14186 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14187 $UnknownRules{$Level}{$Kind}=1;
14188 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014189 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014190 }
14191 }
14192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014193 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014194 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014195 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014196 {
14197 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14198 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014199 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014200 {
14201 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014202 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014203 $Added += 1;
14204 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014205 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014206 {
14207 $Removed += 1;
14208 $TotalAffected{$Level}{$Interface} = $Priority;
14209 }
14210 else
14211 {
14212 if($Priority eq "Safe") {
14213 $I_Other += 1;
14214 }
14215 elsif($Priority eq "High") {
14216 $I_Problems_High += 1;
14217 }
14218 elsif($Priority eq "Medium") {
14219 $I_Problems_Medium += 1;
14220 }
14221 elsif($Priority eq "Low") {
14222 $I_Problems_Low += 1;
14223 }
14224 if(($Priority ne "Low" or $StrictCompat)
14225 and $Priority ne "Safe") {
14226 $TotalAffected{$Level}{$Interface} = $Priority;
14227 }
14228 }
14229 }
14230 }
14231 }
14232 }
14233 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014234 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014235 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014236 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014237 {
14238 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14239 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014240 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014241 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014242 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14243 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014244 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014245 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014246 { # select a problem with the highest priority
14247 next;
14248 }
14249 if(($Priority ne "Low" or $StrictCompat)
14250 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014251 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014252 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014253 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014254 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014255 }
14256 }
14257 }
14258 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014259
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014260 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14261 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14262 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14263 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014264
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014265 if($CheckObjectsOnly)
14266 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014267 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014268 }
14269 else
14270 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014271 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014272 if($ExtendedCheck)
14273 { # don't count external_func_0 for constants
14274 $SCount-=1;
14275 }
14276 if($SCount)
14277 {
14278 my %Weight = (
14279 "High" => 100,
14280 "Medium" => 50,
14281 "Low" => 25
14282 );
14283 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014284 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014285 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014286 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014287 }
14288 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014289 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014290 }
14291 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014292 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14293 if($RESULT{$Level}{"Affected"}>=100) {
14294 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014295 }
14296
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014297 $RESULT{$Level}{"Problems"} += $Removed;
14298 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014299 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014300 if($StrictCompat) {
14301 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14302 }
14303 else {
14304 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014306
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014307 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14308 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014309 if(defined $CompatRules{$Level}{"Changed_Constant"})
14310 {
14311 if($StrictCompat) {
14312 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14313 }
14314 else {
14315 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14316 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014317 }
14318 else
14319 {
14320 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14321 $C_Problems_Low = 0;
14322 }
14323 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014324 if($CheckImpl and $Level eq "Binary")
14325 {
14326 if($StrictCompat) {
14327 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14328 }
14329 else {
14330 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14331 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014332 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014333 if($RESULT{$Level}{"Problems"}
14334 and $RESULT{$Level}{"Affected"}) {
14335 $RESULT{$Level}{"Verdict"} = "incompatible";
14336 }
14337 else {
14338 $RESULT{$Level}{"Verdict"} = "compatible";
14339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014340
14341 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14342 if(not $TotalTypes)
14343 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014344 $TotalTypes = keys(%{$TName_Tid{1}});
14345 }
14346
14347 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14348 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14349
14350 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14351
14352 if($ReportFormat eq "xml")
14353 { # XML
14354 # test info
14355 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14356 $TestInfo .= " <version1>\n";
14357 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14358 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14359 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14360 $TestInfo .= " </version1>\n";
14361
14362 $TestInfo .= " <version2>\n";
14363 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14364 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14365 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14366 $TestInfo .= " </version2>\n";
14367 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14368
14369 # test results
14370 $TestResults .= " <headers>\n";
14371 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14372 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014373 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014374 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14375 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14376 }
14377 $TestResults .= " </headers>\n";
14378
14379 $TestResults .= " <libs>\n";
14380 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14381 {
14382 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14383 $TestResults .= " <name>$Library</name>\n";
14384 }
14385 $TestResults .= " </libs>\n";
14386
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014387 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014388 $TestResults .= " <types>".$TotalTypes."</types>\n";
14389
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014390 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14391 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014392 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14393
14394 # problem summary
14395 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14396 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14397
14398 $Problem_Summary .= " <problems_with_types>\n";
14399 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14400 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14401 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14402 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14403 $Problem_Summary .= " </problems_with_types>\n";
14404
14405 $Problem_Summary .= " <problems_with_symbols>\n";
14406 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14407 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14408 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014409 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014410 $Problem_Summary .= " </problems_with_symbols>\n";
14411
14412 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014413 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014414 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014415 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014416 {
14417 $Problem_Summary .= " <impl>\n";
14418 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14419 $Problem_Summary .= " </impl>\n";
14420 }
14421 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14422
14423 return ($TestInfo.$TestResults.$Problem_Summary, "");
14424 }
14425 else
14426 { # HTML
14427 # test info
14428 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014429 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014430 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14431
14432 my (@VInf1, @VInf2, $AddTestInfo) = ();
14433 if($Arch1 ne "unknown"
14434 and $Arch2 ne "unknown")
14435 { # CPU arch
14436 if($Arch1 eq $Arch2)
14437 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014438 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014439 }
14440 else
14441 { # go to the version number
14442 push(@VInf1, showArch($Arch1));
14443 push(@VInf2, showArch($Arch2));
14444 }
14445 }
14446 if($GccV1 ne "unknown"
14447 and $GccV2 ne "unknown"
14448 and $OStarget ne "windows")
14449 { # GCC version
14450 if($GccV1 eq $GccV2)
14451 { # go to the separate section
14452 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14453 }
14454 else
14455 { # go to the version number
14456 push(@VInf1, "gcc ".$GccV1);
14457 push(@VInf2, "gcc ".$GccV2);
14458 }
14459 }
14460 # show long version names with GCC version and CPU architecture name (if different)
14461 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14462 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14463 $TestInfo .= $AddTestInfo;
14464 #if($COMMON_LANGUAGE{1}) {
14465 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14466 #}
14467 if($ExtendedCheck) {
14468 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14469 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014470 if($JoinReport)
14471 {
14472 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014473 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014474 }
14475 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014476 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014477 }
14478 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014479 $TestInfo .= "</table>\n";
14480
14481 # test results
14482 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014483 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014484
14485 my $Headers_Link = "0";
14486 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14487 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14488
14489 if(not $ExtendedCheck)
14490 {
14491 my $Libs_Link = "0";
14492 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14493 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14494 }
14495
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014496 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014497
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014498 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014499 if($JoinReport) {
14500 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14501 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014502 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014503 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014504 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14505 }
14506 else {
14507 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14508 }
14509 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014510 $TestResults .= "</table>\n";
14511
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014512 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014513 # problem summary
14514 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014515 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014516 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14517
14518 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014519 if($Added>0)
14520 {
14521 if($JoinReport) {
14522 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14523 }
14524 else {
14525 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14526 }
14527 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014528 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014529 $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530
14531 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014532 if($Removed>0)
14533 {
14534 if($JoinReport) {
14535 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14536 }
14537 else {
14538 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14539 }
14540 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014541 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014542 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14543 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014544
14545 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014546 $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014547 $TH_Link = "n/a" if($CheckObjectsOnly);
14548 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014549 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14550 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014551
14552 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014553 $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014554 $TM_Link = "n/a" if($CheckObjectsOnly);
14555 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014556 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014557
14558 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014559 $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014560 $TL_Link = "n/a" if($CheckObjectsOnly);
14561 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014562 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014563
14564 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014565 $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014566 $IH_Link = "n/a" if($CheckObjectsOnly);
14567 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014568 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14569 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014570
14571 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014572 $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014573 $IM_Link = "n/a" if($CheckObjectsOnly);
14574 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014575 $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576
14577 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014578 $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014579 $IL_Link = "n/a" if($CheckObjectsOnly);
14580 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014581 $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582
14583 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014584 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14585 {
14586 if($JoinReport) {
14587 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14588 }
14589 else {
14590 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14591 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014592 }
14593 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014594 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014595 $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014596
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014597 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014598 {
14599 my $ChangedImpl_Link = "0";
14600 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14601 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14602 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014603 $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%ImplProblems))).">$ChangedImpl_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014604 }
14605 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014606 if($T_Other and not $CheckObjectsOnly)
14607 {
14608 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014609 $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014611
14612 if($I_Other and not $CheckObjectsOnly)
14613 {
14614 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014615 $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617
14618 $META_DATA .= "tool_version:$TOOL_VERSION";
14619 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014620 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014621 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14622 }
14623}
14624
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014625sub getStyle($$$)
14626{
14627 my ($Subj, $Act, $Num) = @_;
14628 my %Style = (
14629 "A"=>"new",
14630 "R"=>"failed",
14631 "S"=>"passed",
14632 "L"=>"warning",
14633 "M"=>"failed",
14634 "H"=>"failed"
14635 );
14636 if($Num>0) {
14637 return " class='".$Style{$Act}."'";
14638 }
14639 return "";
14640}
14641
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014642sub show_number($)
14643{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014644 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014645 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014646 my $Num = cut_off_number($_[0], 2, 0);
14647 if($Num eq "0")
14648 {
14649 foreach my $P (3 .. 7)
14650 {
14651 $Num = cut_off_number($_[0], $P, 1);
14652 if($Num ne "0") {
14653 last;
14654 }
14655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014656 }
14657 if($Num eq "0") {
14658 $Num = $_[0];
14659 }
14660 return $Num;
14661 }
14662 return $_[0];
14663}
14664
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014665sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014666{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014667 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014668 if($num!~/\./)
14669 {
14670 $num .= ".";
14671 foreach (1 .. $digs_to_cut-1) {
14672 $num .= "0";
14673 }
14674 }
14675 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14676 {
14677 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14678 $num .= "0";
14679 }
14680 }
14681 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14682 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14683 }
14684 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014685 if($z) {
14686 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14687 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014688 return $num;
14689}
14690
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014691sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014692{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014693 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014694 my $CHANGED_CONSTANTS = "";
14695 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014696 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014697 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014698 }
14699 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014700 if(not defined $CompatRules{$Level}{$Kind}) {
14701 return "";
14702 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014703 if($ReportFormat eq "xml")
14704 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014705 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 {
14707 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014708 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014709 {
14710 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014711 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14712 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14713 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014714 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014715 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14716 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14717 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014718 $CHANGED_CONSTANTS .= " </problem>\n";
14719 $CHANGED_CONSTANTS .= " </constant>\n";
14720 }
14721 $CHANGED_CONSTANTS .= " </header>\n";
14722 }
14723 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14724 }
14725 else
14726 { # HTML
14727 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014728 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014729 {
14730 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014731 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014732 {
14733 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014734 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14735 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014736 my $Report = "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014737 $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14739 $CHANGED_CONSTANTS .= insertIDs($Report);
14740 }
14741 $CHANGED_CONSTANTS .= "<br/>\n";
14742 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 if($CHANGED_CONSTANTS)
14744 {
14745 my $Anchor = "<a name='Changed_Constants'></a>";
14746 if($JoinReport) {
14747 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14748 }
14749 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014750 }
14751 }
14752 return $CHANGED_CONSTANTS;
14753}
14754
14755sub get_Report_Impl()
14756{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014757 my $CHANGED_IMPLEMENTATION = "";
14758 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014759 foreach my $Interface (sort keys(%ImplProblems))
14760 {
14761 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14762 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014763 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014764 }
14765 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014766 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014767 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014768 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014769 {
14770 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14771 if($HeaderName) {
14772 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14773 }
14774 else {
14775 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14776 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014777 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014778 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014779 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014780 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014781 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014783 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014784 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014785 foreach my $Interface (@SortedInterfaces)
14786 {
14787 $Changed_Number += 1;
14788 my $Signature = get_Signature($Interface, 1);
14789 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014790 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014791 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014792 $CHANGED_IMPLEMENTATION .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span>".$ImplProblems{$Interface}{"Diff"}."<br/><br/>".$ContentDivEnd."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014793 }
14794 }
14795 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14796 }
14797 }
14798 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014799 $CHANGED_IMPLEMENTATION = "<a name='Changed_Implementation'></a><h2>Problems with Implementation ($Changed_Number)</h2><hr/>\n".$CHANGED_IMPLEMENTATION.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014800 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014801
14802 # clean memory
14803 %ImplProblems = ();
14804
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014805 return $CHANGED_IMPLEMENTATION;
14806}
14807
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014808sub getTitle($$$)
14809{
14810 my ($Header, $Library, $NameSpace) = @_;
14811 my $Title = "";
14812 if($Library and $Library!~/\.\w+\Z/) {
14813 $Library .= " (.$LIB_EXT)";
14814 }
14815 if($Header and $Library)
14816 {
14817 $Title .= "<span class='h_name'>$Header</span>";
14818 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14819 }
14820 elsif($Library) {
14821 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14822 }
14823 elsif($Header) {
14824 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14825 }
14826 if($NameSpace) {
14827 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14828 }
14829 return $Title;
14830}
14831
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014832sub get_Report_Added($)
14833{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014834 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014835 my $ADDED_INTERFACES = "";
14836 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014837 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014838 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014839 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014840 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014841 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014842 {
14843 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14844 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014845 if($Level eq "Source" and $ReportFormat eq "html")
14846 { # do not show library name in HTML report
14847 $DyLib = "";
14848 }
14849 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014850 }
14851 }
14852 }
14853 if($ReportFormat eq "xml")
14854 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014855 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014856 {
14857 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014858 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014859 {
14860 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014861 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014862 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14863 }
14864 $ADDED_INTERFACES .= " </library>\n";
14865 }
14866 $ADDED_INTERFACES .= " </header>\n";
14867 }
14868 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14869 }
14870 else
14871 { # HTML
14872 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014873 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014875 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014876 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014877 my %NameSpaceSymbols = ();
14878 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14879 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014880 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014881 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014882 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014883 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14884 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014885 foreach my $Interface (@SortedInterfaces)
14886 {
14887 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014888 my $Signature = get_Signature($Interface, 2);
14889 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014890 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014891 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014892 if($Interface=~/\A(_Z|\?)/)
14893 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014895 $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");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014896 }
14897 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014898 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014899 }
14900 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014901 else
14902 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014903 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014904 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014905 }
14906 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014907 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014908 }
14909 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014910 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014911 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014912 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014913 }
14914 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014915 if($ADDED_INTERFACES)
14916 {
14917 my $Anchor = "<a name='Added'></a>";
14918 if($JoinReport) {
14919 $Anchor = "<a name='".$Level."_Added'></a>";
14920 }
14921 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014922 }
14923 }
14924 return $ADDED_INTERFACES;
14925}
14926
14927sub get_Report_Removed($)
14928{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014929 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014930 my $REMOVED_INTERFACES = "";
14931 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014932 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014933 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014934 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014935 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014936 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014937 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014938 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14939 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014940 if($Level eq "Source" and $ReportFormat eq "html")
14941 { # do not show library name in HTML report
14942 $DyLib = "";
14943 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014944 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014945 }
14946 }
14947 }
14948 if($ReportFormat eq "xml")
14949 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014950 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014951 {
14952 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014953 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014954 {
14955 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014956 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14957 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014958 }
14959 $REMOVED_INTERFACES .= " </library>\n";
14960 }
14961 $REMOVED_INTERFACES .= " </header>\n";
14962 }
14963 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14964 }
14965 else
14966 { # HTML
14967 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014968 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014970 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014971 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014972 my %NameSpaceSymbols = ();
14973 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14974 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014975 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014976 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014977 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014978 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14979 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014980 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014981 {
14982 $Removed_Number += 1;
14983 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014984 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014985 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014986 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014987 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014988 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014989 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014990 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014991 $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");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014992 }
14993 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014994 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014995 }
14996 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014997 else
14998 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014999 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015000 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015001 }
15002 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015003 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015004 }
15005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015006 }
15007 }
15008 $REMOVED_INTERFACES .= "<br/>\n";
15009 }
15010 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015011 if($REMOVED_INTERFACES)
15012 {
15013 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
15014 if($JoinReport) {
15015 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
15016 }
15017 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018 }
15019 }
15020 return $REMOVED_INTERFACES;
15021}
15022
15023sub getXmlParams($$)
15024{
15025 my ($Content, $Problem) = @_;
15026 return "" if(not $Content or not $Problem);
15027 my %XMLparams = ();
15028 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15029 {
15030 my $Macro = "\@".lc($Attr);
15031 if($Content=~/\Q$Macro\E/) {
15032 $XMLparams{lc($Attr)} = $Problem->{$Attr};
15033 }
15034 }
15035 my @PString = ();
15036 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015037 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015038 }
15039 if(@PString) {
15040 return " ".join(" ", @PString);
15041 }
15042 else {
15043 return "";
15044 }
15045}
15046
15047sub addMarkup($)
15048{
15049 my $Content = $_[0];
15050 # auto-markup
15051 $Content=~s/\n[ ]*//; # spaces
15052 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
15053 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015054 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015055 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
15056 if($Content=~/\ANOTE:/)
15057 { # notes
15058 $Content=~s!(NOTE):!<b>$1</b>:!g;
15059 }
15060 else {
15061 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
15062 }
15063 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
15064 my @Keywords = (
15065 "void",
15066 "const",
15067 "static",
15068 "restrict",
15069 "volatile",
15070 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015071 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015072 );
15073 my $MKeys = join("|", @Keywords);
15074 foreach (@Keywords) {
15075 $MKeys .= "|non-".$_;
15076 }
15077 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015078
15079 # Markdown
15080 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
15081 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015082 return $Content;
15083}
15084
15085sub applyMacroses($$$$)
15086{
15087 my ($Level, $Kind, $Content, $Problem) = @_;
15088 return "" if(not $Content or not $Problem);
15089 $Problem->{"Word_Size"} = $WORD_SIZE{2};
15090 $Content = addMarkup($Content);
15091 # macros
15092 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15093 {
15094 my $Macro = "\@".lc($Attr);
15095 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015096 if(not defined $Value
15097 or $Value eq "") {
15098 next;
15099 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015100 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015101 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015102 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
15103 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015104 $Value = black_name($Value);
15105 }
15106 elsif($Value=~/\s/) {
15107 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
15108 }
15109 elsif($Value=~/\A\d+\Z/
15110 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
15111 { # bits to bytes
15112 if($Value % $BYTE_SIZE)
15113 { # bits
15114 if($Value==1) {
15115 $Value = "<b>".$Value."</b> bit";
15116 }
15117 else {
15118 $Value = "<b>".$Value."</b> bits";
15119 }
15120 }
15121 else
15122 { # bytes
15123 $Value /= $BYTE_SIZE;
15124 if($Value==1) {
15125 $Value = "<b>".$Value."</b> byte";
15126 }
15127 else {
15128 $Value = "<b>".$Value."</b> bytes";
15129 }
15130 }
15131 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015132 else
15133 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015134 $Value = "<b>".htmlSpecChars($Value)."</b>";
15135 }
15136 $Content=~s/\Q$Macro\E/$Value/g;
15137 }
15138
15139 if($Content=~/(\A|[^\@\w])\@\w/)
15140 {
15141 if(not $IncompleteRules{$Level}{$Kind})
15142 { # only one warning
15143 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15144 $IncompleteRules{$Level}{$Kind} = 1;
15145 }
15146 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015147 return $Content;
15148}
15149
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015150sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015151{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015152 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015153 my $INTERFACE_PROBLEMS = "";
15154 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015155 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015156 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015157 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15158 if($SV and defined $CompatProblems{$Level}{$SN}) {
15159 next;
15160 }
15161 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015162 {
15163 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015164 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015165 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015166 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15167 my $DyLib = $Symbol_Library{1}{$Symbol};
15168 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015169 { # Symbol with Version
15170 $DyLib = $Symbol_Library{1}{$VSym};
15171 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015172 if(not $DyLib)
15173 { # const global data
15174 $DyLib = "";
15175 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015176 if($Level eq "Source" and $ReportFormat eq "html")
15177 { # do not show library name in HTML report
15178 $DyLib = "";
15179 }
15180 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15181 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015182 {
15183 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015184 if($Priority ne $TargetSeverity) {
15185 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015186 }
15187 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015188 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15189 {
15190 delete($SymbolChanges{$Symbol}{$Kind});
15191 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015193 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015194 }
15195 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015196 if(not keys(%{$SymbolChanges{$Symbol}})) {
15197 delete($SymbolChanges{$Symbol});
15198 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015199 }
15200 if($ReportFormat eq "xml")
15201 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015202 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015203 {
15204 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015205 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015206 {
15207 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15208 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15209 {
15210 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15211 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15212 {
15213 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15214 {
15215 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015216 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015217 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15218 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15219 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15220 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15221 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15222 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15223 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15224 $INTERFACE_PROBLEMS .= " </problem>\n";
15225 }
15226 }
15227 $INTERFACE_PROBLEMS .= " </symbol>\n";
15228 }
15229 $INTERFACE_PROBLEMS .= " </library>\n";
15230 }
15231 $INTERFACE_PROBLEMS .= " </header>\n";
15232 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015233 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015234 }
15235 else
15236 { # HTML
15237 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015238 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015239 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015240 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015241 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015242 my (%NameSpaceSymbols, %NewSignature) = ();
15243 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15244 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015245 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015246 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015247 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015248 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15249 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15250 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015251 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015252 my $Signature = get_Signature($Symbol, 1);
15253 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015254 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015255 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015256 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015257 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015258 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015259 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015260 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015261 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015262 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015263 }
15264 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15265 {
15266 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015267 $SYMBOL_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>".$Effect."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015268 $ProblemNum += 1;
15269 $ProblemsNum += 1;
15270 }
15271 }
15272 }
15273 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015274 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015275 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015276 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015277 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015278 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015279 }
15280 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015281 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015282 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015283 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15284 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15285 if($NewSignature{$Symbol})
15286 { # argument list changed to
15287 $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";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015288 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015289 if($Symbol=~/\A(_Z|\?)/) {
15290 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15291 }
15292 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15293 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015294 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015295 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015296 }
15297 }
15298 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015299 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015300 }
15301 }
15302 }
15303 if($INTERFACE_PROBLEMS)
15304 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015305 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15306 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15307 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015308 { # Safe Changes
15309 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015310 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015311 $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";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015312 }
15313 }
15314 return $INTERFACE_PROBLEMS;
15315}
15316
15317sub get_Report_TypeProblems($$)
15318{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015319 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015320 my $TYPE_PROBLEMS = "";
15321 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015322 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015323 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015324 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015325 {
15326 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15327 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015328 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015329 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015330 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15331 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15332 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15333 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15334 my $Severity = getProblemSeverity($Level, $Kind);
15335 if($Severity eq "Safe"
15336 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015337 next;
15338 }
15339 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015340 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015342 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015343 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015344
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015345 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015346 { # select a problem with the highest priority
15347 next;
15348 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015349 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015350 }
15351 }
15352 }
15353 }
15354 my %Kinds_Locations = ();
15355 foreach my $TypeName (keys(%TypeChanges))
15356 {
15357 my %Kinds_Target = ();
15358 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15359 {
15360 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15361 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015362 my $Severity = getProblemSeverity($Level, $Kind);
15363 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015364 { # other priority
15365 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15366 next;
15367 }
15368 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15369 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15370 if($Kinds_Target{$Kind}{$Target})
15371 { # duplicate target
15372 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15373 next;
15374 }
15375 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015376 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015377 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015378 }
15379 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15380 delete($TypeChanges{$TypeName}{$Kind});
15381 }
15382 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015383 if(not keys(%{$TypeChanges{$TypeName}})) {
15384 delete($TypeChanges{$TypeName});
15385 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015386 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015387 my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015388 if($ReportFormat eq "xml")
15389 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015390 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015391 {
15392 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015393 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015394 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015395 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15397 {
15398 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15399 {
15400 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15401 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15402 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15403 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15404 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15405 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15406 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15407 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15408 $TYPE_PROBLEMS .= " </problem>\n";
15409 }
15410 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015411 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015412 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015413 $TYPE_PROBLEMS .= showVTables($TypeName);
15414 }
15415 $TYPE_PROBLEMS .= " </type>\n";
15416 }
15417 $TYPE_PROBLEMS .= " </header>\n";
15418 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015419 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015420 }
15421 else
15422 { # HTML
15423 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015424 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015425 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015426 my (%NameSpace_Type) = ();
15427 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015428 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15429 }
15430 foreach my $NameSpace (sort keys(%NameSpace_Type))
15431 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015432 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15433 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015434 foreach my $TypeName (@SortedTypes)
15435 {
15436 my $ProblemNum = 1;
15437 my $TYPE_REPORT = "";
15438 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15439 {
15440 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15441 {
15442 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15443 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15444 {
15445 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15446 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15447 $ProblemNum += 1;
15448 $ProblemsNum += 1;
15449 }
15450 }
15451 }
15452 $ProblemNum -= 1;
15453 if($TYPE_REPORT)
15454 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015455 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015456 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015457 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015458 $ShowVTables = showVTables($TypeName);
15459 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015460 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15461 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15462 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15463 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15464 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015465 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015466 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015467 }
15468 }
15469 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015470 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015471 }
15472 }
15473 if($TYPE_PROBLEMS)
15474 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015475 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15476 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015477 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015478 { # Safe Changes
15479 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015480 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015481 $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015482 }
15483 }
15484 return $TYPE_PROBLEMS;
15485}
15486
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015487sub get_Anchor($$$)
15488{
15489 my ($Kind, $Level, $Severity) = @_;
15490 if($JoinReport)
15491 {
15492 if($Severity eq "Safe") {
15493 return "Other_".$Level."_Changes_In_".$Kind."s";
15494 }
15495 else {
15496 return $Kind."_".$Level."_Problems_".$Severity;
15497 }
15498 }
15499 else
15500 {
15501 if($Severity eq "Safe") {
15502 return "Other_Changes_In_".$Kind."s";
15503 }
15504 else {
15505 return $Kind."_Problems_".$Severity;
15506 }
15507 }
15508}
15509
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015510sub showVTables($)
15511{
15512 my $TypeName = $_[0];
15513 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015514 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015515 if(defined $Type1{"VTable"}
15516 and keys(%{$Type1{"VTable"}}))
15517 {
15518 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015519 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015520 if(defined $Type2{"VTable"}
15521 and keys(%{$Type2{"VTable"}}))
15522 {
15523 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15524 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015525 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015526 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015527 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15528 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015529 }
15530 my $VTABLES = "";
15531 if($ReportFormat eq "xml")
15532 { # XML
15533 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015534 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015535 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015536 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015537 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15538 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015539 $VTABLES .= " </entry>\n";
15540 }
15541 $VTABLES .= " </vtable>\n\n";
15542 }
15543 else
15544 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015545 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015546 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15547 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15548 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015549 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015550 {
15551 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015552 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015553 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015554 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015555 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015556 $Color1 = " class='failed'";
15557 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015558 }
15559 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015560 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015561 }
15562 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015563 $VTABLES .= "<tr><th>".$Index."</th>\n";
15564 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15565 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015566 }
15567 $VTABLES .= "</table><br/>\n";
15568 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015569 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015570 }
15571 return $VTABLES;
15572 }
15573 }
15574 return "";
15575}
15576
15577sub simpleVEntry($)
15578{
15579 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015580 if(not defined $VEntry
15581 or $VEntry eq "") {
15582 return "";
15583 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015584 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15585 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15586 if($VEntry=~/\A_ZThn.+\Z/) {
15587 $VEntry = "non-virtual thunk";
15588 }
15589 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15590 # support for old GCC versions
15591 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15592 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15593 $VEntry=~s/\A&_Z\Z/& _Z/;
15594 # templates
15595 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15596 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15597 # become std::basic_streambuf<char, ...>::imbue
15598 my ($Pname, $Pval) = ($1, $2);
15599 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15600 { # stdc++ typedefs
15601 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15602 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15603 # The typedef info should be added to ABI dumps
15604 }
15605 else
15606 {
15607 $VEntry=~s/<$Pname>/<$Pval>/g;
15608 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15609 }
15610 }
15611 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15612 return $VEntry;
15613}
15614
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015615sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015616{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015617 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015618 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015619 if($#{$Syms}>=10000)
15620 { # reduce size of the report
15621 $LIMIT = 10;
15622 }
15623 my %SProblems = ();
15624 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015625 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015626 if(keys(%SProblems)>$LIMIT) {
15627 last;
15628 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015629 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015630 { # duplicated problems for C2 constructors, D2 and D0 destructors
15631 next;
15632 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015633 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15634 if($Level eq "Source")
15635 { # remove symbol version
15636 $Symbol=$SN;
15637 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015638 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15639 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015640 my $Signature = get_Signature($Symbol, 1);
15641 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015642 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015643 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015644 {
15645 if(not defined $Kinds_Locations->{$Kind}
15646 or not $Kinds_Locations->{$Kind}{$Location}) {
15647 next;
15648 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015649 if($SV and defined $CompatProblems{$Level}{$SN}
15650 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015651 { # duplicated problems for versioned symbols
15652 next;
15653 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015654 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015655 next if($Type_Name ne $Target_TypeName);
15656
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015657 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15658 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015659 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015660 my $Path_Length = 0;
15661 my $ProblemLocation = $Location;
15662 if($Type_Name) {
15663 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15664 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015665 while($ProblemLocation=~/\-\>/g) {
15666 $Path_Length += 1;
15667 }
15668 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15669 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015670 {
15671 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015672 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015673 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015674 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015675 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15676 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015677 "Signature"=>$Signature,
15678 "Position"=>$Position,
15679 "Param_Name"=>$Param_Name,
15680 "Location"=>$Location
15681 );
15682 }
15683 }
15684 }
15685 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015686 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015687 @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Symbols;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015688 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15689 if($#Symbols+1>$LIMIT)
15690 { # remove last element
15691 pop(@Symbols);
15692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015693 my $Affected = "";
15694 if($ReportFormat eq "xml")
15695 { # XML
15696 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015697 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015698 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015699 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15700 my $Description = $SProblems{$Symbol}{"Descr"};
15701 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015702 my $Target = "";
15703 if($Param_Name) {
15704 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15705 }
15706 elsif($Location=~/\Aretval(\-|\Z)/i) {
15707 $Target = " affected=\"retval\"";
15708 }
15709 elsif($Location=~/\Athis(\-|\Z)/i) {
15710 $Target = " affected=\"this\"";
15711 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015712 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015713 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015714 $Affected .= " </symbol>\n";
15715 }
15716 $Affected .= " </affected>\n";
15717 }
15718 else
15719 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015720 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015721 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015722 my $Description = $SProblems{$Symbol}{"Descr"};
15723 my $Signature = $SProblems{$Symbol}{"Signature"};
15724 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015725 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015726 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015727 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015728 $Affected .= "and others ...<br/>";
15729 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015730 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015731 if($Affected)
15732 {
15733 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015734 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015735 }
15736 }
15737 return $Affected;
15738}
15739
15740sub cmp_locations($$)
15741{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015742 my ($L1, $L2) = @_;
15743 if($L2=~/\b(retval|this)\b/
15744 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015745 return 1;
15746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015747 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15748 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015749 return 1;
15750 }
15751 return 0;
15752}
15753
15754sub getAffectDescription($$$$)
15755{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015756 my ($Level, $Symbol, $Kind, $Location) = @_;
15757 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015758 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015759 my @Sentence = ();
15760 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15761 if($Kind eq "Overridden_Virtual_Method"
15762 or $Kind eq "Overridden_Virtual_Method_B") {
15763 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15764 }
15765 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15766 {
15767 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15768 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015769 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015770 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015771 if($ClassName eq $Problem{"Type_Name"}) {
15772 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15773 }
15774 else {
15775 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15776 }
15777 }
15778 else
15779 {
15780 if($Location=~/retval/)
15781 { # return value
15782 if($Location=~/\-\>/) {
15783 push(@Sentence, "Field \'".$Location."\' in return value");
15784 }
15785 else {
15786 push(@Sentence, "Return value");
15787 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015788 if(my $Init = $Problem{"InitialType_Type"})
15789 {
15790 if($Init eq "Pointer") {
15791 push(@Sentence, "(pointer)");
15792 }
15793 elsif($Init eq "Ref") {
15794 push(@Sentence, "(reference)");
15795 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015796 }
15797 }
15798 elsif($Location=~/this/)
15799 { # "this" pointer
15800 if($Location=~/\-\>/) {
15801 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15802 }
15803 else {
15804 push(@Sentence, "\'this\' pointer");
15805 }
15806 }
15807 else
15808 { # parameters
15809 if($Location=~/\-\>/) {
15810 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15811 }
15812 else {
15813 push(@Sentence, "$PPos parameter");
15814 }
15815 if($Problem{"Param_Name"}) {
15816 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15817 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015818 if(my $Init = $Problem{"InitialType_Type"})
15819 {
15820 if($Init eq "Pointer") {
15821 push(@Sentence, "(pointer)");
15822 }
15823 elsif($Init eq "Ref") {
15824 push(@Sentence, "(reference)");
15825 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015826 }
15827 }
15828 if($Location eq "this") {
15829 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15830 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015831 elsif(defined $Problem{"Start_Type_Name"}
15832 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015833 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15834 }
15835 else {
15836 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15837 }
15838 }
15839 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015840 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015841 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15842 }
15843 return join(" ", @Sentence);
15844}
15845
15846sub get_XmlSign($$)
15847{
15848 my ($Symbol, $LibVersion) = @_;
15849 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15850 my $Report = "";
15851 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15852 {
15853 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015854 my $Type = $Info->{"Param"}{$Pos}{"type"};
15855 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015856 foreach my $Typedef (keys(%ChangedTypedef))
15857 {
15858 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015859 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015860 }
15861 $Report .= " <param pos=\"$Pos\">\n";
15862 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015863 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015864 $Report .= " </param>\n";
15865 }
15866 if(my $Return = $Info->{"Return"})
15867 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015868 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015869 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015870 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015871 $Report .= " </retval>\n";
15872 }
15873 return $Report;
15874}
15875
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015876sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015877{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015878 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015879 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015880 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015881 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015882 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15883 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015884 next;
15885 }
15886 $Report .= " <symbol name=\"$Symbol\">\n";
15887 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015888 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015889 {
15890 if(defined $CompleteSignature{1}{$Symbol}
15891 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15892 {
15893 $P1 = get_XmlSign($Symbol, 1);
15894 $S1 = get_Signature($Symbol, 1);
15895 }
15896 elsif($Symbol=~/\A(_Z|\?)/) {
15897 $S1 = $tr_name{$Symbol};
15898 }
15899 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015900 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015901 {
15902 if(defined $CompleteSignature{2}{$Symbol}
15903 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15904 {
15905 $P2 = get_XmlSign($Symbol, 2);
15906 $S2 = get_Signature($Symbol, 2);
15907 }
15908 elsif($Symbol=~/\A(_Z|\?)/) {
15909 $S2 = $tr_name{$Symbol};
15910 }
15911 }
15912 if($S1)
15913 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015914 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015915 $Report .= $P1;
15916 $Report .= " </old>\n";
15917 }
15918 if($S2 and $S2 ne $S1)
15919 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015920 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015921 $Report .= $P2;
15922 $Report .= " </new>\n";
15923 }
15924 $Report .= " </symbol>\n";
15925 }
15926 $Report .= "</symbols_info>\n";
15927 return $Report;
15928}
15929
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015930sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015931{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015932 my ($Level, $Report) = @_;
15933 if($ReportFormat eq "xml") {
15934 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015935 }
15936 if($StdOut)
15937 { # --stdout option
15938 print STDOUT $Report;
15939 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015940 else
15941 {
15942 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015943 mkpath(get_dirname($RPath));
15944
15945 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15946 print REPORT $Report;
15947 close(REPORT);
15948
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015949 if($Browse or $OpenReport)
15950 { # open in browser
15951 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015952 if($JoinReport or $DoubleReport)
15953 {
15954 if($Level eq "Binary")
15955 { # wait to open a browser
15956 sleep(1);
15957 }
15958 }
15959 }
15960 }
15961}
15962
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015963sub openReport($)
15964{
15965 my $Path = $_[0];
15966 my $Cmd = "";
15967 if($Browse)
15968 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015969 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015970 }
15971 if(not $Cmd)
15972 { # default browser
15973 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015974 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015975 }
15976 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015977 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015978 }
15979 else
15980 { # linux, freebsd, solaris
15981 my @Browsers = (
15982 "x-www-browser",
15983 "sensible-browser",
15984 "firefox",
15985 "opera",
15986 "xdg-open",
15987 "lynx",
15988 "links"
15989 );
15990 foreach my $Br (@Browsers)
15991 {
15992 if($Br = get_CmdPath($Br))
15993 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015994 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015995 last;
15996 }
15997 }
15998 }
15999 }
16000 if($Cmd)
16001 {
16002 if($Debug) {
16003 printMsg("INFO", "running $Cmd");
16004 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040016005 if($OSgroup ne "windows"
16006 and $OSgroup ne "macos")
16007 {
16008 if($Cmd!~/lynx|links/) {
16009 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
16010 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016011 }
16012 system($Cmd);
16013 }
16014 else {
16015 printMsg("ERROR", "cannot open report in browser");
16016 }
16017}
16018
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016019sub getReport($)
16020{
16021 my $Level = $_[0];
16022 if($ReportFormat eq "xml")
16023 { # XML
16024
16025 if($Level eq "Join")
16026 {
16027 my $Report = "<reports>\n";
16028 $Report .= getReport("Binary");
16029 $Report .= getReport("Source");
16030 $Report .= "</reports>\n";
16031 return $Report;
16032 }
16033 else
16034 {
16035 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
16036 my ($Summary, $MetaData) = get_Summary($Level);
16037 $Report .= $Summary."\n";
16038 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16039 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16040 $Report .= get_Report_SymbolsInfo($Level);
16041 $Report .= "</report>\n";
16042 return $Report;
16043 }
16044 }
16045 else
16046 { # HTML
16047 my $CssStyles = readModule("Styles", "Report.css");
16048 my $JScripts = readModule("Scripts", "Sections.js");
16049 if($Level eq "Join")
16050 {
16051 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
16052 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040016053 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
16054 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016055 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
16056 my ($BSummary, $BMetaData) = get_Summary("Binary");
16057 my ($SSummary, $SMetaData) = get_Summary("Source");
16058 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>";
16059 $Report .= get_Report_Header("Join")."
16060 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016061 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
16062 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016063 </div>";
16064 $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>";
16065 $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>";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016066 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016067 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16068 return $Report;
16069 }
16070 else
16071 {
16072 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040016073 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
16074 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
16075 my $Description = "$Level compatibility report for the ".$TargetLibraryFName." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016076 if($Level eq "Binary")
16077 {
16078 if(getArch(1) eq getArch(2)
16079 and getArch(1) ne "unknown") {
16080 $Description .= " on ".showArch(getArch(1));
16081 }
16082 }
16083 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
16084 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
16085 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16086 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16087 $Report .= get_SourceInfo();
16088 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016089 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016090 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16091 return $Report;
16092 }
16093 }
16094}
16095
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016096sub getLegend()
16097{
16098 return "<br/>
16099<table class='summary'>
16100<tr>
16101 <td class='new'>added</td>
16102 <td class='passed'>compatible</td>
16103</tr>
16104<tr>
16105 <td class='warning'>warning</td>
16106 <td class='failed'>incompatible</td>
16107</tr></table>\n";
16108}
16109
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016110sub createReport()
16111{
16112 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016113 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016114 writeReport("Join", getReport("Join"));
16115 }
16116 elsif($DoubleReport)
16117 { # default
16118 writeReport("Binary", getReport("Binary"));
16119 writeReport("Source", getReport("Source"));
16120 }
16121 elsif($BinaryOnly)
16122 { # --binary
16123 writeReport("Binary", getReport("Binary"));
16124 }
16125 elsif($SourceOnly)
16126 { # --source
16127 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016128 }
16129}
16130
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016131sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016132{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016133 my ($LibName, $Wide) = @_;
16134 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016135 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016136 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016137 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16138 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016139 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16140 return $Footer;
16141}
16142
16143sub get_Report_Problems($$)
16144{
16145 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016146 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016147 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16148 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016149 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016150 if($Priority eq "Low")
16151 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016152 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +040016153 if($ReportFormat eq "html")
16154 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016155 if($CheckImpl and $Level eq "Binary") {
16156 $Report .= get_Report_Impl();
16157 }
16158 }
16159 }
16160 if($ReportFormat eq "html")
16161 {
16162 if($Report)
16163 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016164 if($JoinReport)
16165 {
16166 if($Priority eq "Safe") {
16167 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16168 }
16169 else {
16170 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16171 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016172 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016173 else
16174 {
16175 if($Priority eq "Safe") {
16176 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16177 }
16178 else {
16179 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16180 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016181 }
16182 }
16183 }
16184 return $Report;
16185}
16186
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016187sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016188{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016189 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16190 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16191 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16192 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016193 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16194 <meta name=\"keywords\" content=\"$Keywords\" />
16195 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016196 <title>
16197 $Title
16198 </title>
16199 <style type=\"text/css\">
16200 $Styles
16201 </style>
16202 <script type=\"text/javascript\" language=\"JavaScript\">
16203 <!--
16204 $Scripts
16205 -->
16206 </script>
16207 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016208}
16209
16210sub insertIDs($)
16211{
16212 my $Text = $_[0];
16213 while($Text=~/CONTENT_ID/)
16214 {
16215 if(int($Content_Counter)%2) {
16216 $ContentID -= 1;
16217 }
16218 $Text=~s/CONTENT_ID/c_$ContentID/;
16219 $ContentID += 1;
16220 $Content_Counter += 1;
16221 }
16222 return $Text;
16223}
16224
16225sub checkPreprocessedUnit($)
16226{
16227 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016228 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016229 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016230 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016231 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016232
16233 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016234 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016235 chomp($Line);
16236 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016237 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016238 $CurHeader = path_format($1, $OSgroup);
16239 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016240 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016241 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16242 and not $Registered_Headers{$Version}{$CurHeader})
16243 { # not a target
16244 next;
16245 }
16246 if(not is_target_header($CurHeaderName, 1)
16247 and not is_target_header($CurHeaderName, 2))
16248 { # user-defined header
16249 next;
16250 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016251 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016252 {
16253 my ($Name, $Value) = ($1, $2);
16254 if(not $Constants{$Version}{$Name}{"Access"})
16255 {
16256 $Constants{$Version}{$Name}{"Access"} = "public";
16257 $Constants{$Version}{$Name}{"Value"} = $Value;
16258 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16259 }
16260 }
16261 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16262 $Constants{$Version}{$1}{"Access"} = "private";
16263 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016264 }
16265 }
16266 close(PREPROC);
16267 foreach my $Constant (keys(%{$Constants{$Version}}))
16268 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016269 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16270 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016271 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16272 { # skip private constants
16273 delete($Constants{$Version}{$Constant});
16274 }
16275 else {
16276 delete($Constants{$Version}{$Constant}{"Access"});
16277 }
16278 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016279 if($Debug)
16280 {
16281 mkpath($DEBUG_PATH{$Version});
16282 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016284}
16285
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016286sub uncoverConstant($$)
16287{
16288 my ($LibVersion, $Constant) = @_;
16289 return "" if(not $LibVersion or not $Constant);
16290 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16291 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16292 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16293 }
16294 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16295 if(defined $Value)
16296 {
16297 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16298 {
16299 push(@RecurConstant, $Constant);
16300 my $Uncovered = uncoverConstant($LibVersion, $Value);
16301 if($Uncovered ne "") {
16302 $Value = $Uncovered;
16303 }
16304 pop(@RecurConstant);
16305 }
16306 # FIXME: uncover $Value using all the enum constants
16307 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16308 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16309 }
16310 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16311}
16312
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016313my %IgnoreConstant = map {$_=>1} (
16314 "VERSION",
16315 "VERSIONCODE",
16316 "VERNUM",
16317 "VERS_INFO",
16318 "PATCHLEVEL",
16319 "INSTALLPREFIX",
16320 "VBUILD",
16321 "VPATCH",
16322 "VMINOR",
16323 "BUILD_STRING",
16324 "BUILD_TIME",
16325 "PACKAGE_STRING",
16326 "PRODUCTION",
16327 "CONFIGURE_COMMAND",
16328 "INSTALLDIR",
16329 "BINDIR",
16330 "CONFIG_FILE_PATH",
16331 "DATADIR",
16332 "EXTENSION_DIR",
16333 "INCLUDE_PATH",
16334 "LIBDIR",
16335 "LOCALSTATEDIR",
16336 "SBINDIR",
16337 "SYSCONFDIR",
16338 "RELEASE",
16339 "SOURCE_ID",
16340 "SUBMINOR",
16341 "MINOR",
16342 "MINNOR",
16343 "MINORVERSION",
16344 "MAJOR",
16345 "MAJORVERSION",
16346 "MICRO",
16347 "MICROVERSION",
16348 "BINARY_AGE",
16349 "INTERFACE_AGE",
16350 "CORE_ABI",
16351 "PATCH",
16352 "COPYRIGHT",
16353 "TIMESTAMP",
16354 "REVISION",
16355 "PACKAGE_TAG",
16356 "PACKAGEDATE",
16357 "NUMVERSION",
16358 "Release",
16359 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016360);
16361
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016362sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016363{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016364 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016365 foreach my $Constant (keys(%{$Constants{1}}))
16366 {
16367 if($SkipConstants{1}{$Constant})
16368 { # skipped by the user
16369 next;
16370 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016371 if(not defined $Constants{2}{$Constant}{"Value"}
16372 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016373 { # empty value
16374 next;
16375 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016376 my $Header = $Constants{1}{$Constant}{"Header"};
16377 if(not is_target_header($Header, 1)
16378 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016379 { # user-defined header
16380 next;
16381 }
16382 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016383 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16384 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016385 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16386 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16387 $New_Value_Pure=~s/(\W)\s+/$1/g;
16388 $New_Value_Pure=~s/\s+(\W)/$1/g;
16389 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16390 if($New_Value_Pure ne $Old_Value_Pure)
16391 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016392 if($Level eq "Binary")
16393 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016394 foreach (keys(%IgnoreConstant))
16395 {
16396 if($Constant=~/(\A|_)$_(_|\Z)/)
16397 { # ignore library version
16398 next;
16399 }
16400 if(/\A[A-Z].*[a-z]\Z/)
16401 {
16402 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16403 { # ignore library version
16404 next;
16405 }
16406 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016407 }
16408 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16409 { # ignore library version
16410 next;
16411 }
16412 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16413 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016414 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016415 next;
16416 }
16417 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16418 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016419 # static int gcry_pth_init ( void) { return ...
16420 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16421 next;
16422 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016423 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016424 { # ignore source defines:
16425 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016426 next;
16427 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016428 }
16429 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16430 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16431 next;
16432 }
16433 if($Old_Value eq "0" and $New_Value eq "NULL")
16434 { # 0 => NULL
16435 next;
16436 }
16437 if($Old_Value eq "NULL" and $New_Value eq "0")
16438 { # NULL => 0
16439 next;
16440 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016441 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016442 "Target"=>$Constant,
16443 "Old_Value"=>$Old_Value,
16444 "New_Value"=>$New_Value );
16445 }
16446 }
16447}
16448
16449sub convert_integer($)
16450{
16451 my $Value = $_[0];
16452 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016453 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016454 return hex($Value);
16455 }
16456 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016457 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016458 return oct($Value);
16459 }
16460 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016461 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016462 return oct($Value);
16463 }
16464 else {
16465 return $Value;
16466 }
16467}
16468
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016469sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016470{
16471 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016472 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016473 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016474 {
16475 if($LibVersion==1)
16476 {
16477 printMsg("WARNING", "checking headers only");
16478 $CheckHeadersOnly = 1;
16479 }
16480 else {
16481 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16482 }
16483 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016484
16485 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths)
16486 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016487 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016488
16489
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016490 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016491
16492 if($CheckUndefined)
16493 {
16494 my %UndefinedLibs = ();
16495
16496 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths)
16497 {
16498 my $LibName = get_filename($LibPath);
16499 foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibPath}}))
16500 {
16501 if(not $Symbol_Library{$LibVersion}{$Symbol} and not $DepSymbol_Library{$LibVersion}{$Symbol})
16502 {
16503 foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) {
16504 $UndefinedLibs{$Path} = 1;
16505 }
16506 }
16507 }
16508 }
16509 if($ExtraInfo)
16510 { # extra information for other tools
16511 if(my @Paths = keys(%UndefinedLibs))
16512 {
16513 my $LibString = "";
16514 foreach (@Paths)
16515 {
16516 my ($Dir, $Name) = separate_path($_);
16517
16518 if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) {
16519 $LibString .= "-L".esc($Dir);
16520 }
16521
16522 $Name = parse_libname($Name, "name", $OStarget);
16523 $Name=~s/\Alib//;
16524
16525 $LibString .= "-l$Name";
16526 }
16527 writeFile($ExtraInfo."/libs-string", $LibString);
16528 }
16529 }
16530 }
16531
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016532 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016533 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016534 if($#LibPaths!=-1)
16535 {
16536 if(not keys(%{$Symbol_Library{$LibVersion}}))
16537 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016538 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016539 printMsg("WARNING", "checking headers only");
16540 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016541 }
16542 }
16543 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016544
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016545 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016546 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016547}
16548
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016549my %Prefix_Lib_Map=(
16550 # symbols for autodetecting library dependencies (by prefix)
16551 "pthread_" => ["libpthread"],
16552 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"],
16553 "cairo_" => ["libcairo"],
16554 "gtk_" => ["libgtk-x11-2.0"],
16555 "atk_" => ["libatk-1.0"],
16556 "gdk_" => ["libgdk-x11-2.0"],
16557 "gl" => ["libGL"],
16558 "glu" => ["libGLU"],
16559 "popt" => ["libpopt"],
16560 "Py" => ["libpython"],
16561 "jpeg_" => ["libjpeg"],
16562 "BZ2_" => ["libbz2"],
16563 "Fc" => ["libfontconfig"],
16564 "Xft" => ["libXft"],
16565 "SSL_" => ["libssl"],
16566 "sem_" => ["libpthread"],
16567 "snd_" => ["libasound"],
16568 "art_" => ["libart_lgpl_2"],
16569 "dbus_g" => ["libdbus-glib-1"],
16570 "GOMP_" => ["libgomp"],
16571 "omp_" => ["libgomp"],
16572 "cms" => ["liblcms"]
16573);
16574
16575my %Pattern_Lib_Map=(
16576 "SL[a-z]" => ["libslang"]
16577);
16578
16579my %Symbol_Lib_Map=(
16580 # symbols for autodetecting library dependencies (by name)
16581 "pow" => "libm",
16582 "fmod" => "libm",
16583 "sin" => "libm",
16584 "floor" => "libm",
16585 "cos" => "libm",
16586 "dlopen" => "libdl",
16587 "deflate" => "libz",
16588 "inflate" => "libz",
16589 "move_panel" => "libpanel",
16590 "XOpenDisplay" => "libX11",
16591 "resize_term" => "libncurses",
16592 "clock_gettime" => "librt"
16593);
16594
16595sub find_SymbolLibs($$)
16596{
16597 my ($LibVersion, $Symbol) = @_;
16598
16599 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/)
16600 { # debug symbols
16601 return ();
16602 }
16603
16604 my %Paths = ();
16605
16606 if(my $LibName = $Symbol_Lib_Map{$Symbol})
16607 {
16608 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16609 $Paths{$Path} = 1;
16610 }
16611 }
16612
16613 if(my $SymbolPrefix = getPrefix($Symbol))
16614 {
16615 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) {
16616 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}};
16617 }
16618
16619 if(not keys(%Paths))
16620 {
16621 if(defined $Prefix_Lib_Map{$SymbolPrefix})
16622 {
16623 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}})
16624 {
16625 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16626 $Paths{$Path} = 1;
16627 }
16628 }
16629 }
16630 }
16631
16632 if(not keys(%Paths))
16633 {
16634 foreach my $Prefix (sort keys(%Pattern_Lib_Map))
16635 {
16636 if($Symbol=~/\A$Prefix/)
16637 {
16638 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}})
16639 {
16640 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16641 $Paths{$Path} = 1;
16642 }
16643 }
16644 }
16645 }
16646 }
16647
16648 if(not keys(%Paths))
16649 {
16650 if($SymbolPrefix)
16651 { # try to find a library by symbol prefix
16652 if($SymbolPrefix eq "inotify" and
16653 index($Symbol, "\@GLIBC")!=-1)
16654 {
16655 if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) {
16656 $Paths{$Path} = 1;
16657 }
16658 }
16659 else
16660 {
16661 if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) {
16662 $Paths{$Path} = 1;
16663 }
16664 }
16665 }
16666 }
16667
16668 if(my @Paths = keys(%Paths)) {
16669 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths;
16670 }
16671 }
16672 return keys(%Paths);
16673}
16674
16675sub get_LibPath_Prefix($$)
16676{
16677 my ($LibVersion, $Prefix) = @_;
16678
16679 $Prefix = lc($Prefix);
16680 $Prefix=~s/[_]+\Z//g;
16681
16682 foreach ("-2", "2", "-1", "1", "")
16683 { # libgnome-2.so
16684 # libxml2.so
16685 # libdbus-1.so
16686 if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) {
16687 return $Path;
16688 }
16689 }
16690 return "";
16691}
16692
16693sub getPrefix($)
16694{
16695 my $Str = $_[0];
16696 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
16697 { # XmuValidArea: Xmu
16698 return $1;
16699 }
16700 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
16701 { # snfReadFont: snf
16702 return $1;
16703 }
16704 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
16705 { # XRRTimes: XRR
16706 return $1;
16707 }
16708 elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i)
16709 { # H5HF_delete: H5
16710 return $1;
16711 }
16712 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
16713 { # alarm_event_add: alarm_
16714 return $1;
16715 }
16716 elsif($Str=~/\A(([a-z])\2{1,})/i)
16717 { # ffopen
16718 return $1;
16719 }
16720 return "";
16721}
16722
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016723sub getSymbolSize($$)
16724{ # size from the shared library
16725 my ($Symbol, $LibVersion) = @_;
16726 return 0 if(not $Symbol);
16727 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16728 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16729 {
16730 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16731 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16732 {
16733 if($Size<0) {
16734 return -$Size;
16735 }
16736 }
16737 }
16738 return 0;
16739}
16740
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016741sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016742{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16743 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016744 my ($Name, $Type) = @_;
16745
16746 # single
16747 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016748 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016749 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016750 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016751 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016752
16753 # double
16754 if($Name=~/$DEFAULT_STD_PARMS/)
16755 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016756 if($Type eq "S")
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016757 {
16758 my ($ShortName, $FuncParams) = split_Signature($Name);
16759
16760 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16761 {
16762 if(index($FParam, "<")!=-1)
16763 {
16764 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16765 my $FParam_N = canonifyName($FParam, "T");
16766 if($FParam_N ne $FParam) {
16767 $Name=~s/\Q$FParam\E/$FParam_N/g;
16768 }
16769 }
16770 }
16771 }
16772 elsif($Type eq "T")
16773 {
16774 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16775
16776 my @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016777 if($#TParams>=1)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016778 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016779 my $FParam = $TParams[0];
16780 foreach my $Pos (1 .. $#TParams)
16781 {
16782 my $TParam = $TParams[$Pos];
16783 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
16784 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
16785 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016786 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016787 }
16788 }
16789 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016790 if($Type eq "S") {
16791 return formatName($Name, "S");
16792 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016793 return $Name;
16794}
16795
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016796sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016797{
16798 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016799 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016800 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016801 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016802 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016803 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016804 next if($tr_name{$Symbol});
16805 $Symbol=~s/[\@\$]+(.*)\Z//;
16806 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016807 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016808 elsif(index($Symbol, "?")==0)
16809 {
16810 next if($tr_name{$Symbol});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016811 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016812 }
16813 else
16814 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016815 $tr_name{$Symbol} = $Symbol;
16816 $mangled_name_gcc{$Symbol} = $Symbol;
16817 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016818 }
16819 }
16820 if($#MnglNames1 > -1)
16821 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016822 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016823 foreach my $MnglName (@MnglNames1)
16824 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016825 if(my $Unmangled = pop(@UnmangledNames))
16826 {
Andrey Ponomarenko72930b92012-11-14 12:09:17 +040016827 $tr_name{$MnglName} = canonifyName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016828 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16829 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16830 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016831 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016832 and $tr_name{$MnglName}=~/vtable for (.+)/)
16833 { # bind class name and v-table symbol
16834 my $ClassName = $1;
16835 $ClassVTable{$ClassName} = $MnglName;
16836 $VTableClass{$MnglName} = $ClassName;
16837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016838 }
16839 }
16840 }
16841 if($#MnglNames2 > -1)
16842 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016843 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016844 foreach my $MnglName (@MnglNames2)
16845 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016846 if(my $Unmangled = pop(@UnmangledNames))
16847 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016848 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016849 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16850 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016851 }
16852 }
16853 return \%tr_name;
16854}
16855
16856sub link_symbol($$$)
16857{
16858 my ($Symbol, $RunWith, $Deps) = @_;
16859 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16860 return 1;
16861 }
16862 if($Deps eq "+Deps")
16863 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016864 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016865 return 1;
16866 }
16867 }
16868 return 0;
16869}
16870
16871sub link_symbol_internal($$$)
16872{
16873 my ($Symbol, $RunWith, $Where) = @_;
16874 return 0 if(not $Where or not $Symbol);
16875 if($Where->{$RunWith}{$Symbol})
16876 { # the exact match by symbol name
16877 return 1;
16878 }
16879 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16880 { # indirect symbol version, i.e.
16881 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016882 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016883 if($Where->{$RunWith}{$VSym}) {
16884 return 1;
16885 }
16886 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016887 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016888 if($Sym and $Ver)
16889 { # search for the symbol with the same version
16890 # or without version
16891 if($Where->{$RunWith}{$Sym})
16892 { # old: foo@v|foo@@v
16893 # new: foo
16894 return 1;
16895 }
16896 if($Where->{$RunWith}{$Sym."\@".$Ver})
16897 { # old: foo|foo@@v
16898 # new: foo@v
16899 return 1;
16900 }
16901 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16902 { # old: foo|foo@v
16903 # new: foo@@v
16904 return 1;
16905 }
16906 }
16907 return 0;
16908}
16909
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016910sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016911{
16912 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016913 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016914 my @Imported = ();
16915 if($OSgroup eq "macos")
16916 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016917 my $NM = get_CmdPath("nm");
16918 if(not $NM) {
16919 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016920 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016921 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016922 while(<APP>)
16923 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016924 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016925 push(@Imported, $1);
16926 }
16927 }
16928 close(APP);
16929 }
16930 elsif($OSgroup eq "windows")
16931 {
16932 my $DumpBinCmd = get_CmdPath("dumpbin");
16933 if(not $DumpBinCmd) {
16934 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16935 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016936 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016937 while(<APP>)
16938 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016939 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16940 push(@Imported, $1);
16941 }
16942 }
16943 close(APP);
16944 }
16945 else
16946 {
16947 my $ReadelfCmd = get_CmdPath("readelf");
16948 if(not $ReadelfCmd) {
16949 exitStatus("Not_Found", "can't find \"readelf\"");
16950 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016951 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016952 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016953 while(<APP>)
16954 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016955 if(defined $symtab)
16956 { # do nothing with symtab
16957 if(index($_, "'.dynsym'")!=-1)
16958 { # dynamic table
16959 $symtab = undef;
16960 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016961 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016962 elsif(index($_, "'.symtab'")!=-1)
16963 { # symbol table
16964 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016965 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016966 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016967 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016968 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16969 if($Ndx eq "UND")
16970 { # only imported symbols
16971 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016972 }
16973 }
16974 }
16975 close(APP);
16976 }
16977 return @Imported;
16978}
16979
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016980my %ELF_BIND = map {$_=>1} (
16981 "WEAK",
16982 "GLOBAL"
16983);
16984
16985my %ELF_TYPE = map {$_=>1} (
16986 "FUNC",
16987 "IFUNC",
16988 "OBJECT",
16989 "COMMON"
16990);
16991
16992my %ELF_VIS = map {$_=>1} (
16993 "DEFAULT",
16994 "PROTECTED"
16995);
16996
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016997sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016998{ # read the line of 'readelf' output corresponding to the symbol
16999 my @Info = split(/\s+/, $_[0]);
17000 # Num: Value Size Type Bind Vis Ndx Name
17001 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
17002 shift(@Info); # spaces
17003 shift(@Info); # num
17004 if($#Info!=6)
17005 { # other lines
17006 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017007 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017008 return () if(not defined $ELF_TYPE{$Info[2]});
17009 return () if(not defined $ELF_BIND{$Info[3]});
17010 return () if(not defined $ELF_VIS{$Info[4]});
17011 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
17012 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
17013 return ();
17014 }
17015 if($OStarget eq "symbian")
17016 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
17017 if(index($Info[6], "_._.absent_export_")!=-1)
17018 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
17019 return ();
17020 }
17021 $Info[6]=~s/\@.+//g; # remove version
17022 }
17023 if(index($Info[2], "0x") == 0)
17024 { # size == 0x3d158
17025 $Info[2] = hex($Info[2]);
17026 }
17027 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017028}
17029
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017030sub read_symlink($)
17031{
17032 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017033 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017034 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017035 }
17036 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017037 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017038 }
17039 elsif(my $FileCmd = get_CmdPath("file"))
17040 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017041 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017042 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017043 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017044 }
17045 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017046
17047 # can't read
17048 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017049}
17050
17051sub resolve_symlink($)
17052{
17053 my $Path = $_[0];
17054 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017055
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017056 if(defined $Cache{"resolve_symlink"}{$Path}) {
17057 return $Cache{"resolve_symlink"}{$Path};
17058 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017059 if(not -f $Path and not -l $Path)
17060 { # broken
17061 return ($Cache{"resolve_symlink"}{$Path} = "");
17062 }
17063 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
17064}
17065
17066sub resolve_symlink_I($)
17067{
17068 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017069 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017070 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017071 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017072 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017073 {
17074 if(is_abs($Redirect))
17075 { # absolute path
17076 if($SystemRoot and $SystemRoot ne "/"
17077 and $Path=~/\A\Q$SystemRoot\E\//
17078 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
17079 { # symbolic links from the sysroot
17080 # should be corrected to point to
17081 # the files inside sysroot
17082 $Redirect = $SystemRoot.$Redirect;
17083 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017084 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017085 }
17086 elsif($Redirect=~/\.\.[\/\\]/)
17087 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017088 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017089 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017090 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017091 }
17092 elsif(-f get_dirname($Path)."/".$Redirect)
17093 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017094 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017095 }
17096 else
17097 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017098 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017099 }
17100 }
17101 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017102 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017103}
17104
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017105sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017106{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017107 my ($LibVersion, $Name) = @_;
17108 return "" if(not $LibVersion or not $Name);
17109 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
17110 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017111 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017112 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
17113}
17114
17115sub get_LibPath_I($$)
17116{
17117 my ($LibVersion, $Name) = @_;
17118 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017119 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017120 if(-f $Name)
17121 { # absolute path
17122 return $Name;
17123 }
17124 else
17125 { # broken
17126 return "";
17127 }
17128 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017129 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017130 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017131 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017132 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017133 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017134 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017135 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017136 }
17137 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
17138 { # ldconfig default paths
17139 return $DefaultPath;
17140 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017141 foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017142 { # search in default linker directories
17143 # and then in all system paths
17144 if(-f $Dir."/".$Name) {
17145 return joinPath($Dir,$Name);
17146 }
17147 }
17148 detectSystemObjects() if(not keys(%SystemObjects));
17149 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
17150 return $AllObjects[0];
17151 }
17152 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
17153 {
17154 if($ShortName ne $Name)
17155 { # FIXME: check this case
17156 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
17157 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017158 }
17159 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017160 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017161 # can't find
17162 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017163}
17164
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017165sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017166{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017167 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
17168 return () if(not $LibVersion or not $Lib_Path);
17169 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
17170 if($IsNeededLib)
17171 {
17172 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
17173 return ();
17174 }
17175 }
17176 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017177 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017178
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017179 if($CheckImpl)
17180 {
17181 if(not $IsNeededLib) {
17182 getImplementations($LibVersion, $Lib_Path);
17183 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017184 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017185
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017186 push(@RecurLib, $Lib_Name);
17187 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017188 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
17189
17190 if(not $IsNeededLib)
17191 { # special cases: libstdc++ and libc
17192 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget))
17193 {
17194 if($ShortName eq "libstdc++")
17195 { # libstdc++.so.6
17196 $STDCXX_TESTING = 1;
17197 }
17198 elsif($ShortName eq "libc")
17199 { # libc-2.11.3.so
17200 $GLIBC_TESTING = 1;
17201 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017202 }
17203 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017204 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017205 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017206 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017207 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017208 mkpath(get_dirname($DebugPath));
17209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017210 if($OStarget eq "macos")
17211 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017212 my $NM = get_CmdPath("nm");
17213 if(not $NM)
17214 {
17215 print STDERR "ERROR: can't find \"nm\"\n";
17216 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017217 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017218 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017219 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017220 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017221 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017222 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017223 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017224 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017225 else
17226 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017227 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017228 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017229 while(<LIB>)
17230 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017231 if($CheckUndefined)
17232 {
17233 if(not $IsNeededLib)
17234 {
17235 if(/ U _([\w\$]+)\s*\Z/)
17236 {
17237 $UndefinedSymbols{$LibVersion}{$Lib_Path}{$1} = 1;
17238 next;
17239 }
17240 }
17241 }
17242
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017243 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017244 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017245 my $Symbol = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017246 if($IsNeededLib)
17247 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017248 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017249 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017250 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17251 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017252 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017254 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017255 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017256 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17257 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017258 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17259 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017260 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017261 setLanguage($LibVersion, "C++");
17262 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017263 }
17264 if($CheckObjectsOnly
17265 and $LibVersion==1) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017266 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017267 }
17268 }
17269 }
17270 }
17271 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017272
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017273 if($Deps)
17274 {
17275 if($LIB_TYPE eq "dynamic")
17276 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017277
17278 my $OtoolCmd = get_CmdPath("otool");
17279 if(not $OtoolCmd)
17280 {
17281 print STDERR "ERROR: can't find \"otool\"\n";
17282 exit(1);
17283 }
17284
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017285 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17286 while(<LIB>)
17287 {
17288 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
17289 and $1 ne $Lib_Path) {
17290 $NeededLib{$1} = 1;
17291 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017292 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017293 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017295 }
17296 }
17297 elsif($OStarget eq "windows")
17298 { # Windows *.dll, *.lib
17299 my $DumpBinCmd = get_CmdPath("dumpbin");
17300 if(not $DumpBinCmd) {
17301 exitStatus("Not_Found", "can't find \"dumpbin\"");
17302 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017303 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017304 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017305 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017306 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017307 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017308 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017309 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017310 else
17311 { # write to pipe
17312 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017313 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017314 while(<LIB>)
17315 { # 1197 4AC 0000A620 SetThreadStackGuarantee
17316 # 1198 4AD SetThreadToken (forwarded to ...)
17317 # 3368 _o2i_ECPublicKey
17318 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
17319 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
17320 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
17321 { # dynamic, static and forwarded symbols
17322 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017323 if($IsNeededLib)
17324 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017325 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017326 {
17327 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
17328 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
17329 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017330 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017331 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017332 {
17333 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
17334 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017335 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17336 {
17337 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
17338 setLanguage($LibVersion, "C++");
17339 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017340 }
17341 if($CheckObjectsOnly
17342 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017343 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017344 }
17345 }
17346 }
17347 }
17348 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017349 if($Deps)
17350 {
17351 if($LIB_TYPE eq "dynamic")
17352 { # dependencies
17353 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17354 while(<LIB>)
17355 {
17356 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
17357 and $1 ne $Lib_Path) {
17358 $NeededLib{path_format($1, $OSgroup)} = 1;
17359 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017360 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017361 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017362 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017363 }
17364 }
17365 else
17366 { # Unix; *.so, *.a
17367 # Symbian: *.dso, *.lib
17368 my $ReadelfCmd = get_CmdPath("readelf");
17369 if(not $ReadelfCmd) {
17370 exitStatus("Not_Found", "can't find \"readelf\"");
17371 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017372 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17373 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017374 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017375 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017376 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017377 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017378 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017379 else
17380 { # write to pipe
17381 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017382 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017383 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017384 while(<LIB>)
17385 {
17386 if($LIB_TYPE eq "dynamic")
17387 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017388 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017389 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017390 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017391 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017392 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017393 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017394 # do nothing with symtab
17395 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017396 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017397 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017398 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017399 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017400 next;
17401 }
17402 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017403 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017404 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017405 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017406 { # ignore interfaces that are imported from somewhere else
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017407 if($CheckUndefined)
17408 {
17409 if(not $IsNeededLib) {
17410 $UndefinedSymbols{$LibVersion}{$Lib_Path}{$Symbol} = 1;
17411 }
17412 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017413 next;
17414 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017415 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017416 and $Weak eq "-Weak")
17417 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017418 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017419 next;
17420 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017421 my $Short = $Symbol;
17422 $Short=~s/\@.+//g;
17423 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017424 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017425 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17426 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017427 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017428 if($IsNeededLib)
17429 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017430 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017431 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017432 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17433 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017434 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017435 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017436 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017437 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017438 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17439 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17440 if($Vers)
17441 {
17442 if($LIB_EXT eq "so")
17443 { # value
17444 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17445 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017447 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017448 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17449 {
17450 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17451 setLanguage($LibVersion, "C++");
17452 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017453 }
17454 if($CheckObjectsOnly
17455 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017456 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017457 }
17458 }
17459 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017460 elsif($LIB_TYPE eq "dynamic")
17461 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017462 if($Deps)
17463 {
17464 if(/NEEDED.+\[([^\[\]]+)\]/)
17465 { # dependencies:
17466 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17467 $NeededLib{$1} = 1;
17468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017469 }
17470 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017471 }
17472 close(LIB);
17473 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017474 if($Vers)
17475 {
17476 if(not $IsNeededLib and $LIB_EXT eq "so")
17477 { # get symbol versions
17478 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017479 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017480 next if(index($Symbol,"\@")==-1);
17481 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017482 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017483 my $Interface_SymName = "";
17484 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017485 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017486 if($Symbol_SameValue ne $Symbol
17487 and index($Symbol_SameValue,"\@")==-1)
17488 {
17489 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17490 $Interface_SymName = $Symbol_SameValue;
17491 last;
17492 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017493 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017494 if(not $Interface_SymName)
17495 {
17496 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17497 and not $SymVer{$LibVersion}{$1}) {
17498 $SymVer{$LibVersion}{$1} = $Symbol;
17499 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017500 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017501 }
17502 }
17503 }
17504 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017505 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017506 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017507 foreach my $DyLib (sort keys(%NeededLib))
17508 {
17509 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17510 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17511 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017512 }
17513 }
17514 pop(@RecurLib);
17515 return $Library_Symbol{$LibVersion};
17516}
17517
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017518sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017519{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017520 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017521 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017522 return keys(%Prefixes);
17523}
17524
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017525sub get_prefixes_I($$)
17526{
17527 foreach my $P (@{$_[0]})
17528 {
17529 my @Parts = reverse(split(/[\/\\]+/, $P));
17530 my $Name = $Parts[0];
17531 foreach (1 .. $#Parts)
17532 {
17533 $_[1]->{$Name}{$P} = 1;
17534 last if($_>4 or $Parts[$_] eq "include");
17535 $Name = $Parts[$_].$SLASH.$Name;
17536 }
17537 }
17538}
17539
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017540sub detectSystemHeaders()
17541{
17542 my @SysHeaders = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017543 foreach my $DevelPath (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017544 {
17545 next if(not -d $DevelPath);
17546 # search for all header files in the /usr/include
17547 # with or without extension (ncurses.h, QtCore, ...)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017548 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f"));
17549 foreach my $Link (cmd_find($DevelPath,"l"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017550 { # add symbolic links
17551 if(-f $Link) {
17552 push(@SysHeaders, $Link);
17553 }
17554 }
17555 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017556 foreach my $DevelPath (@{$SystemPaths{"lib"}})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017557 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017558 next if(not -d $DevelPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017559 foreach (cmd_find($DevelPath,"f"))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017560 {
17561 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17562 {
17563 if(/\.h\Z|\/include\//) {
17564 push(@SysHeaders, $_);
17565 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017566 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017567 }
17568 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017569 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017570}
17571
17572sub detectSystemObjects()
17573{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017574 foreach my $DevelPath (@{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017575 {
17576 next if(not -d $DevelPath);
17577 foreach my $Path (find_libs($DevelPath,"",""))
17578 { # search for shared libraries in the /usr/lib (including symbolic links)
17579 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17580 }
17581 }
17582}
17583
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017584sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017585{
17586 my $LibVersion = $_[0];
17587 my @SoPaths = ();
17588 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17589 {
17590 if(not -e $Dest) {
17591 exitStatus("Access_Error", "can't access \'$Dest\'");
17592 }
17593 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17594 foreach (@SoPaths_Dest) {
17595 push(@SoPaths, $_);
17596 }
17597 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017598 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017599}
17600
17601sub skip_lib($$)
17602{
17603 my ($Path, $LibVersion) = @_;
17604 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017605 my $Name = get_filename($Path);
17606 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017607 return 1;
17608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017609 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017610 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17611 return 1;
17612 }
17613 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17614 {
17615 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17616 return 1;
17617 }
17618 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017619 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017620 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017621 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017622 return 1;
17623 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017624 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017625 return 1;
17626 }
17627 }
17628 return 0;
17629}
17630
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017631sub skipHeader($$)
17632{
17633 my ($Path, $LibVersion) = @_;
17634 return 1 if(not $Path or not $LibVersion);
17635 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17636 return 0;
17637 }
17638 if(defined $Cache{"skipHeader"}{$Path}) {
17639 return $Cache{"skipHeader"}{$Path};
17640 }
17641 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17642}
17643
17644sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017645{ # returns:
17646 # 1 - if header should NOT be included and checked
17647 # 2 - if header should NOT be included, but should be checked
17648 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017649 my $Name = get_filename($Path);
17650 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017651 return $Kind;
17652 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017653 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017654 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017655 if(index($Path, $D)!=-1)
17656 {
17657 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17658 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017660 }
17661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017662 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017663 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017664 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17665 {
17666 if($Name=~/$P/) {
17667 return $Kind;
17668 }
17669 if($P=~/[\/\\]/ and $Path=~/$P/) {
17670 return $Kind;
17671 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017672 }
17673 }
17674 return 0;
17675}
17676
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017677sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017678{
17679 my ($Dir, $LibVersion) = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017680 if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017681 { # system directory
17682 return;
17683 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017684 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017685 { # already registered
17686 return;
17687 }
17688 foreach my $Path (find_libs($Dir,"",1))
17689 {
17690 next if(ignore_path($Path));
17691 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017692 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017693 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017694 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17695}
17696
17697sub registerObject($$)
17698{
17699 my ($Path, $LibVersion) = @_;
17700 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017701 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017702 if($OSgroup=~/linux|bsd/i)
17703 {
17704 if(my $SONAME = getSONAME($Path)) {
17705 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17706 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017707 }
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017708 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) {
17709 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017710 }
17711}
17712
17713sub getSONAME($)
17714{
17715 my $Path = $_[0];
17716 return if(not $Path);
17717 if(defined $Cache{"getSONAME"}{$Path}) {
17718 return $Cache{"getSONAME"}{$Path};
17719 }
17720 my $ObjdumpCmd = get_CmdPath("objdump");
17721 if(not $ObjdumpCmd) {
17722 exitStatus("Not_Found", "can't find \"objdump\"");
17723 }
17724 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17725 if($OSgroup eq "windows") {
17726 $SonameCmd .= " | find \"SONAME\"";
17727 }
17728 else {
17729 $SonameCmd .= " | grep SONAME";
17730 }
17731 if(my $SonameInfo = `$SonameCmd`) {
17732 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17733 return ($Cache{"getSONAME"}{$Path} = $1);
17734 }
17735 }
17736 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017737}
17738
17739sub getSOPaths_Dest($$)
17740{
17741 my ($Dest, $LibVersion) = @_;
17742 if(skip_lib($Dest, $LibVersion)) {
17743 return ();
17744 }
17745 if(-f $Dest)
17746 {
17747 if(not parse_libname($Dest, "name", $OStarget)) {
17748 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17749 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017750 registerObject($Dest, $LibVersion);
17751 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017752 return ($Dest);
17753 }
17754 elsif(-d $Dest)
17755 {
17756 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017757 my %Libs = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017758 if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017759 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17760 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017761 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017762 { # all files and symlinks that match the name of a library
17763 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17764 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017765 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017766 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017767 }
17768 }
17769 }
17770 else
17771 { # search for all files and symlinks
17772 foreach my $Path (find_libs($Dest,"",""))
17773 {
17774 next if(ignore_path($Path));
17775 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017776 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017777 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017778 }
17779 if($OSgroup eq "macos")
17780 { # shared libraries on MacOS X may have no extension
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017781 foreach my $Path (cmd_find($Dest,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017782 {
17783 next if(ignore_path($Path));
17784 next if(skip_lib($Path, $LibVersion));
17785 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017786 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17787 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017788 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017789 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017790 }
17791 }
17792 }
17793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017794 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017795 }
17796 else {
17797 return ();
17798 }
17799}
17800
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017801sub isCyclical($$)
17802{
17803 my ($Stack, $Value) = @_;
17804 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017805}
17806
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017807sub detectWordSize()
17808{
17809 return "" if(not $GCC_PATH);
17810 if($Cache{"detectWordSize"}) {
17811 return $Cache{"detectWordSize"};
17812 }
17813 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017814 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017815 unlink("$TMP_DIR/empty.h");
17816 my $WSize = 0;
17817 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017818 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017819 $WSize = $1;
17820 }
17821 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017822 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017823 my $PTRDIFF = $1;
17824 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017825 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017826 }
17827 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017828 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017829 }
17830 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017831 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017832 exitStatus("Error", "can't check WORD size");
17833 }
17834 return ($Cache{"detectWordSize"} = $WSize);
17835}
17836
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017837sub getWordSize($) {
17838 return $WORD_SIZE{$_[0]};
17839}
17840
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017841sub majorVersion($)
17842{
17843 my $V = $_[0];
17844 return 0 if(not $V);
17845 my @VParts = split(/\./, $V);
17846 return $VParts[0];
17847}
17848
17849sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017850{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017851 my ($V1, $V2) = @_;
17852 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017853 my @V1Parts = split(/\./, $V1);
17854 my @V2Parts = split(/\./, $V2);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017855 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++)
17856 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017857 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17858 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17859 }
17860 return -1 if($#V1Parts < $#V2Parts);
17861 return 1 if($#V1Parts > $#V2Parts);
17862 return 0;
17863}
17864
17865sub read_ABI_Dump($$)
17866{
17867 my ($LibVersion, $Path) = @_;
17868 return if(not $LibVersion or not -e $Path);
17869 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017870 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017871 { # input *.abi
17872 $FilePath = $Path;
17873 }
17874 else
17875 { # input *.abi.tar.gz
17876 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017877 if(not isDump_U($FilePath)) {
17878 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17879 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017880 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017881
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017882 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017883
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017884 my $Line = readLineNum($FilePath, 0);
17885 if($Line=~/xml/)
17886 { # XML format
17887 loadModule("XmlDump");
17888 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017889 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017890 else
17891 { # Perl Data::Dumper format (default)
17892 open(DUMP, $FilePath);
17893 local $/ = undef;
17894 my $Content = <DUMP>;
17895 close(DUMP);
17896
17897 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17898 { # remove temp file
17899 unlink($FilePath);
17900 }
17901 if($Content!~/};\s*\Z/) {
17902 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17903 }
17904 $ABI = eval($Content);
17905 if(not $ABI) {
17906 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017908 }
17909 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017910 my $DVersion = $ABI->{"ABI_DUMP_VERSION"};
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017911 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017912 if(not $DVersion)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017913 { # old dumps (<=1.21.6) have been marked by the tool version
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017914 $DVersion = $ToolVersion;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017915 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017916 $UsedDump{$LibVersion}{"V"} = $DVersion;
17917 if(majorVersion($DVersion) ne majorVersion($ABI_DUMP_VERSION))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017918 { # should be compatible with dumps of the same major version
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017919 if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017920 { # Don't know how to parse future dump formats
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017921 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017922 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017923 elsif(cmpVersions($DVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017924 { # Don't know how to parse future dump formats
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017925 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017926 }
17927 if($UseOldDumps)
17928 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017929 if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) {
17930 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017931 }
17932 }
17933 else
17934 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017935 my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
17936 if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017937 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17938 }
17939 exitStatus("Dump_Version", $Msg);
17940 }
17941 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017942 if(not checkDump($LibVersion, "2.11"))
17943 { # old ABI dumps
17944 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017945 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017946 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017947 { # ABI dump created with --binary option
17948 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17949 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017950 else
17951 { # default
17952 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17953 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017954 if(defined $ABI->{"Mode"}
17955 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017956 { # --ext option
17957 $ExtendedCheck = 1;
17958 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017959 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017960 {
17961 $UsedDump{$LibVersion}{"L"} = $Lang;
17962 setLanguage($LibVersion, $Lang);
17963 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017964 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017965 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017966 }
17967 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017968 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017969 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017970 if(not $TInfo)
17971 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017972 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017973 }
17974 my %Tid_TDid = ();
17975 foreach my $TDid (keys(%{$TInfo}))
17976 {
17977 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17978 {
17979 $MAX_ID = $Tid if($Tid>$MAX_ID);
17980 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17981 $Tid_TDid{$Tid}{$TDid}=1;
17982 }
17983 }
17984 my %NewID = ();
17985 foreach my $Tid (keys(%Tid_TDid))
17986 {
17987 my @TDids = keys(%{$Tid_TDid{$Tid}});
17988 if($#TDids>=1)
17989 {
17990 foreach my $TDid (@TDids)
17991 {
17992 if($TDid) {
17993 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17994 }
17995 else
17996 {
17997 if(my $ID = ++$MAX_ID)
17998 {
17999 $NewID{$TDid}{$Tid} = $ID;
18000 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
18001 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
18002 }
18003 }
18004 }
18005 }
18006 else
18007 {
18008 my $TDid = $TDids[0];
18009 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
18010 }
18011 }
18012 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
18013 {
18014 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
18015 if(defined $Info{"BaseType"})
18016 {
18017 my $Bid = $Info{"BaseType"}{"Tid"};
18018 my $BDid = $Info{"BaseType"}{"TDid"};
18019 $BDid="" if(not defined $BDid);
18020 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
18021 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
18022 }
18023 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
18024 }
18025 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
18026 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018027 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018028 read_Machine_DumpInfo($ABI, $LibVersion);
18029 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018030 if(not $SymbolInfo{$LibVersion})
18031 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018032 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018033 }
18034 if(not keys(%{$SymbolInfo{$LibVersion}}))
18035 { # validation of old-version dumps
18036 if(not $ExtendedCheck) {
18037 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
18038 }
18039 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018040 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018041 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018042 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018043 else
18044 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018045 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018046 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018047 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018048 }
18049 if(not $DepSymbols)
18050 { # Cannot reconstruct DepSymbols. This may result in false
18051 # positives if the old dump is for library 2. Not a problem if
18052 # old dumps are only from old libraries.
18053 $DepSymbols = {};
18054 }
18055 foreach my $Symbol (keys(%{$DepSymbols})) {
18056 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
18057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018058 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018059 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
18060 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
18061 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018062 if(not $SkipTypes{$LibVersion})
18063 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018064 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018065 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018066 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018067 if(not $SkipSymbols{$LibVersion})
18068 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018069 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018070 }
18071 if(not $SkipSymbols{$LibVersion})
18072 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018073 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018074 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018075 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
18076 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
18077 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018078 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018079 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018080 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018081 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018082 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018083 read_Headers_DumpInfo($ABI, $LibVersion);
18084 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018085 if(not checkDump($LibVersion, "2.10.1")
18086 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018087 { # support for old ABI dumps: added target headers
18088 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
18089 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018090 }
18091 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018092 $Constants{$LibVersion} = $ABI->{"Constants"};
18093 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018094 if(not $NestedNameSpaces{$LibVersion})
18095 { # support for old dumps
18096 # Cannot reconstruct NameSpaces. This may affect design
18097 # of the compatibility report.
18098 $NestedNameSpaces{$LibVersion} = {};
18099 }
18100 # target system type
18101 # needed to adopt HTML report
18102 if(not $DumpSystem)
18103 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018104 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018105 }
18106 # recreate environment
18107 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
18108 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018109 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018110 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018111 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
18112 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018113 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018114 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018115 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018116 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
18117 {
18118 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
18119 setLanguage($LibVersion, "C++");
18120 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018121 }
18122 }
18123 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018124 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
18125 {
18126 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
18127 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
18128 }
18129 }
18130
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018131 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018132 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018133 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018134 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018135 {
18136 if(not $Symbol_Library{$LibVersion}{$MnglName}
18137 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
18138 push(@VFunc, $MnglName);
18139 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018140 }
18141 }
18142 translateSymbols(@VFunc, $LibVersion);
18143 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018144 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
18145
18146 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018147 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018148 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
18149 { # support for old ABI dumps < 2.0 (ACC 1.22)
18150 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
18151 {
18152 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
18153 {
18154 if($Access ne "public") {
18155 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
18156 }
18157 }
18158 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
18159 }
18160 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
18161 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018162 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
18163 { # support for old ABI dumps
18164 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
18165 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018166 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
18167 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
18168 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018169 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
18170 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018171 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018172 foreach (keys(%{$TInfo{"Base"}})) {
18173 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018174 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018175 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018176 if($TInfo{"Type"} eq "MethodPtr")
18177 {
18178 if(defined $TInfo{"Param"})
18179 { # support for old ABI dumps <= 1.17
18180 if(not defined $TInfo{"Param"}{"0"})
18181 {
18182 my $Max = keys(%{$TInfo{"Param"}});
18183 foreach my $Pos (1 .. $Max) {
18184 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
18185 }
18186 delete($TInfo{"Param"}{$Max});
18187 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
18188 }
18189 }
18190 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018191 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
18192 {
18193 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018194 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018195 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
18196 if(not $BName)
18197 { # broken type
18198 next;
18199 }
18200 if($TInfo{"Name"} eq $BName)
18201 { # typedef to "class Class"
18202 # should not be registered in TName_Tid
18203 next;
18204 }
18205 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
18206 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018207 }
18208 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018209 }
18210 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
18211 { # classes: class (id1), typedef (artificial, id2 > id1)
18212 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
18213 }
18214 }
18215
18216 if(not checkDump($LibVersion, "2.15"))
18217 { # support for old ABI dumps
18218 my %Dups = ();
18219 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
18220 {
18221 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018222 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018223 if(not defined $TypeInfo{$LibVersion}{$ClassId})
18224 { # remove template decls
18225 delete($SymbolInfo{$LibVersion}{$InfoId});
18226 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018227 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018228 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040018229 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
18230 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018231 { # templates
18232 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018233 }
18234 }
18235 }
18236
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018237 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
18238 {
18239 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
18240 { # ABI dumps have no mangled names for C-functions
18241 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
18242 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018243 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
18244 { # support for old ABI dumps
18245 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
18246 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018247 }
18248
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018249 $Descriptor{$LibVersion}{"Dump"} = 1;
18250}
18251
18252sub read_Machine_DumpInfo($$)
18253{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018254 my ($ABI, $LibVersion) = @_;
18255 if($ABI->{"Arch"}) {
18256 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018257 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018258 if($ABI->{"WordSize"}) {
18259 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018260 }
18261 else
18262 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018263 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018264 }
18265 if(not $WORD_SIZE{$LibVersion})
18266 { # support for old dumps (<1.23)
18267 if(my $Tid = getTypeIdByName("char*", $LibVersion))
18268 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018269 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018270 }
18271 else
18272 {
18273 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018274 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018275 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018276 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
18277 { # any "pointer"-type
18278 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018279 last;
18280 }
18281 }
18282 if($PSize)
18283 { # a pointer type size
18284 $WORD_SIZE{$LibVersion} = $PSize;
18285 }
18286 else {
18287 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
18288 }
18289 }
18290 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018291 if($ABI->{"GccVersion"}) {
18292 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018293 }
18294}
18295
18296sub read_Libs_DumpInfo($$)
18297{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018298 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018299 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
18300 if(not $Library_Symbol{$LibVersion})
18301 { # support for old dumps
18302 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
18303 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018304 if(keys(%{$Library_Symbol{$LibVersion}})
18305 and not $DumpAPI) {
18306 $Descriptor{$LibVersion}{"Libs"} = "OK";
18307 }
18308}
18309
18310sub read_Headers_DumpInfo($$)
18311{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018312 my ($ABI, $LibVersion) = @_;
18313 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018314 and not $DumpAPI) {
18315 $Descriptor{$LibVersion}{"Headers"} = "OK";
18316 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018317 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018318 { # headers info is stored in the old dumps in the different way
18319 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018320 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018321 { # support for old dumps: headers info corrected in 1.22
18322 $Identity = $Name;
18323 }
18324 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018325 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018326 }
18327}
18328
18329sub find_libs($$$)
18330{
18331 my ($Path, $Type, $MaxDepth) = @_;
18332 # FIXME: correct the search pattern
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018333 return cmd_find($Path, $Type, ".*\\.".$LIB_EXT."[0-9.]*", $MaxDepth, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018334}
18335
18336sub createDescriptor($$)
18337{
18338 my ($LibVersion, $Path) = @_;
18339 if(not $LibVersion or not $Path
18340 or not -e $Path) {
18341 return "";
18342 }
18343 if(-d $Path)
18344 { # directory with headers files and shared objects
18345 return "
18346 <version>
18347 ".$TargetVersion{$LibVersion}."
18348 </version>
18349
18350 <headers>
18351 $Path
18352 </headers>
18353
18354 <libs>
18355 $Path
18356 </libs>";
18357 }
18358 else
18359 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018360 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018361 { # standard XML-descriptor
18362 return readFile($Path);
18363 }
18364 elsif(is_header($Path, 2, $LibVersion))
18365 { # header file
18366 return "
18367 <version>
18368 ".$TargetVersion{$LibVersion}."
18369 </version>
18370
18371 <headers>
18372 $Path
18373 </headers>
18374
18375 <libs>
18376 none
18377 </libs>";
18378 }
18379 elsif(parse_libname($Path, "name", $OStarget))
18380 { # shared object
18381 return "
18382 <version>
18383 ".$TargetVersion{$LibVersion}."
18384 </version>
18385
18386 <headers>
18387 none
18388 </headers>
18389
18390 <libs>
18391 $Path
18392 </libs>";
18393 }
18394 else
18395 { # standard XML-descriptor
18396 return readFile($Path);
18397 }
18398 }
18399}
18400
18401sub detect_lib_default_paths()
18402{
18403 my %LPaths = ();
18404 if($OSgroup eq "bsd")
18405 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018406 if(my $LdConfig = get_CmdPath("ldconfig"))
18407 {
18408 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18409 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018410 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18411 $LPaths{"lib".$1} = $2;
18412 }
18413 }
18414 }
18415 else {
18416 printMsg("WARNING", "can't find ldconfig");
18417 }
18418 }
18419 else
18420 {
18421 if(my $LdConfig = get_CmdPath("ldconfig"))
18422 {
18423 if($SystemRoot and $OSgroup eq "linux")
18424 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18425 if(-e $SystemRoot."/etc/ld.so.conf") {
18426 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18427 }
18428 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018429 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18430 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018431 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18432 {
18433 my ($Name, $Path) = ($1, $2);
18434 $Path=~s/[\/]{2,}/\//;
18435 $LPaths{$Name} = $Path;
18436 }
18437 }
18438 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018439 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018440 printMsg("WARNING", "can't find ldconfig");
18441 }
18442 }
18443 return \%LPaths;
18444}
18445
18446sub detect_bin_default_paths()
18447{
18448 my $EnvPaths = $ENV{"PATH"};
18449 if($OSgroup eq "beos") {
18450 $EnvPaths.=":".$ENV{"BETOOLS"};
18451 }
18452 my $Sep = ($OSgroup eq "windows")?";":":|;";
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018453 foreach my $Path (split(/$Sep/, $EnvPaths))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018454 {
18455 $Path = path_format($Path, $OSgroup);
18456 $Path=~s/[\/\\]+\Z//g;
18457 next if(not $Path);
18458 if($SystemRoot
18459 and $Path=~/\A\Q$SystemRoot\E\//)
18460 { # do NOT use binaries from target system
18461 next;
18462 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018463 push_U(\@DefaultBinPaths, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018464 }
18465}
18466
18467sub detect_inc_default_paths()
18468{
18469 return () if(not $GCC_PATH);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018470 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018471 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018472 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018473 { # detecting GCC default include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018474 next if(index($Line, "/cc1plus ")!=-1);
18475
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018476 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18477 {
18478 my $Path = simplify_path($1);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018479 $Path=~s/[\/\\]+\.?\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018480 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018481 if(index($Path, "c++")!=-1
18482 or index($Path, "/g++/")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018483 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018484 push_U($DPaths{"Cpp"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018485 if(not defined $MAIN_CPP_DIR
18486 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18487 $MAIN_CPP_DIR = $Path;
18488 }
18489 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018490 elsif(index($Path, "gcc")!=-1) {
18491 push_U($DPaths{"Gcc"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018492 }
18493 else
18494 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018495 if($Path=~/local[\/\\]+include/)
18496 { # local paths
18497 next;
18498 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018499 if($SystemRoot
18500 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18501 { # The GCC include path for user headers is not a part of the system root
18502 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18503 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18504 next;
18505 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018506 push_U($DPaths{"Inc"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018507 }
18508 }
18509 }
18510 unlink("$TMP_DIR/empty.h");
18511 return %DPaths;
18512}
18513
18514sub detect_default_paths($)
18515{
18516 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18517 my $Search = $_[0];
18518 if($Search!~/inc/) {
18519 $HSearch = 0;
18520 }
18521 if($Search!~/lib/) {
18522 $LSearch = 0;
18523 }
18524 if($Search!~/bin/) {
18525 $BSearch = 0;
18526 }
18527 if($Search!~/gcc/) {
18528 $GSearch = 0;
18529 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018530 if(@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018531 { # <search_headers> section of the XML descriptor
18532 # do NOT search for systems headers
18533 $HSearch = 0;
18534 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018535 if(@{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018536 { # <search_headers> section of the XML descriptor
18537 # do NOT search for systems headers
18538 $LSearch = 0;
18539 }
18540 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18541 { # additional search paths
18542 next if($Type eq "include" and not $HSearch);
18543 next if($Type eq "lib" and not $LSearch);
18544 next if($Type eq "bin" and not $BSearch);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018545 push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018546 }
18547 if($OSgroup ne "windows")
18548 { # unix-like
18549 foreach my $Type ("include", "lib", "bin")
18550 { # automatic detection of system "devel" directories
18551 next if($Type eq "include" and not $HSearch);
18552 next if($Type eq "lib" and not $LSearch);
18553 next if($Type eq "bin" and not $BSearch);
18554 my ($UsrDir, $RootDir) = ("/usr", "/");
18555 if($SystemRoot and $Type ne "bin")
18556 { # 1. search for target headers and libraries
18557 # 2. use host commands: ldconfig, readelf, etc.
18558 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18559 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018560 push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018561 if(-d $RootDir."/".$Type)
18562 { # if "/lib" is symbolic link
18563 if($RootDir eq "/") {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018564 push_U($SystemPaths{$Type}, "/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018565 }
18566 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018567 push_U($SystemPaths{$Type}, $RootDir."/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018568 }
18569 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018570 if(-d $UsrDir)
18571 {
18572 push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018573 if(-d $UsrDir."/".$Type)
18574 { # if "/usr/lib" is symbolic link
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018575 push_U($SystemPaths{$Type}, $UsrDir."/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018576 }
18577 }
18578 }
18579 }
18580 if($BSearch)
18581 {
18582 detect_bin_default_paths();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018583 push_U($SystemPaths{"bin"}, @DefaultBinPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018584 }
18585 # check environment variables
18586 if($OSgroup eq "beos")
18587 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018588 if(my @Paths = @{$SystemPaths{"bin"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018589 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018590 foreach (@Paths)
18591 {
18592 if($_ eq ".") {
18593 next;
18594 }
18595 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18596 if(my @Dirs = sort cmd_find($_, "d", "bin")) {
18597 push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs);
18598 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018599 }
18600 }
18601 if($HSearch)
18602 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018603 push_U(\@DefaultIncPaths, grep { is_abs($_) } (
18604 split(/:|;/, $ENV{"BEINCLUDES"})
18605 ));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018606 }
18607 if($LSearch)
18608 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018609 push_U(\@DefaultLibPaths, grep { is_abs($_) } (
18610 split(/:|;/, $ENV{"BELIBRARIES"}),
18611 split(/:|;/, $ENV{"LIBRARY_PATH"})
18612 ));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018613 }
18614 }
18615 if($LSearch)
18616 { # using linker to get system paths
18617 if(my $LPaths = detect_lib_default_paths())
18618 { # unix-like
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018619 my %Dirs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018620 foreach my $Name (keys(%{$LPaths}))
18621 {
18622 if($SystemRoot
18623 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18624 { # wrong ldconfig configuration
18625 # check your <sysroot>/etc/ld.so.conf
18626 next;
18627 }
18628 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018629 if(my $Dir = get_dirname($LPaths->{$Name})) {
18630 $Dirs{$Dir} = 1;
18631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018632 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018633 push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018634 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018635 push_U($SystemPaths{"lib"}, @DefaultLibPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018636 }
18637 if($BSearch)
18638 {
18639 if($CrossGcc)
18640 { # --cross-gcc=arm-linux-gcc
18641 if(-e $CrossGcc)
18642 { # absolute or relative path
18643 $GCC_PATH = get_abs_path($CrossGcc);
18644 }
18645 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18646 { # command name
18647 $GCC_PATH = $CrossGcc;
18648 }
18649 else {
18650 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18651 }
18652 if($GCC_PATH=~/\s/) {
18653 $GCC_PATH = "\"".$GCC_PATH."\"";
18654 }
18655 }
18656 }
18657 if($GSearch)
18658 { # GCC path and default include dirs
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018659 if(not $CrossGcc)
18660 { # try default gcc
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018661 $GCC_PATH = get_CmdPath("gcc");
18662 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018663 if(not $GCC_PATH)
18664 { # try to find gcc-X.Y
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018665 foreach my $Path (@{$SystemPaths{"bin"}})
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018666 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018667 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1, 1))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018668 { # select the latest version
18669 @GCCs = sort {$b cmp $a} @GCCs;
18670 if(check_gcc($GCCs[0], "3"))
18671 {
18672 $GCC_PATH = $GCCs[0];
18673 last;
18674 }
18675 }
18676 }
18677 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018678 if(not $GCC_PATH) {
18679 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18680 }
18681 if(not $CheckObjectsOnly_Opt)
18682 {
18683 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18684 {
18685 my $GccTarget = get_dumpmachine($GCC_PATH);
18686 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18687 if($GccTarget=~/symbian/)
18688 {
18689 $OStarget = "symbian";
18690 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18691 }
18692 }
18693 else {
18694 exitStatus("Error", "something is going wrong with the GCC compiler");
18695 }
18696 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018697 if($HSearch)
18698 {
18699 if(not $NoStdInc)
18700 { # do NOT search in GCC standard paths
18701 my %DPaths = detect_inc_default_paths();
18702 @DefaultCppPaths = @{$DPaths{"Cpp"}};
18703 @DefaultGccPaths = @{$DPaths{"Gcc"}};
18704 @DefaultIncPaths = @{$DPaths{"Inc"}};
18705 push_U($SystemPaths{"include"}, @DefaultIncPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018706 }
18707 }
18708 }
18709 if($HSearch)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018710 { # users include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018711 my $IncPath = "/usr/include";
18712 if($SystemRoot) {
18713 $IncPath = $SystemRoot.$IncPath;
18714 }
18715 if(-d $IncPath) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018716 push_U(\@UsersIncPath, $IncPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018717 }
18718 }
18719}
18720
18721sub getLIB_EXT($)
18722{
18723 my $Target = $_[0];
18724 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18725 return $Ext;
18726 }
18727 return $OS_LibExt{$LIB_TYPE}{"default"};
18728}
18729
18730sub getAR_EXT($)
18731{
18732 my $Target = $_[0];
18733 if(my $Ext = $OS_Archive{$Target}) {
18734 return $Ext;
18735 }
18736 return $OS_Archive{"default"};
18737}
18738
18739sub get_dumpversion($)
18740{
18741 my $Cmd = $_[0];
18742 return "" if(not $Cmd);
18743 if($Cache{"get_dumpversion"}{$Cmd}) {
18744 return $Cache{"get_dumpversion"}{$Cmd};
18745 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018746 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018747 chomp($V);
18748 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18749}
18750
18751sub get_dumpmachine($)
18752{
18753 my $Cmd = $_[0];
18754 return "" if(not $Cmd);
18755 if($Cache{"get_dumpmachine"}{$Cmd}) {
18756 return $Cache{"get_dumpmachine"}{$Cmd};
18757 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018758 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018759 chomp($Machine);
18760 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18761}
18762
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018763sub checkCmd($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018764{
18765 my $Cmd = $_[0];
18766 return "" if(not $Cmd);
18767 my @Options = (
18768 "--version",
18769 "-help"
18770 );
18771 foreach my $Opt (@Options)
18772 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018773 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018774 if($Info) {
18775 return 1;
18776 }
18777 }
18778 return 0;
18779}
18780
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018781sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018782{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018783 my ($Cmd, $ReqVer) = @_;
18784 return 0 if(not $Cmd or not $ReqVer);
18785 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18786 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018787 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018788 if(my $GccVer = get_dumpversion($Cmd))
18789 {
18790 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18791 if(cmpVersions($GccVer, $ReqVer)>=0) {
18792 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18793 }
18794 }
18795 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018796}
18797
18798sub get_depth($)
18799{
18800 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018801 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018802 }
18803 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18804}
18805
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018806sub registerGccHeaders()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018807{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018808 return if($Cache{"registerGccHeaders"}); # this function should be called once
18809
18810 foreach my $Path (@DefaultGccPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018811 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018812 my @Headers = cmd_find($Path,"f");
18813 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
18814 foreach my $HPath (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018815 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018816 my $FileName = get_filename($HPath);
18817 if(not defined $DefaultGccHeader{$FileName})
18818 { # skip duplicated
18819 $DefaultGccHeader{$FileName} = $HPath;
18820 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018821 }
18822 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018823 $Cache{"registerGccHeaders"} = 1;
18824}
18825
18826sub registerCppHeaders()
18827{
18828 return if($Cache{"registerCppHeaders"}); # this function should be called once
18829
18830 foreach my $CppDir (@DefaultCppPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018831 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018832 my @Headers = cmd_find($CppDir,"f");
18833 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
18834 foreach my $Path (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018835 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018836 my $FileName = get_filename($Path);
18837 if(not defined $DefaultCppHeader{$FileName})
18838 { # skip duplicated
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018839 $DefaultCppHeader{$FileName} = $Path;
18840 }
18841 }
18842 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018843 $Cache{"registerCppHeaders"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018844}
18845
18846sub parse_libname($$$)
18847{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018848 return "" if(not $_[0]);
18849 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18850 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018851 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018852 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18853}
18854
18855sub parse_libname_I($$$)
18856{
18857 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018858 if($Target eq "symbian") {
18859 return parse_libname_symbian($Name, $Type);
18860 }
18861 elsif($Target eq "windows") {
18862 return parse_libname_windows($Name, $Type);
18863 }
18864 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018865 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018866 { # libSDL-1.2.so.0.7.1
18867 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018868 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018869 if($Type eq "name")
18870 { # libSDL-1.2
18871 # libwbxml2
18872 return $2;
18873 }
18874 elsif($Type eq "name+ext")
18875 { # libSDL-1.2.so
18876 # libwbxml2.so
18877 return $1;
18878 }
18879 elsif($Type eq "version")
18880 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018881 if(defined $7
18882 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018883 { # 0.7.1
18884 return $7;
18885 }
18886 else
18887 { # libc-2.5.so (=>2.5 version)
18888 my $MV = $5;
18889 $MV=~s/\A[\-\_]+//g;
18890 return $MV;
18891 }
18892 }
18893 elsif($Type eq "short")
18894 { # libSDL
18895 # libwbxml2
18896 return $3;
18897 }
18898 elsif($Type eq "shortest")
18899 { # SDL
18900 # wbxml
18901 return shortest_name($3);
18902 }
18903 }
18904 return "";# error
18905}
18906
18907sub parse_libname_symbian($$)
18908{
18909 my ($Name, $Type) = @_;
18910 my $Ext = getLIB_EXT("symbian");
18911 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18912 { # libpthread{00010001}.dso
18913 if($Type eq "name")
18914 { # libpthread{00010001}
18915 return $2;
18916 }
18917 elsif($Type eq "name+ext")
18918 { # libpthread{00010001}.dso
18919 return $1;
18920 }
18921 elsif($Type eq "version")
18922 { # 00010001
18923 my $V = $4;
18924 $V=~s/\{(.+)\}/$1/;
18925 return $V;
18926 }
18927 elsif($Type eq "short")
18928 { # libpthread
18929 return $3;
18930 }
18931 elsif($Type eq "shortest")
18932 { # pthread
18933 return shortest_name($3);
18934 }
18935 }
18936 return "";# error
18937}
18938
18939sub parse_libname_windows($$)
18940{
18941 my ($Name, $Type) = @_;
18942 my $Ext = getLIB_EXT("windows");
18943 if($Name=~/((.+?)\.$Ext)\Z/)
18944 { # netapi32.dll
18945 if($Type eq "name")
18946 { # netapi32
18947 return $2;
18948 }
18949 elsif($Type eq "name+ext")
18950 { # netapi32.dll
18951 return $1;
18952 }
18953 elsif($Type eq "version")
18954 { # DLL version embedded
18955 # at binary-level
18956 return "";
18957 }
18958 elsif($Type eq "short")
18959 { # netapi32
18960 return $2;
18961 }
18962 elsif($Type eq "shortest")
18963 { # netapi
18964 return shortest_name($2);
18965 }
18966 }
18967 return "";# error
18968}
18969
18970sub shortest_name($)
18971{
18972 my $Name = $_[0];
18973 # remove prefix
18974 $Name=~s/\A(lib|open)//;
18975 # remove suffix
18976 $Name=~s/[\W\d_]+\Z//i;
18977 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18978 return $Name;
18979}
18980
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018981sub createSymbolsList($$$$$)
18982{
18983 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18984 read_ABI_Dump(1, $DPath);
18985 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018986 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018987 }
18988 my %SymbolHeaderLib = ();
18989 my $Total = 0;
18990 # Get List
18991 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18992 {
18993 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018994 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018995 next;
18996 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018997 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018998 { # skip other symbols
18999 next;
19000 }
19001 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
19002 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019003 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019004 next;
19005 }
19006 my $DyLib = $Symbol_Library{1}{$Symbol};
19007 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019008 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019009 next;
19010 }
19011 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
19012 $Total+=1;
19013 }
19014 # Draw List
19015 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
19016 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
19017 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
19018 {
19019 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
19020 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019021 my %NS_Symbol = ();
19022 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
19023 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
19024 }
19025 foreach my $NameSpace (sort keys(%NS_Symbol))
19026 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019027 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019028 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
19029 foreach my $Symbol (@SortedInterfaces)
19030 {
19031 my $SubReport = "";
19032 my $Signature = get_Signature($Symbol, 1);
19033 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019034 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019035 }
19036 if($Symbol=~/\A(_Z|\?)/)
19037 {
19038 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019039 $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019040 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019041 else {
19042 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
19043 }
19044 }
19045 else
19046 {
19047 if($Signature) {
19048 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
19049 }
19050 else {
19051 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
19052 }
19053 }
19054 $SYMBOLS_LIST .= $SubReport;
19055 }
19056 }
19057 $SYMBOLS_LIST .= "<br/>\n";
19058 }
19059 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019060 # clear info
19061 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
19062 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
19063 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
19064 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019065 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019066 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019067 my $CssStyles = readModule("Styles", "SymbolsList.css");
19068 my $JScripts = readModule("Scripts", "Sections.js");
19069 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019070 my $Title = "$LName: public symbols";
19071 my $Keywords = "$LName, API, symbols";
19072 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019073 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019074 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019075 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019076 <div style='height:999px;'></div></body></html>";
19077 writeFile($SaveTo, $SYMBOLS_LIST);
19078}
19079
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019080sub add_target_libs($)
19081{
19082 foreach (@{$_[0]}) {
19083 $TargetLibs{$_} = 1;
19084 }
19085}
19086
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019087sub is_target_lib($)
19088{
19089 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040019090 if(not $LName) {
19091 return 0;
19092 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019093 if($TargetLibraryName
19094 and $LName!~/\Q$TargetLibraryName\E/) {
19095 return 0;
19096 }
19097 if(keys(%TargetLibs)
19098 and not $TargetLibs{$LName}
19099 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
19100 return 0;
19101 }
19102 return 1;
19103}
19104
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019105sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019106{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019107 my ($H, $V) = @_;
19108 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019109 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019110 if($TargetHeaders{$V}{$H}) {
19111 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019112 }
19113 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019114 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019115}
19116
19117sub checkVersionNum($$)
19118{
19119 my ($LibVersion, $Path) = @_;
19120 if(my $VerNum = $TargetVersion{$LibVersion}) {
19121 return $VerNum;
19122 }
19123 my $UsedAltDescr = 0;
19124 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019125 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019126 next if(isDump($Part)); # ABI dump
19127 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019128 my $VerNum = "";
19129 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019130 {
19131 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019132 $VerNum = parse_libname($Part, "version", $OStarget);
19133 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019134 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019135 }
19136 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019137 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
19138 {
19139 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019140 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019141 }
19142 if($VerNum ne "")
19143 {
19144 $TargetVersion{$LibVersion} = $VerNum;
19145 if($DumpAPI) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019146 printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019147 }
19148 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019149 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019150 }
19151 return $TargetVersion{$LibVersion};
19152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019153 }
19154 if($UsedAltDescr)
19155 {
19156 if($DumpAPI) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019157 exitStatus("Error", "version number is not set (use -vnum option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019158 }
19159 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019160 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019161 }
19162 }
19163}
19164
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019165sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019166{
19167 my $Str = $_[0];
19168 return "" if(not $Str);
19169 $Str=~s/\Q$TargetLibraryName\E//g;
19170 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019171 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019172 return $2;
19173 }
19174 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
19175 return $V;
19176 }
19177 return "";
19178}
19179
19180sub readLibs($)
19181{
19182 my $LibVersion = $_[0];
19183 if($OStarget eq "windows")
19184 { # dumpbin.exe will crash
19185 # without VS Environment
19186 check_win32_env();
19187 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019188 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019189 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019190 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019191}
19192
19193sub dump_sorting($)
19194{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019195 my $Hash = $_[0];
19196 return [] if(not $Hash);
19197 my @Keys = keys(%{$Hash});
19198 return [] if($#Keys<0);
19199 if($Keys[0]=~/\A\d+\Z/)
19200 { # numbers
19201 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019202 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019203 else
19204 { # strings
19205 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019206 }
19207}
19208
19209sub printMsg($$)
19210{
19211 my ($Type, $Msg) = @_;
19212 if($Type!~/\AINFO/) {
19213 $Msg = $Type.": ".$Msg;
19214 }
19215 if($Type!~/_C\Z/) {
19216 $Msg .= "\n";
19217 }
19218 if($Quiet)
19219 { # --quiet option
19220 appendFile($COMMON_LOG_PATH, $Msg);
19221 }
19222 else
19223 {
19224 if($Type eq "ERROR") {
19225 print STDERR $Msg;
19226 }
19227 else {
19228 print $Msg;
19229 }
19230 }
19231}
19232
19233sub exitStatus($$)
19234{
19235 my ($Code, $Msg) = @_;
19236 printMsg("ERROR", $Msg);
19237 exit($ERROR_CODE{$Code});
19238}
19239
19240sub exitReport()
19241{ # the tool has run without any errors
19242 printReport();
19243 if($COMPILE_ERRORS)
19244 { # errors in headers may add false positives/negatives
19245 exit($ERROR_CODE{"Compile_Error"});
19246 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019247 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
19248 { # --binary
19249 exit($ERROR_CODE{"Incompatible"});
19250 }
19251 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
19252 { # --source
19253 exit($ERROR_CODE{"Incompatible"});
19254 }
19255 elsif($RESULT{"Source"}{"Problems"}
19256 or $RESULT{"Binary"}{"Problems"})
19257 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019258 exit($ERROR_CODE{"Incompatible"});
19259 }
19260 else {
19261 exit($ERROR_CODE{"Compatible"});
19262 }
19263}
19264
19265sub readRules($)
19266{
19267 my $Kind = $_[0];
19268 if(not -f $RULES_PATH{$Kind}) {
19269 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
19270 }
19271 my $Content = readFile($RULES_PATH{$Kind});
19272 while(my $Rule = parseTag(\$Content, "rule"))
19273 {
19274 my $RId = parseTag(\$Rule, "id");
19275 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
19276 foreach my $Prop (@Properties) {
19277 if(my $Value = parseTag(\$Rule, lc($Prop)))
19278 {
19279 $Value=~s/\n[ ]*//;
19280 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
19281 }
19282 }
19283 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
19284 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
19285 }
19286 else {
19287 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
19288 }
19289 }
19290}
19291
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019292sub getReportPath($)
19293{
19294 my $Level = $_[0];
19295 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
19296 if($Level eq "Binary")
19297 {
19298 if($BinaryReportPath)
19299 { # --bin-report-path
19300 return $BinaryReportPath;
19301 }
19302 elsif($OutputReportPath)
19303 { # --report-path
19304 return $OutputReportPath;
19305 }
19306 else
19307 { # default
19308 return $Dir."/abi_compat_report.$ReportFormat";
19309 }
19310 }
19311 elsif($Level eq "Source")
19312 {
19313 if($SourceReportPath)
19314 { # --src-report-path
19315 return $SourceReportPath;
19316 }
19317 elsif($OutputReportPath)
19318 { # --report-path
19319 return $OutputReportPath;
19320 }
19321 else
19322 { # default
19323 return $Dir."/src_compat_report.$ReportFormat";
19324 }
19325 }
19326 else
19327 {
19328 if($OutputReportPath)
19329 { # --report-path
19330 return $OutputReportPath;
19331 }
19332 else
19333 { # default
19334 return $Dir."/compat_report.$ReportFormat";
19335 }
19336 }
19337}
19338
19339sub printStatMsg($)
19340{
19341 my $Level = $_[0];
19342 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
19343}
19344
19345sub listAffected($)
19346{
19347 my $Level = $_[0];
19348 my $List = "";
19349 foreach (keys(%{$TotalAffected{$Level}}))
19350 {
19351 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
19352 { # skip "Low"-severity problems
19353 next;
19354 }
19355 $List .= "$_\n";
19356 }
19357 my $Dir = get_dirname(getReportPath($Level));
19358 if($Level eq "Binary") {
19359 writeFile($Dir."/abi_affected.txt", $List);
19360 }
19361 elsif($Level eq "Source") {
19362 writeFile($Dir."/src_affected.txt", $List);
19363 }
19364}
19365
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019366sub printReport()
19367{
19368 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019369 createReport();
19370 if($JoinReport or $DoubleReport)
19371 {
19372 if($RESULT{"Binary"}{"Problems"}
19373 or $RESULT{"Source"}{"Problems"}) {
19374 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019375 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019376 else {
19377 printMsg("INFO", "result: COMPATIBLE");
19378 }
19379 printStatMsg("Binary");
19380 printStatMsg("Source");
19381 if($ListAffected)
19382 { # --list-affected
19383 listAffected("Binary");
19384 listAffected("Source");
19385 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019386 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019387 elsif($BinaryOnly)
19388 {
19389 if($RESULT{"Binary"}{"Problems"}) {
19390 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19391 }
19392 else {
19393 printMsg("INFO", "result: COMPATIBLE");
19394 }
19395 printStatMsg("Binary");
19396 if($ListAffected)
19397 { # --list-affected
19398 listAffected("Binary");
19399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019400 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019401 elsif($SourceOnly)
19402 {
19403 if($RESULT{"Source"}{"Problems"}) {
19404 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19405 }
19406 else {
19407 printMsg("INFO", "result: COMPATIBLE");
19408 }
19409 printStatMsg("Source");
19410 if($ListAffected)
19411 { # --list-affected
19412 listAffected("Source");
19413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019414 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019415 if($StdOut)
19416 {
19417 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019418 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019419 printMsg("INFO", "compatibility report has been generated to stdout");
19420 }
19421 else
19422 { # default
19423 printMsg("INFO", "compatibility reports have been generated to stdout");
19424 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019425 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019426 else
19427 {
19428 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019429 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019430 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19431 }
19432 elsif($DoubleReport)
19433 { # default
19434 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19435 }
19436 elsif($BinaryOnly)
19437 { # --binary
19438 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19439 }
19440 elsif($SourceOnly)
19441 { # --source
19442 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19443 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019444 }
19445}
19446
19447sub check_win32_env()
19448{
19449 if(not $ENV{"DevEnvDir"}
19450 or not $ENV{"LIB"}) {
19451 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19452 }
19453}
19454
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019455sub diffSets($$)
19456{
19457 my ($S1, $S2) = @_;
19458 my @SK1 = keys(%{$S1});
19459 my @SK2 = keys(%{$S2});
19460 if($#SK1!=$#SK2) {
19461 return 1;
19462 }
19463 foreach my $K1 (@SK1)
19464 {
19465 if(not defined $S2->{$K1}) {
19466 return 1;
19467 }
19468 }
19469 return 0;
19470}
19471
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019472sub create_ABI_Dump()
19473{
19474 if(not -e $DumpAPI) {
19475 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19476 }
19477 # check the archive utilities
19478 if($OSgroup eq "windows")
19479 { # using zip
19480 my $ZipCmd = get_CmdPath("zip");
19481 if(not $ZipCmd) {
19482 exitStatus("Not_Found", "can't find \"zip\"");
19483 }
19484 }
19485 else
19486 { # using tar and gzip
19487 my $TarCmd = get_CmdPath("tar");
19488 if(not $TarCmd) {
19489 exitStatus("Not_Found", "can't find \"tar\"");
19490 }
19491 my $GzipCmd = get_CmdPath("gzip");
19492 if(not $GzipCmd) {
19493 exitStatus("Not_Found", "can't find \"gzip\"");
19494 }
19495 }
19496 my @DParts = split(/\s*,\s*/, $DumpAPI);
19497 foreach my $Part (@DParts)
19498 {
19499 if(not -e $Part) {
19500 exitStatus("Access_Error", "can't access \'$Part\'");
19501 }
19502 }
19503 checkVersionNum(1, $DumpAPI);
19504 foreach my $Part (@DParts)
19505 {
19506 if(isDump($Part)) {
19507 read_ABI_Dump(1, $Part);
19508 }
19509 else {
19510 readDescriptor(1, createDescriptor(1, $Part));
19511 }
19512 }
19513 initLogging(1);
19514 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019515 if(not $Descriptor{1}{"Dump"})
19516 {
19517 if(not $CheckHeadersOnly) {
19518 readLibs(1);
19519 }
19520 if($CheckHeadersOnly) {
19521 setLanguage(1, "C++");
19522 }
19523 if(not $CheckObjectsOnly) {
19524 searchForHeaders(1);
19525 }
19526 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019527 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019528 if(not $Descriptor{1}{"Dump"})
19529 {
19530 if($Descriptor{1}{"Headers"}) {
19531 readHeaders(1);
19532 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019533 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019534 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019535 if(not keys(%{$SymbolInfo{1}}))
19536 { # check if created dump is valid
19537 if(not $ExtendedCheck and not $CheckObjectsOnly)
19538 {
19539 if($CheckHeadersOnly) {
19540 exitStatus("Empty_Set", "the set of public symbols is empty");
19541 }
19542 else {
19543 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19544 }
19545 }
19546 }
19547 my %HeadersInfo = ();
19548 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19549 { # headers info stored without paths in the dump
19550 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19551 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019552 if($ExtraDump)
19553 { # add unmangled names to the ABI dump
19554 my @Names = ();
19555 foreach my $InfoId (keys(%{$SymbolInfo{1}}))
19556 {
19557 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) {
19558 push(@Names, $MnglName);
19559 }
19560 }
19561 translateSymbols(@Names, 1);
19562 foreach my $InfoId (keys(%{$SymbolInfo{1}}))
19563 {
19564 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"})
19565 {
19566 if(my $Unmangled = $tr_name{$MnglName})
19567 {
19568 if($MnglName ne $Unmangled) {
19569 $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled;
19570 }
19571 }
19572 }
19573 }
19574 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019575 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019576 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019577 "TypeInfo" => $TypeInfo{1},
19578 "SymbolInfo" => $SymbolInfo{1},
19579 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019580 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019581 "SymbolVersion" => $SymVer{1},
19582 "LibraryVersion" => $Descriptor{1}{"Version"},
19583 "LibraryName" => $TargetLibraryName,
19584 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019585 "SkipTypes" => $SkipTypes{1},
19586 "SkipSymbols" => $SkipSymbols{1},
19587 "SkipNameSpaces" => $SkipNameSpaces{1},
19588 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019589 "Headers" => \%HeadersInfo,
19590 "Constants" => $Constants{1},
19591 "NameSpaces" => $NestedNameSpaces{1},
19592 "Target" => $OStarget,
19593 "Arch" => getArch(1),
19594 "WordSize" => $WORD_SIZE{1},
19595 "GccVersion" => get_dumpversion($GCC_PATH),
19596 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19597 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19598 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019599 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019600 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019601 }
19602 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019603 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019604 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019605 if($ExtendedCheck)
19606 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019607 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019609 if($BinaryOnly)
19610 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019611 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019612 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019613
19614 my $ABI_DUMP = "";
19615 if($UseXML)
19616 {
19617 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019618 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019619 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019620 else
19621 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019622 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019623 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019624 if($StdOut)
19625 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019626 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019627 printMsg("INFO", "ABI dump has been generated to stdout");
19628 return;
19629 }
19630 else
19631 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019632 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19633 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019634 if($OutputDumpPath)
19635 { # user defined path
19636 $DumpPath = $OutputDumpPath;
19637 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019638 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019639 my ($DDir, $DName) = separate_path($DumpPath);
19640 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019641 if(not $Archive) {
19642 $DPath = $DumpPath;
19643 }
19644
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019645 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019646
19647 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019648 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019649 close(DUMP);
19650
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019651 if(not -s $DPath) {
19652 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19653 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019654 if($Archive) {
19655 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019656 }
19657
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019658 if(not $OutputDumpPath)
19659 {
19660 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19661 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19662 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019663 }
19664}
19665
19666sub quickEmptyReports()
19667{ # Quick "empty" reports
19668 # 4 times faster than merging equal dumps
19669 # NOTE: the dump contains the "LibraryVersion" attribute
19670 # if you change the version, then your dump will be different
19671 # OVERCOME: use -v1 and v2 options for comparing dumps
19672 # and don't change version in the XML descriptor (and dumps)
19673 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19674 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19675 {
19676 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19677 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19678 if($FilePath1 and $FilePath2)
19679 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019680 my $Line = readLineNum($FilePath1, 0);
19681 if($Line=~/xml/)
19682 { # XML format
19683 # is not supported yet
19684 return;
19685 }
19686
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019687 local $/ = undef;
19688
19689 open(DUMP1, $FilePath1);
19690 my $Content1 = <DUMP1>;
19691 close(DUMP1);
19692
19693 open(DUMP2, $FilePath2);
19694 my $Content2 = <DUMP2>;
19695 close(DUMP2);
19696
19697 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019698 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019699 # clean memory
19700 undef $Content2;
19701
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019702 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019703 my $ABIdump = eval($Content1);
19704
19705 # clean memory
19706 undef $Content1;
19707
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019708 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019709 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019710 }
19711 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019712 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019713 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19714 }
19715 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019716 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019717 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19718 }
19719 read_Headers_DumpInfo($ABIdump, 1);
19720 read_Libs_DumpInfo($ABIdump, 1);
19721 read_Machine_DumpInfo($ABIdump, 1);
19722 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019723
19724 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19725 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19726
19727 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19728 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19729
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019730 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19731 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19732 exitReport();
19733 }
19734 }
19735 }
19736}
19737
19738sub initLogging($)
19739{
19740 my $LibVersion = $_[0];
19741 # create log directory
19742 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19743 if($OutputLogPath{$LibVersion})
19744 { # user-defined by -log-path option
19745 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19746 }
19747 if($LogMode ne "n") {
19748 mkpath($LOG_DIR);
19749 }
19750 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019751 if($Debug)
19752 { # debug directory
19753 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019754 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019755 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019756}
19757
19758sub writeLog($$)
19759{
19760 my ($LibVersion, $Msg) = @_;
19761 if($LogMode ne "n") {
19762 appendFile($LOG_PATH{$LibVersion}, $Msg);
19763 }
19764}
19765
19766sub resetLogging($)
19767{
19768 my $LibVersion = $_[0];
19769 if($LogMode!~/a|n/)
19770 { # remove old log
19771 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019772 if($Debug) {
19773 rmtree($DEBUG_PATH{$LibVersion});
19774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019775 }
19776}
19777
19778sub printErrorLog($)
19779{
19780 my $LibVersion = $_[0];
19781 if($LogMode ne "n") {
19782 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19783 }
19784}
19785
19786sub isDump($)
19787{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019788 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19789 return $1;
19790 }
19791 return 0;
19792}
19793
19794sub isDump_U($)
19795{
19796 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019797 return $1;
19798 }
19799 return 0;
19800}
19801
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019802sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019803{
19804 # read input XML descriptors or ABI dumps
19805 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019806 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019807 }
19808 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19809 foreach my $Part (@DParts1)
19810 {
19811 if(not -e $Part) {
19812 exitStatus("Access_Error", "can't access \'$Part\'");
19813 }
19814 }
19815 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019816 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019817 }
19818 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19819 foreach my $Part (@DParts2)
19820 {
19821 if(not -e $Part) {
19822 exitStatus("Access_Error", "can't access \'$Part\'");
19823 }
19824 }
19825 detect_default_paths("bin"); # to extract dumps
19826 if($#DParts1==0 and $#DParts2==0
19827 and isDump($Descriptor{1}{"Path"})
19828 and isDump($Descriptor{2}{"Path"}))
19829 { # optimization: equal ABI dumps
19830 quickEmptyReports();
19831 }
19832 checkVersionNum(1, $Descriptor{1}{"Path"});
19833 checkVersionNum(2, $Descriptor{2}{"Path"});
19834 printMsg("INFO", "preparation, please wait ...");
19835 foreach my $Part (@DParts1)
19836 {
19837 if(isDump($Part)) {
19838 read_ABI_Dump(1, $Part);
19839 }
19840 else {
19841 readDescriptor(1, createDescriptor(1, $Part));
19842 }
19843 }
19844 foreach my $Part (@DParts2)
19845 {
19846 if(isDump($Part)) {
19847 read_ABI_Dump(2, $Part);
19848 }
19849 else {
19850 readDescriptor(2, createDescriptor(2, $Part));
19851 }
19852 }
19853 initLogging(1);
19854 initLogging(2);
19855 # check consistency
19856 if(not $Descriptor{1}{"Headers"}
19857 and not $Descriptor{1}{"Libs"}) {
19858 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19859 }
19860 if(not $Descriptor{2}{"Headers"}
19861 and not $Descriptor{2}{"Libs"}) {
19862 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19863 }
19864 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19865 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19866 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19867 }
19868 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19869 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19870 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19871 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019872 if(not $Descriptor{1}{"Headers"})
19873 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019874 if($CheckHeadersOnly_Opt) {
19875 exitStatus("Error", "can't find header files info in descriptor d1");
19876 }
19877 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019878 if(not $Descriptor{2}{"Headers"})
19879 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019880 if($CheckHeadersOnly_Opt) {
19881 exitStatus("Error", "can't find header files info in descriptor d2");
19882 }
19883 }
19884 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019885 or not $Descriptor{2}{"Headers"})
19886 {
19887 if(not $CheckObjectsOnly_Opt)
19888 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019889 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19890 $CheckObjectsOnly = 1;
19891 }
19892 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019893 if(not $Descriptor{1}{"Libs"})
19894 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019895 if($CheckObjectsOnly_Opt) {
19896 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19897 }
19898 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019899 if(not $Descriptor{2}{"Libs"})
19900 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019901 if($CheckObjectsOnly_Opt) {
19902 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19903 }
19904 }
19905 if(not $Descriptor{1}{"Libs"}
19906 or not $Descriptor{2}{"Libs"})
19907 { # comparing standalone header files
19908 # comparing ABI dumps created with --headers-only
19909 if(not $CheckHeadersOnly_Opt)
19910 {
19911 printMsg("WARNING", "checking headers only");
19912 $CheckHeadersOnly = 1;
19913 }
19914 }
19915 if($UseDumps)
19916 { # --use-dumps
19917 # parallel processing
19918 my $pid = fork();
19919 if($pid)
19920 { # dump on two CPU cores
19921 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19922 if($RelativeDirectory{1}) {
19923 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19924 }
19925 if($OutputLogPath{1}) {
19926 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19927 }
19928 if($CrossGcc) {
19929 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19930 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019931 if($Quiet)
19932 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019933 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019934 @PARAMS = (@PARAMS, "-logging-mode", "a");
19935 }
19936 elsif($LogMode and $LogMode ne "w")
19937 { # "w" is default
19938 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019939 }
19940 if($ExtendedCheck) {
19941 @PARAMS = (@PARAMS, "-extended");
19942 }
19943 if($UserLang) {
19944 @PARAMS = (@PARAMS, "-lang", $UserLang);
19945 }
19946 if($TargetVersion{1}) {
19947 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19948 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019949 if($BinaryOnly) {
19950 @PARAMS = (@PARAMS, "-binary");
19951 }
19952 if($SourceOnly) {
19953 @PARAMS = (@PARAMS, "-source");
19954 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019955 if($SortDump) {
19956 @PARAMS = (@PARAMS, "-sort");
19957 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019958 if($DumpFormat and $DumpFormat ne "perl") {
19959 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19960 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019961 if($CheckHeadersOnly) {
19962 @PARAMS = (@PARAMS, "-headers-only");
19963 }
19964 if($CheckObjectsOnly) {
19965 @PARAMS = (@PARAMS, "-objects-only");
19966 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019967 if($Debug)
19968 {
19969 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019970 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019971 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019972 system("perl", $0, @PARAMS);
19973 if($?) {
19974 exit(1);
19975 }
19976 }
19977 else
19978 { # child
19979 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19980 if($RelativeDirectory{2}) {
19981 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19982 }
19983 if($OutputLogPath{2}) {
19984 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19985 }
19986 if($CrossGcc) {
19987 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19988 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019989 if($Quiet)
19990 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019991 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019992 @PARAMS = (@PARAMS, "-logging-mode", "a");
19993 }
19994 elsif($LogMode and $LogMode ne "w")
19995 { # "w" is default
19996 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019997 }
19998 if($ExtendedCheck) {
19999 @PARAMS = (@PARAMS, "-extended");
20000 }
20001 if($UserLang) {
20002 @PARAMS = (@PARAMS, "-lang", $UserLang);
20003 }
20004 if($TargetVersion{2}) {
20005 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
20006 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020007 if($BinaryOnly) {
20008 @PARAMS = (@PARAMS, "-binary");
20009 }
20010 if($SourceOnly) {
20011 @PARAMS = (@PARAMS, "-source");
20012 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020013 if($SortDump) {
20014 @PARAMS = (@PARAMS, "-sort");
20015 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020016 if($DumpFormat and $DumpFormat ne "perl") {
20017 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
20018 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020019 if($CheckHeadersOnly) {
20020 @PARAMS = (@PARAMS, "-headers-only");
20021 }
20022 if($CheckObjectsOnly) {
20023 @PARAMS = (@PARAMS, "-objects-only");
20024 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020025 if($Debug)
20026 {
20027 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020028 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020030 system("perl", $0, @PARAMS);
20031 if($?) {
20032 exit(1);
20033 }
20034 else {
20035 exit(0);
20036 }
20037 }
20038 waitpid($pid, 0);
20039 my @CMP_PARAMS = ("-l", $TargetLibraryName);
20040 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
20041 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
20042 if($TargetLibraryFName ne $TargetLibraryName) {
20043 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
20044 }
20045 if($ShowRetVal) {
20046 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
20047 }
20048 if($CrossGcc) {
20049 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
20050 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040020051 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
20052 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020053 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020054 }
20055 if($ReportFormat and $ReportFormat ne "html")
20056 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020057 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
20058 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020059 if($OutputReportPath) {
20060 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
20061 }
20062 if($BinaryReportPath) {
20063 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
20064 }
20065 if($SourceReportPath) {
20066 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
20067 }
20068 if($LoggingPath) {
20069 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
20070 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020071 if($CheckHeadersOnly) {
20072 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
20073 }
20074 if($CheckObjectsOnly) {
20075 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
20076 }
20077 if($BinaryOnly) {
20078 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
20079 }
20080 if($SourceOnly) {
20081 @CMP_PARAMS = (@CMP_PARAMS, "-source");
20082 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020083 if($Browse) {
20084 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
20085 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020086 if($OpenReport) {
20087 @CMP_PARAMS = (@CMP_PARAMS, "-open");
20088 }
20089 if($Debug)
20090 {
20091 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
20092 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020093 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020094 system("perl", $0, @CMP_PARAMS);
20095 exit($?>>8);
20096 }
20097 if(not $Descriptor{1}{"Dump"}
20098 or not $Descriptor{2}{"Dump"})
20099 { # need GCC toolchain to analyze
20100 # header files and libraries
20101 detect_default_paths("inc|lib|gcc");
20102 }
20103 if(not $Descriptor{1}{"Dump"})
20104 {
20105 if(not $CheckHeadersOnly) {
20106 readLibs(1);
20107 }
20108 if($CheckHeadersOnly) {
20109 setLanguage(1, "C++");
20110 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020111 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020112 searchForHeaders(1);
20113 }
20114 $WORD_SIZE{1} = detectWordSize();
20115 }
20116 if(not $Descriptor{2}{"Dump"})
20117 {
20118 if(not $CheckHeadersOnly) {
20119 readLibs(2);
20120 }
20121 if($CheckHeadersOnly) {
20122 setLanguage(2, "C++");
20123 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020124 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020125 searchForHeaders(2);
20126 }
20127 $WORD_SIZE{2} = detectWordSize();
20128 }
20129 if($WORD_SIZE{1} ne $WORD_SIZE{2})
20130 { # support for old ABI dumps
20131 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020132 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020133 {
20134 $WORD_SIZE{1} = $WORD_SIZE{2};
20135 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
20136 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020137 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020138 {
20139 $WORD_SIZE{2} = $WORD_SIZE{1};
20140 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
20141 }
20142 }
20143 elsif(not $WORD_SIZE{1}
20144 and not $WORD_SIZE{2})
20145 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020146 $WORD_SIZE{1} = "4";
20147 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020148 }
20149 if($Descriptor{1}{"Dump"})
20150 { # support for old ABI dumps
20151 prepareTypes(1);
20152 }
20153 if($Descriptor{2}{"Dump"})
20154 { # support for old ABI dumps
20155 prepareTypes(2);
20156 }
20157 if($AppPath and not keys(%{$Symbol_Library{1}})) {
20158 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
20159 }
20160 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020161 if(not $CheckObjectsOnly)
20162 {
20163 if($Descriptor{1}{"Headers"}
20164 and not $Descriptor{1}{"Dump"}) {
20165 readHeaders(1);
20166 }
20167 if($Descriptor{2}{"Headers"}
20168 and not $Descriptor{2}{"Dump"}) {
20169 readHeaders(2);
20170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020171 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020172
20173 # clean memory
20174 %SystemHeaders = ();
20175 %mangled_name_gcc = ();
20176
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020177 prepareSymbols(1);
20178 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020179
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020180 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020181 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020182
20183 # Virtual Tables
20184 registerVTable(1);
20185 registerVTable(2);
20186
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020187 if(not checkDump(1, "1.22")
20188 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020189 { # support for old ABI dumps
20190 foreach my $ClassName (keys(%{$VirtualTable{2}}))
20191 {
20192 if($ClassName=~/</)
20193 { # templates
20194 if(not defined $VirtualTable{1}{$ClassName})
20195 { # synchronize
20196 delete($VirtualTable{2}{$ClassName});
20197 }
20198 }
20199 }
20200 }
20201
20202 registerOverriding(1);
20203 registerOverriding(2);
20204
20205 setVirtFuncPositions(1);
20206 setVirtFuncPositions(2);
20207
20208 # Other
20209 addParamNames(1);
20210 addParamNames(2);
20211
20212 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020213}
20214
20215sub compareAPIs($)
20216{
20217 my $Level = $_[0];
20218 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020219 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020220 if($Level eq "Binary") {
20221 printMsg("INFO", "comparing ABIs ...");
20222 }
20223 else {
20224 printMsg("INFO", "comparing APIs ...");
20225 }
20226 if($CheckHeadersOnly
20227 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020228 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020229 detectAdded_H($Level);
20230 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020231 }
20232 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020233 { # added/removed in libs
20234 detectAdded($Level);
20235 detectRemoved($Level);
20236 }
20237 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020238 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020239 mergeSignatures($Level);
20240 if(keys(%{$CheckedSymbols{$Level}})) {
20241 mergeConstants($Level);
20242 }
20243 }
20244 if($CheckHeadersOnly
20245 or $Level eq "Source")
20246 { # added/removed in headers
20247 mergeHeaders($Level);
20248 }
20249 else
20250 { # added/removed in libs
20251 mergeLibs($Level);
20252 if($CheckImpl
20253 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020254 mergeImpl();
20255 }
20256 }
20257}
20258
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020259sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020260{
20261 my %Opts = (
20262 "OStarget"=>$OStarget,
20263 "Debug"=>$Debug,
20264 "Quiet"=>$Quiet,
20265 "LogMode"=>$LogMode,
20266 "CheckHeadersOnly"=>$CheckHeadersOnly,
20267
20268 "SystemRoot"=>$SystemRoot,
20269 "MODULES_DIR"=>$MODULES_DIR,
20270 "GCC_PATH"=>$GCC_PATH,
20271 "TargetSysInfo"=>$TargetSysInfo,
20272 "CrossPrefix"=>$CrossPrefix,
20273 "TargetLibraryName"=>$TargetLibraryName,
20274 "CrossGcc"=>$CrossGcc,
20275 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020276 "NoStdInc"=>$NoStdInc,
20277
20278 "BinaryOnly" => $BinaryOnly,
20279 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020280 );
20281 return \%Opts;
20282}
20283
20284sub get_CoreError($)
20285{
20286 my %CODE_ERROR = reverse(%ERROR_CODE);
20287 return $CODE_ERROR{$_[0]};
20288}
20289
20290sub scenario()
20291{
20292 if($StdOut)
20293 { # enable quiet mode
20294 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020295 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020296 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020297 if(not $LogMode)
20298 { # default
20299 $LogMode = "w";
20300 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020301 if($UserLang)
20302 { # --lang=C++
20303 $UserLang = uc($UserLang);
20304 $COMMON_LANGUAGE{1}=$UserLang;
20305 $COMMON_LANGUAGE{2}=$UserLang;
20306 }
20307 if($LoggingPath)
20308 {
20309 $OutputLogPath{1} = $LoggingPath;
20310 $OutputLogPath{2} = $LoggingPath;
20311 if($Quiet) {
20312 $COMMON_LOG_PATH = $LoggingPath;
20313 }
20314 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020315 if($OutputDumpPath)
20316 { # validate
20317 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
20318 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
20319 }
20320 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020321 if($BinaryOnly and $SourceOnly)
20322 { # both --binary and --source
20323 # is the default mode
20324 $DoubleReport = 1;
20325 $JoinReport = 0;
20326 $BinaryOnly = 0;
20327 $SourceOnly = 0;
20328 if($OutputReportPath)
20329 { # --report-path
20330 $DoubleReport = 0;
20331 $JoinReport = 1;
20332 }
20333 }
20334 elsif($BinaryOnly or $SourceOnly)
20335 { # --binary or --source
20336 $DoubleReport = 0;
20337 $JoinReport = 0;
20338 }
20339 if($UseXML)
20340 { # --xml option
20341 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020342 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020344 if($ReportFormat)
20345 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020346 $ReportFormat = lc($ReportFormat);
20347 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020348 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020349 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020350 if($ReportFormat eq "htm")
20351 { # HTM == HTML
20352 $ReportFormat = "html";
20353 }
20354 elsif($ReportFormat eq "xml")
20355 { # --report-format=XML equal to --xml
20356 $UseXML = 1;
20357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020358 }
20359 else
20360 { # default: HTML
20361 $ReportFormat = "html";
20362 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020363 if($DumpFormat)
20364 { # validate
20365 $DumpFormat = lc($DumpFormat);
20366 if($DumpFormat!~/\A(xml|perl)\Z/) {
20367 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
20368 }
20369 if($DumpFormat eq "xml")
20370 { # --dump-format=XML equal to --xml
20371 $UseXML = 1;
20372 }
20373 }
20374 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020375 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020376 $DumpFormat = "perl";
20377 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020378 if($Quiet and $LogMode!~/a|n/)
20379 { # --quiet log
20380 if(-f $COMMON_LOG_PATH) {
20381 unlink($COMMON_LOG_PATH);
20382 }
20383 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020384 if($ExtraInfo)
20385 {
20386 $CheckUndefined = 1;
20387 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020388 if($TestTool and $UseDumps)
20389 { # --test && --use-dumps == --test-dump
20390 $TestDump = 1;
20391 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020392 if($Help)
20393 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020394 HELP_MESSAGE();
20395 exit(0);
20396 }
20397 if($InfoMsg) {
20398 INFO_MESSAGE();
20399 exit(0);
20400 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020401 if($ShowVersion)
20402 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020403 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.");
20404 exit(0);
20405 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020406 if($DumpVersion)
20407 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020408 printMsg("INFO", $TOOL_VERSION);
20409 exit(0);
20410 }
20411 if($ExtendedCheck) {
20412 $CheckHeadersOnly = 1;
20413 }
20414 if($SystemRoot_Opt)
20415 { # user defined root
20416 if(not -e $SystemRoot_Opt) {
20417 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20418 }
20419 $SystemRoot = $SystemRoot_Opt;
20420 $SystemRoot=~s/[\/]+\Z//g;
20421 if($SystemRoot) {
20422 $SystemRoot = get_abs_path($SystemRoot);
20423 }
20424 }
20425 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020426
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020427 if($SortDump)
20428 {
20429 $Data::Dumper::Useperl = 1;
20430 $Data::Dumper::Sortkeys = \&dump_sorting;
20431 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020432
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020433 if($TargetLibsPath)
20434 {
20435 if(not -f $TargetLibsPath) {
20436 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20437 }
20438 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20439 $TargetLibs{$Lib} = 1;
20440 }
20441 }
20442 if($TargetHeadersPath)
20443 { # --headers-list
20444 if(not -f $TargetHeadersPath) {
20445 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20446 }
20447 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20448 {
20449 $TargetHeaders{1}{$Header} = 1;
20450 $TargetHeaders{2}{$Header} = 1;
20451 }
20452 }
20453 if($TargetHeader)
20454 { # --header
20455 $TargetHeaders{1}{$TargetHeader} = 1;
20456 $TargetHeaders{2}{$TargetHeader} = 1;
20457 }
20458 if($TestTool
20459 or $TestDump)
20460 { # --test, --test-dump
20461 detect_default_paths("bin|gcc"); # to compile libs
20462 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020463 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20464 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020465 exit(0);
20466 }
20467 if($DumpSystem)
20468 { # --dump-system
20469 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020470 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020471 { # system XML descriptor
20472 if(not -f $DumpSystem) {
20473 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20474 }
20475 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020476 foreach (@{$Ret->{"Tools"}})
20477 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020478 push_U($SystemPaths{"bin"}, $_);
20479 $TargetTools{$_} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020480 }
20481 if($Ret->{"CrossPrefix"}) {
20482 $CrossPrefix = $Ret->{"CrossPrefix"};
20483 }
20484 }
20485 elsif($SystemRoot_Opt)
20486 { # -sysroot "/" option
20487 # default target: /usr/lib, /usr/include
20488 # search libs: /usr/lib and /lib
20489 if(not -e $SystemRoot."/usr/lib") {
20490 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20491 }
20492 if(not -e $SystemRoot."/lib") {
20493 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20494 }
20495 if(not -e $SystemRoot."/usr/include") {
20496 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20497 }
20498 readSystemDescriptor("
20499 <name>
20500 $DumpSystem
20501 </name>
20502 <headers>
20503 $SystemRoot/usr/include
20504 </headers>
20505 <libs>
20506 $SystemRoot/usr/lib
20507 </libs>
20508 <search_libs>
20509 $SystemRoot/lib
20510 </search_libs>");
20511 }
20512 else {
20513 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20514 }
20515 detect_default_paths("bin|gcc"); # to check symbols
20516 if($OStarget eq "windows")
20517 { # to run dumpbin.exe
20518 # and undname.exe
20519 check_win32_env();
20520 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020521 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020522 exit(0);
20523 }
20524 if($CmpSystems)
20525 { # --cmp-systems
20526 detect_default_paths("bin"); # to extract dumps
20527 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020528 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020529 exit(0);
20530 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020531 if($GenerateTemplate)
20532 {
20533 writeFile("VERSION.xml", $DescriptorTemplate."\n");
20534 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020535 exit(0);
20536 }
20537 if(not $TargetLibraryName) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020538 exitStatus("Error", "library name is not selected (-l option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020539 }
20540 else
20541 { # validate library name
20542 if($TargetLibraryName=~/[\*\/\\]/) {
20543 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20544 }
20545 }
20546 if(not $TargetLibraryFName) {
20547 $TargetLibraryFName = $TargetLibraryName;
20548 }
20549 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20550 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20551 }
20552 if($SymbolsListPath)
20553 {
20554 if(not -f $SymbolsListPath) {
20555 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20556 }
20557 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20558 $SymbolsList{$Interface} = 1;
20559 }
20560 }
20561 if($SkipHeadersPath)
20562 {
20563 if(not -f $SkipHeadersPath) {
20564 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20565 }
20566 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020567 { # register for both versions
20568 $SkipHeadersList{1}{$Path} = 1;
20569 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020570 my ($CPath, $Type) = classifyPath($Path);
20571 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020572 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020573 }
20574 }
20575 if($ParamNamesPath)
20576 {
20577 if(not -f $ParamNamesPath) {
20578 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20579 }
20580 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20581 {
20582 if($Line=~s/\A(\w+)\;//)
20583 {
20584 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020585 if($Line=~/;(\d+);/)
20586 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020587 while($Line=~s/(\d+);(\w+)//) {
20588 $AddIntParams{$Interface}{$1}=$2;
20589 }
20590 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020591 else
20592 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020593 my $Num = 0;
20594 foreach my $Name (split(/;/, $Line)) {
20595 $AddIntParams{$Interface}{$Num++}=$Name;
20596 }
20597 }
20598 }
20599 }
20600 }
20601 if($AppPath)
20602 {
20603 if(not -f $AppPath) {
20604 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20605 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020606 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020607 $SymbolsList_App{$Interface} = 1;
20608 }
20609 }
20610 if($DumpAPI)
20611 { # --dump-abi
20612 # make an API dump
20613 create_ABI_Dump();
20614 exit($COMPILE_ERRORS);
20615 }
20616 # default: compare APIs
20617 # -d1 <path>
20618 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020619 compareInit();
20620 if($JoinReport or $DoubleReport)
20621 {
20622 compareAPIs("Binary");
20623 compareAPIs("Source");
20624 }
20625 elsif($BinaryOnly) {
20626 compareAPIs("Binary");
20627 }
20628 elsif($SourceOnly) {
20629 compareAPIs("Source");
20630 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020631 exitReport();
20632}
20633
20634scenario();