blob: 12eb9737c4b12dbcedddb3d463beade34f121fa1 [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 Ponomarenko07aea072012-11-12 16:15:07 +040026# - Xcode (g++, c++filt, 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,
90$ExtraInfo);
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
173if($#ARGV==-1) {
174 printMsg("INFO", $ShortUsage);
175 exit(0);
176}
177
178foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400179{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400180 if($ARGV[$_-1] eq ",") {
181 $ARGV[$_-2].=",".$ARGV[$_];
182 splice(@ARGV, $_-1, 2);
183 }
184 elsif($ARGV[$_-1]=~/,\Z/) {
185 $ARGV[$_-1].=$ARGV[$_];
186 splice(@ARGV, $_, 1);
187 }
188 elsif($ARGV[$_]=~/\A,/
189 and $ARGV[$_] ne ",") {
190 $ARGV[$_-1].=$ARGV[$_];
191 splice(@ARGV, $_, 1);
192 }
193}
194
195GetOptions("h|help!" => \$Help,
196 "i|info!" => \$InfoMsg,
197 "v|version!" => \$ShowVersion,
198 "dumpversion!" => \$DumpVersion,
199# general options
200 "l|lib|library=s" => \$TargetLibraryName,
201 "d1|old|o=s" => \$Descriptor{1}{"Path"},
202 "d2|new|n=s" => \$Descriptor{2}{"Path"},
203 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
204 "old-dumps!" => \$UseOldDumps,
205# extra options
206 "d|descriptor-template!" => \$GenerateTemplate,
207 "app|application=s" => \$AppPath,
208 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400209 "cross-gcc|gcc-path=s" => \$CrossGcc,
210 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400211 "sysroot=s" => \$SystemRoot_Opt,
212 "v1|version1|vnum=s" => \$TargetVersion{1},
213 "v2|version2=s" => \$TargetVersion{2},
214 "s|strict!" => \$StrictCompat,
215 "symbols-list=s" => \$SymbolsListPath,
216 "skip-headers=s" => \$SkipHeadersPath,
217 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
218 "objects-only!" => \$CheckObjectsOnly_Opt,
219 "check-impl|check-implementation!" => \$CheckImpl,
220 "show-retval!" => \$ShowRetVal,
221 "use-dumps!" => \$UseDumps,
222 "nostdinc!" => \$NoStdInc,
223 "dump-system=s" => \$DumpSystem,
224 "sysinfo=s" => \$TargetSysInfo,
225 "cmp-systems!" => \$CmpSystems,
226 "libs-list=s" => \$TargetLibsPath,
227 "headers-list=s" => \$TargetHeadersPath,
228 "header=s" => \$TargetHeader,
229 "ext|extended!" => \$ExtendedCheck,
230 "q|quiet!" => \$Quiet,
231 "stdout!" => \$StdOut,
232 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400233 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400234 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400235 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400236 "binary|bin|abi!" => \$BinaryOnly,
237 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400238# other options
239 "test!" => \$TestTool,
240 "test-dump!" => \$TestDump,
241 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400242 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400243 "p|params=s" => \$ParamNamesPath,
244 "relpath1|relpath=s" => \$RelativeDirectory{1},
245 "relpath2=s" => \$RelativeDirectory{2},
246 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400247 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400248 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400249 "bin-report-path=s" => \$BinaryReportPath,
250 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251 "log-path=s" => \$LoggingPath,
252 "log1-path=s" => \$OutputLogPath{1},
253 "log2-path=s" => \$OutputLogPath{2},
254 "logging-mode=s" => \$LogMode,
255 "list-affected!" => \$ListAffected,
256 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400257 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400258 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400259 "open!" => \$OpenReport,
260 "extra-info=s" => \$ExtraInfo
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400261) or ERR_MESSAGE();
262
263sub ERR_MESSAGE()
264{
265 printMsg("INFO", "\n".$ShortUsage);
266 exit($ERROR_CODE{"Error"});
267}
268
269my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
270my $SLIB_TYPE = $LIB_TYPE;
271if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
272{ # show as "shared" library
273 $SLIB_TYPE = "shared";
274}
275my $LIB_EXT = getLIB_EXT($OSgroup);
276my $AR_EXT = getAR_EXT($OSgroup);
277my $BYTE_SIZE = 8;
278my $COMMON_LOG_PATH = "logs/run.log";
279
280my $HelpMessage="
281NAME:
282 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400283 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400284
285DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400286 ABI Compliance Checker (ACC) is a tool for checking backward binary and
287 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
288 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
289 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
290 and/or source-level compatibility: changes in calling stack, v-table changes,
291 removed symbols, renamed fields, etc. Binary incompatibility may result in
292 crashing or incorrect behavior of applications built with an old version of
293 a library if they run on a new one. Source incompatibility may result in
294 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400295
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400296 The tool is intended for developers of software libraries and maintainers
297 of operating systems who are interested in ensuring backward compatibility,
298 i.e. allow old applications to run or to be recompiled with newer library
299 versions.
300
301 Also the tool can be used by ISVs for checking applications portability to
302 new library versions. Found issues can be taken into account when adapting
303 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400304
305 This tool is free software: you can redistribute it and/or modify it
306 under the terms of the GNU LGPL or GNU GPL.
307
308USAGE:
309 $CmdName [options]
310
311EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400312 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400313
314 OLD.xml and NEW.xml are XML-descriptors:
315
316 <version>
317 1.0
318 </version>
319
320 <headers>
321 /path1/to/header(s)/
322 /path2/to/header(s)/
323 ...
324 </headers>
325
326 <libs>
327 /path1/to/library(ies)/
328 /path2/to/library(ies)/
329 ...
330 </libs>
331
332INFORMATION OPTIONS:
333 -h|-help
334 Print this help.
335
336 -i|-info
337 Print complete info.
338
339 -v|-version
340 Print version information.
341
342 -dumpversion
343 Print the tool version ($TOOL_VERSION) and don't do anything else.
344
345GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400346 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400347 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400348
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400349 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400350 Descriptor of 1st (old) library version.
351 It may be one of the following:
352
353 1. XML-descriptor (VERSION.xml file):
354
355 <version>
356 1.0
357 </version>
358
359 <headers>
360 /path1/to/header(s)/
361 /path2/to/header(s)/
362 ...
363 </headers>
364
365 <libs>
366 /path1/to/library(ies)/
367 /path2/to/library(ies)/
368 ...
369 </libs>
370
371 ... (XML-descriptor template
372 can be generated by -d option)
373
374 2. ABI dump generated by -dump option
375 3. Directory with headers and/or $SLIB_TYPE libraries
376 4. Single header file
377 5. Single $SLIB_TYPE library
378 6. Comma separated list of headers and/or libraries
379
380 If you are using an 2-6 descriptor types then you should
381 specify version numbers with -v1 <num> and -v2 <num> options too.
382
383 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400384 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400385
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400386 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400387 Descriptor of 2nd (new) library version.
388
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400389 -dump|-dump-abi PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400390 Dump library ABI to gzipped TXT format file. You can transfer it
391 anywhere and pass instead of the descriptor. Also it can be used
392 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
393
394 -old-dumps
395 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
396
397sub HELP_MESSAGE() {
398 printMsg("INFO", $HelpMessage."
399MORE INFO:
400 $CmdName --info\n");
401}
402
403sub INFO_MESSAGE()
404{
405 printMsg("INFO", "$HelpMessage
406EXTRA OPTIONS:
407 -d|-descriptor-template
408 Create XML-descriptor template ./VERSION.xml
409
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400410 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400411 This option allows to specify the application that should be checked
412 for portability to the new library version.
413
414 -static-libs
415 Check static libraries instead of the shared ones. The <libs> section
416 of the XML-descriptor should point to static libraries location.
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 Path to the cross GCC compiler to use instead of the usual (host) GCC.
420
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400421 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400422 GCC toolchain prefix.
423
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400424 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400425 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400428 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400429 Specify 1st library version outside the descriptor. This option is needed
430 if you have prefered an alternative descriptor type (see -d1 option).
431
432 In general case you should specify it in the XML-descriptor:
433 <version>
434 VERSION
435 </version>
436
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400437 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400438 Specify 2nd library version outside the descriptor.
439
440 -s|-strict
441 Treat all compatibility warnings as problems. Add a number of \"Low\"
442 severity problems to the return value of the tool.
443
444 -headers-only
445 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without detecting of added/removed symbols.
448
449 Alternatively you can write \"none\" word to the <libs> section
450 in the XML-descriptor:
451 <libs>
452 none
453 </libs>
454
455 -objects-only
456 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
457 provide a low quality compatibility report with false positives and
458 without analysis of changes in parameters and data types.
459
460 Alternatively you can write \"none\" word to the <headers> section
461 in the XML-descriptor:
462 <headers>
463 none
464 </headers>
465
466 -check-impl|-check-implementation
467 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
468 detect changes in the implementation. Add \'Problems with Implementation\'
469 section to the report.
470
471 -show-retval
472 Show the symbol's return type in the report.
473
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400474 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400475 This option allows to specify a file with a list of symbols (mangled
476 names in C++) that should be checked, other symbols will not be checked.
477
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400478 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400479 The file with the list of header files, that should not be checked.
480
481 -use-dumps
482 Make dumps for two versions of a library and compare dumps. This should
483 increase the performance of the tool and decrease the system memory usage.
484
485 -nostdinc
486 Do not search the GCC standard system directories for header files.
487
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400488 -dump-system NAME -sysroot DIR
489 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400490 create XML descriptors and make ABI dumps for each library. The result
491 set of ABI dumps can be compared (--cmp-systems) with the other one
492 created for other version of operating system in order to check them for
493 compatibility. Do not forget to specify -cross-gcc option if your target
494 system requires some specific version of GCC compiler (different from
495 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400497
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400498 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400499 The same as the previous option but takes an XML descriptor of the target
500 system as input, where you should describe it:
501
502 /* Primary sections */
503
504 <name>
505 /* Name of the system */
506 </name>
507
508 <headers>
509 /* The list of paths to header files and/or
510 directories with header files, one per line */
511 </headers>
512
513 <libs>
514 /* The list of paths to shared libraries and/or
515 directories with shared libraries, one per line */
516 </libs>
517
518 /* Optional sections */
519
520 <search_headers>
521 /* List of directories to be searched
522 for header files to automatically
523 generate include paths, one per line */
524 </search_headers>
525
526 <search_libs>
527 /* List of directories to be searched
528 for shared libraries to resolve
529 dependencies, one per line */
530 </search_libs>
531
532 <tools>
533 /* List of directories with tools used
534 for analysis (GCC toolchain), one per line */
535 </tools>
536
537 <cross_prefix>
538 /* GCC toolchain prefix.
539 Examples:
540 arm-linux-gnueabi
541 arm-none-symbianelf */
542 </cross_prefix>
543
544 <gcc_options>
545 /* Additional GCC options, one per line */
546 </gcc_options>
547
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400548 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400549 This option may be used with -dump-system to dump ABI of operating
550 systems and configure the dumping process.
551 Default:
552 modules/Targets/{unix, symbian, windows}
553
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400554 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400555 Compare two system ABI dumps. Create compatibility reports for each
556 library and the common HTML report including the summary of test
557 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400558 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400559
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400560 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400561 The file with a list of libraries, that should be dumped by
562 the -dump-system option or should be checked by the -cmp-systems option.
563
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400564 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400565 Check/Dump ABI of this header only.
566
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400567 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400568 The file with a list of headers, that should be checked/dumped.
569
570 -ext|-extended
571 If your library A is supposed to be used by other library B and you
572 want to control the ABI of B, then you should enable this option. The
573 tool will check for changes in all data types, even if they are not
574 used by any function in the library A. Such data types are not part
575 of the A library ABI, but may be a part of the ABI of the B library.
576
577 The short scheme is:
578 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
579
580 -q|-quiet
581 Print all messages to the file instead of stdout and stderr.
582 Default path (can be changed by -log-path option):
583 $COMMON_LOG_PATH
584
585 -stdout
586 Print analysis results (compatibility reports and ABI dumps) to stdout
587 instead of creating a file. This would allow piping data to other programs.
588
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400589 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400590 Change format of compatibility report.
591 Formats:
592 htm - HTML format (default)
593 xml - XML format
594
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400595 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400596 Change format of ABI dump.
597 Formats:
598 perl - Data::Dumper format (default)
599 xml - XML format
600
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400601 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400602 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400603
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400604 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400605 Set library language (C or C++). You can use this option if the tool
606 cannot auto-detect a language. This option may be useful for checking
607 C-library headers (--lang=C) in --headers-only or --extended modes.
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -binary|-bin|-abi
610 Show \"Binary\" compatibility problems only.
611 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400613
614 -source|-src|-api
615 Show \"Source\" compatibility problems only.
616 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400617 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400619OTHER OPTIONS:
620 -test
621 Run internal tests. Create two binary incompatible versions of a sample
622 library and run the tool to check them for compatibility. This option
623 allows to check if the tool works correctly in the current environment.
624
625 -test-dump
626 Test ability to create, read and compare ABI dumps.
627
628 -debug
629 Debugging mode. Print debug info on the screen. Save intermediate
630 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400631 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400632
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400633 Also consider using --dump option for debugging the tool.
634
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400635 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400636 If your header files are written in C language and can be compiled
637 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
638 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400639
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400640 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400641 Path to file with the function parameter names. It can be used
642 for improving report view if the library header files have no
643 parameter names. File format:
644
645 func1;param1;param2;param3 ...
646 func2;param1;param2;param3 ...
647 ...
648
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400649 -relpath PATH
650 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400651 for dumping the library ABI (see -dump option).
652
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400653 -relpath1 PATH
654 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400655
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400656 -relpath2 PATH
657 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400658
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400659 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400660 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400661 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400662 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400664 -sort
665 Enable sorting of data in ABI dumps.
666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400668 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400671
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400672 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400673 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400674 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400676
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400677 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400678 Path to \"Source\" compatibility report.
679 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400682 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400683 Log path for all messages.
684 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400686
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400687 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400688 Log path for 1st version of a library.
689 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400692 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400693 Log path for 2nd version of a library.
694 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400697 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400698 Change logging mode.
699 Modes:
700 w - overwrite old logs (default)
701 a - append old logs
702 n - do not write any logs
703
704 -list-affected
705 Generate file with the list of incompatible
706 symbols beside the HTML compatibility report.
707 Use 'c++filt \@file' command from GNU binutils
708 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400709 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400710 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400711 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400712
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400713 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400714 The component name in the title and summary of the HTML report.
715 Default:
716 library
717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400718 -l-full|-lib-full NAME
719 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720 will be displayed a name specified by -l option.
721
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400722 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400723 Open report(s) in the browser (firefox, opera, etc.).
724
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400725 -open
726 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400727
728 -extra-info DIR
729 Dump extra info to DIR.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400730
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731REPORT:
732 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400733 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400734
735 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400736 logs/LIB_NAME/V1/log.txt
737 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400738
739EXIT CODES:
740 0 - Compatible. The tool has run without any errors.
741 non-zero - Incompatible or the tool has run with errors.
742
743REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400744 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400745
746MORE INFORMATION:
747 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400748 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749}
750
751my $DescriptorTemplate = "
752<?xml version=\"1.0\" encoding=\"utf-8\"?>
753<descriptor>
754
755/* Primary sections */
756
757<version>
758 /* Version of the library */
759</version>
760
761<headers>
762 /* The list of paths to header files and/or
763 directories with header files, one per line */
764</headers>
765
766<libs>
767 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
768 directories with shared libraries, one per line */
769</libs>
770
771/* Optional sections */
772
773<include_paths>
774 /* The list of include paths that will be provided
775 to GCC to compile library headers, one per line.
776 NOTE: If you define this section then the tool
777 will not automatically generate include paths */
778</include_paths>
779
780<add_include_paths>
781 /* The list of include paths that will be added
782 to the automatically generated include paths, one per line */
783</add_include_paths>
784
785<skip_include_paths>
786 /* The list of include paths that will be removed from the
787 list of automatically generated include paths, one per line */
788</skip_include_paths>
789
790<gcc_options>
791 /* Additional GCC options, one per line */
792</gcc_options>
793
794<include_preamble>
795 /* The list of header files that will be
796 included before other headers, one per line.
797 Examples:
798 1) tree.h for libxml2
799 2) ft2build.h for freetype2 */
800</include_preamble>
801
802<defines>
803 /* The list of defines that will be added at the
804 headers compiling stage, one per line:
805 #define A B
806 #define C D */
807</defines>
808
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400809<add_namespaces>
810 /* The list of namespaces that should be added to the alanysis
811 if the tool cannot find them automatically, one per line */
812</add_namespaces>
813
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400814<skip_types>
815 /* The list of data types, that
816 should not be checked, one per line */
817</skip_types>
818
819<skip_symbols>
820 /* The list of functions (mangled/symbol names in C++),
821 that should not be checked, one per line */
822</skip_symbols>
823
824<skip_namespaces>
825 /* The list of C++ namespaces, that
826 should not be checked, one per line */
827</skip_namespaces>
828
829<skip_constants>
830 /* The list of constants that should
831 not be checked, one name per line */
832</skip_constants>
833
834<skip_headers>
835 /* The list of header files and/or directories
836 with header files that should not be checked, one per line */
837</skip_headers>
838
839<skip_libs>
840 /* The list of shared libraries and/or directories
841 with shared libraries that should not be checked, one per line */
842</skip_libs>
843
844<skip_including>
845 /* The list of header files, that cannot be included
846 directly (or non-self compiled ones), one per line */
847</skip_including>
848
849<search_headers>
850 /* List of directories to be searched
851 for header files to automatically
852 generate include paths, one per line. */
853</search_headers>
854
855<search_libs>
856 /* List of directories to be searched
857 for shared librariess to resolve
858 dependencies, one per line */
859</search_libs>
860
861<tools>
862 /* List of directories with tools used
863 for analysis (GCC toolchain), one per line */
864</tools>
865
866<cross_prefix>
867 /* GCC toolchain prefix.
868 Examples:
869 arm-linux-gnueabi
870 arm-none-symbianelf */
871</cross_prefix>
872
873</descriptor>";
874
875my %Operator_Indication = (
876 "not" => "~",
877 "assign" => "=",
878 "andassign" => "&=",
879 "orassign" => "|=",
880 "xorassign" => "^=",
881 "or" => "|",
882 "xor" => "^",
883 "addr" => "&",
884 "and" => "&",
885 "lnot" => "!",
886 "eq" => "==",
887 "ne" => "!=",
888 "lt" => "<",
889 "lshift" => "<<",
890 "lshiftassign" => "<<=",
891 "rshiftassign" => ">>=",
892 "call" => "()",
893 "mod" => "%",
894 "modassign" => "%=",
895 "subs" => "[]",
896 "land" => "&&",
897 "lor" => "||",
898 "rshift" => ">>",
899 "ref" => "->",
900 "le" => "<=",
901 "deref" => "*",
902 "mult" => "*",
903 "preinc" => "++",
904 "delete" => " delete",
905 "vecnew" => " new[]",
906 "vecdelete" => " delete[]",
907 "predec" => "--",
908 "postinc" => "++",
909 "postdec" => "--",
910 "plusassign" => "+=",
911 "plus" => "+",
912 "minus" => "-",
913 "minusassign" => "-=",
914 "gt" => ">",
915 "ge" => ">=",
916 "new" => " new",
917 "multassign" => "*=",
918 "divassign" => "/=",
919 "div" => "/",
920 "neg" => "-",
921 "pos" => "+",
922 "memref" => "->*",
923 "compound" => "," );
924
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400925my %UnknownOperator;
926
927my %NodeType= (
928 "array_type" => "Array",
929 "binfo" => "Other",
930 "boolean_type" => "Intrinsic",
931 "complex_type" => "Intrinsic",
932 "const_decl" => "Other",
933 "enumeral_type" => "Enum",
934 "field_decl" => "Other",
935 "function_decl" => "Other",
936 "function_type" => "FunctionType",
937 "identifier_node" => "Other",
938 "integer_cst" => "Other",
939 "integer_type" => "Intrinsic",
940 "method_type" => "MethodType",
941 "namespace_decl" => "Other",
942 "parm_decl" => "Other",
943 "pointer_type" => "Pointer",
944 "real_cst" => "Other",
945 "real_type" => "Intrinsic",
946 "record_type" => "Struct",
947 "reference_type" => "Ref",
948 "string_cst" => "Other",
949 "template_decl" => "Other",
950 "template_type_parm" => "Other",
951 "tree_list" => "Other",
952 "tree_vec" => "Other",
953 "type_decl" => "Other",
954 "union_type" => "Union",
955 "var_decl" => "Other",
956 "void_type" => "Intrinsic",
957 # "nop_expr" => "Other",
958 # "addr_expr" => "Other",
959 "offset_type" => "Other" );
960
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400961my %CppKeywords_C = map {$_=>1} (
962 # C++ 2003 keywords
963 "public",
964 "protected",
965 "private",
966 "default",
967 "template",
968 "new",
969 #"asm",
970 "dynamic_cast",
971 "auto",
972 "try",
973 "namespace",
974 "typename",
975 "using",
976 "reinterpret_cast",
977 "friend",
978 "class",
979 "virtual",
980 "const_cast",
981 "mutable",
982 "static_cast",
983 "export",
984 # C++0x keywords
985 "noexcept",
986 "nullptr",
987 "constexpr",
988 "static_assert",
989 "explicit",
990 # cannot be used as a macro name
991 # as it is an operator in C++
992 "and",
993 #"and_eq",
994 "not",
995 #"not_eq",
996 "or"
997 #"or_eq",
998 #"bitand",
999 #"bitor",
1000 #"xor",
1001 #"xor_eq",
1002 #"compl"
1003);
1004
1005my %CppKeywords_F = map {$_=>1} (
1006 "delete",
1007 "catch",
1008 "alignof",
1009 "thread_local",
1010 "decltype",
1011 "typeid"
1012);
1013
1014my %CppKeywords_O = map {$_=>1} (
1015 "bool",
1016 "register",
1017 "inline",
1018 "operator"
1019);
1020
1021my %CppKeywords_A = map {$_=>1} (
1022 "this",
1023 "throw"
1024);
1025
1026foreach (keys(%CppKeywords_C),
1027keys(%CppKeywords_F),
1028keys(%CppKeywords_O)) {
1029 $CppKeywords_A{$_}=1;
1030}
1031
1032# Header file extensions as described by gcc
1033my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1034
1035my %IntrinsicMangling = (
1036 "void" => "v",
1037 "bool" => "b",
1038 "wchar_t" => "w",
1039 "char" => "c",
1040 "signed char" => "a",
1041 "unsigned char" => "h",
1042 "short" => "s",
1043 "unsigned short" => "t",
1044 "int" => "i",
1045 "unsigned int" => "j",
1046 "long" => "l",
1047 "unsigned long" => "m",
1048 "long long" => "x",
1049 "__int64" => "x",
1050 "unsigned long long" => "y",
1051 "__int128" => "n",
1052 "unsigned __int128" => "o",
1053 "float" => "f",
1054 "double" => "d",
1055 "long double" => "e",
1056 "__float80" => "e",
1057 "__float128" => "g",
1058 "..." => "z"
1059);
1060
1061my %StdcxxMangling = (
1062 "3std"=>"St",
1063 "3std9allocator"=>"Sa",
1064 "3std12basic_string"=>"Sb",
1065 "3std12basic_stringIcE"=>"Ss",
1066 "3std13basic_istreamIcE"=>"Si",
1067 "3std13basic_ostreamIcE"=>"So",
1068 "3std14basic_iostreamIcE"=>"Sd"
1069);
1070
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001071my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits)";
1072
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001073my %ConstantSuffix = (
1074 "unsigned int"=>"u",
1075 "long"=>"l",
1076 "unsigned long"=>"ul",
1077 "long long"=>"ll",
1078 "unsigned long long"=>"ull"
1079);
1080
1081my %ConstantSuffixR =
1082reverse(%ConstantSuffix);
1083
1084my %OperatorMangling = (
1085 "~" => "co",
1086 "=" => "aS",
1087 "|" => "or",
1088 "^" => "eo",
1089 "&" => "an",#ad (addr)
1090 "==" => "eq",
1091 "!" => "nt",
1092 "!=" => "ne",
1093 "<" => "lt",
1094 "<=" => "le",
1095 "<<" => "ls",
1096 "<<=" => "lS",
1097 ">" => "gt",
1098 ">=" => "ge",
1099 ">>" => "rs",
1100 ">>=" => "rS",
1101 "()" => "cl",
1102 "%" => "rm",
1103 "[]" => "ix",
1104 "&&" => "aa",
1105 "||" => "oo",
1106 "*" => "ml",#de (deref)
1107 "++" => "pp",#
1108 "--" => "mm",#
1109 "new" => "nw",
1110 "delete" => "dl",
1111 "new[]" => "na",
1112 "delete[]" => "da",
1113 "+=" => "pL",
1114 "+" => "pl",#ps (pos)
1115 "-" => "mi",#ng (neg)
1116 "-=" => "mI",
1117 "*=" => "mL",
1118 "/=" => "dV",
1119 "&=" => "aN",
1120 "|=" => "oR",
1121 "%=" => "rM",
1122 "^=" => "eO",
1123 "/" => "dv",
1124 "->*" => "pm",
1125 "->" => "pt",#rf (ref)
1126 "," => "cm",
1127 "?" => "qu",
1128 "." => "dt",
1129 "sizeof"=> "sz"#st
1130);
1131
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001132my %Intrinsic_Keywords = map {$_=>1} (
1133 "true",
1134 "false",
1135 "_Bool",
1136 "_Complex",
1137 "const",
1138 "int",
1139 "long",
1140 "void",
1141 "short",
1142 "float",
1143 "volatile",
1144 "restrict",
1145 "unsigned",
1146 "signed",
1147 "char",
1148 "double",
1149 "class",
1150 "struct",
1151 "union",
1152 "enum"
1153);
1154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001155my %GlibcHeader = map {$_=>1} (
1156 "aliases.h",
1157 "argp.h",
1158 "argz.h",
1159 "assert.h",
1160 "cpio.h",
1161 "ctype.h",
1162 "dirent.h",
1163 "envz.h",
1164 "errno.h",
1165 "error.h",
1166 "execinfo.h",
1167 "fcntl.h",
1168 "fstab.h",
1169 "ftw.h",
1170 "glob.h",
1171 "grp.h",
1172 "iconv.h",
1173 "ifaddrs.h",
1174 "inttypes.h",
1175 "langinfo.h",
1176 "limits.h",
1177 "link.h",
1178 "locale.h",
1179 "malloc.h",
1180 "math.h",
1181 "mntent.h",
1182 "monetary.h",
1183 "nl_types.h",
1184 "obstack.h",
1185 "printf.h",
1186 "pwd.h",
1187 "regex.h",
1188 "sched.h",
1189 "search.h",
1190 "setjmp.h",
1191 "shadow.h",
1192 "signal.h",
1193 "spawn.h",
1194 "stdarg.h",
1195 "stdint.h",
1196 "stdio.h",
1197 "stdlib.h",
1198 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001199 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001200 "tar.h",
1201 "termios.h",
1202 "time.h",
1203 "ulimit.h",
1204 "unistd.h",
1205 "utime.h",
1206 "wchar.h",
1207 "wctype.h",
1208 "wordexp.h" );
1209
1210my %GlibcDir = map {$_=>1} (
1211 "arpa",
1212 "bits",
1213 "gnu",
1214 "netinet",
1215 "net",
1216 "nfs",
1217 "rpc",
1218 "sys",
1219 "linux" );
1220
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001221my %WinHeaders = map {$_=>1} (
1222 "dos.h",
1223 "process.h",
1224 "winsock.h",
1225 "config-win.h",
1226 "mem.h",
1227 "windows.h",
1228 "winsock2.h",
1229 "crtdbg.h",
1230 "ws2tcpip.h"
1231);
1232
1233my %ObsoleteHeaders = map {$_=>1} (
1234 "iostream.h",
1235 "fstream.h"
1236);
1237
1238my %ConfHeaders = map {$_=>1} (
1239 "atomic",
1240 "conf.h",
1241 "config.h",
1242 "configure.h",
1243 "build.h",
1244 "setup.h"
1245);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my %LocalIncludes = map {$_=>1} (
1248 "/usr/local/include",
1249 "/usr/local" );
1250
1251my %OS_AddPath=(
1252# These paths are needed if the tool cannot detect them automatically
1253 "macos"=>{
1254 "include"=>{
1255 "/Library"=>1,
1256 "/Developer/usr/include"=>1
1257 },
1258 "lib"=>{
1259 "/Library"=>1,
1260 "/Developer/usr/lib"=>1
1261 },
1262 "bin"=>{
1263 "/Developer/usr/bin"=>1
1264 }
1265 },
1266 "beos"=>{
1267 # Haiku has GCC 2.95.3 by default
1268 # try to find GCC>=3.0 in /boot/develop/abi
1269 "include"=>{
1270 "/boot/common"=>1,
1271 "/boot/develop"=>1},
1272 "lib"=>{
1273 "/boot/common/lib"=>1,
1274 "/boot/system/lib"=>1,
1275 "/boot/apps"=>1},
1276 "bin"=>{
1277 "/boot/common/bin"=>1,
1278 "/boot/system/bin"=>1,
1279 "/boot/develop/abi"=>1
1280 }
1281}
1282);
1283
1284my %Slash_Type=(
1285 "default"=>"/",
1286 "windows"=>"\\"
1287);
1288
1289my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1290
1291# Global Variables
1292my %COMMON_LANGUAGE=(
1293 1 => "C",
1294 2 => "C" );
1295
1296my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001297my $MAX_CPPFILT_FILE_SIZE = 50000;
1298my $CPPFILT_SUPPORT_FILE;
1299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001300my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1301
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001302my $STDCXX_TESTING = 0;
1303my $GLIBC_TESTING = 0;
1304
1305my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1306my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001307my $TargetComponent;
1308
1309# Set Target Component Name
1310if($TargetComponent_Opt) {
1311 $TargetComponent = lc($TargetComponent_Opt);
1312}
1313else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001314{ # default: library
1315 # other components: header, system, ...
1316 $TargetComponent = "library";
1317}
1318
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001319my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1320
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001321my $SystemRoot;
1322
1323my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001324my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001325my %LOG_PATH;
1326my %DEBUG_PATH;
1327my %Cache;
1328my %LibInfo;
1329my $COMPILE_ERRORS = 0;
1330my %CompilerOptions;
1331my %CheckedDyLib;
1332my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1333
1334# Constants (#defines)
1335my %Constants;
1336my %SkipConstants;
1337
1338# Types
1339my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001341my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342my %SkipTypes = (
1343 "1"=>{},
1344 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001345my %CheckedTypes;
1346my %TName_Tid;
1347my %EnumMembName_Id;
1348my %NestedNameSpaces = (
1349 "1"=>{},
1350 "2"=>{} );
1351my %UsedType;
1352my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001353my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001354my %ClassVTable;
1355my %ClassVTable_Content;
1356my %VTableClass;
1357my %AllocableClass;
1358my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001359my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %Class_SubClasses;
1361my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001362my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Typedefs
1365my %Typedef_BaseName;
1366my %Typedef_Tr;
1367my %Typedef_Eq;
1368my %StdCxxTypedef;
1369my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001370my %MissedBase;
1371my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001372my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001373
1374# Symbols
1375my %SymbolInfo;
1376my %tr_name;
1377my %mangled_name_gcc;
1378my %mangled_name;
1379my %SkipSymbols = (
1380 "1"=>{},
1381 "2"=>{} );
1382my %SkipNameSpaces = (
1383 "1"=>{},
1384 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001385my %AddNameSpaces = (
1386 "1"=>{},
1387 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my %SymbolsList;
1389my %SymbolsList_App;
1390my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001391my %Symbol_Library = (
1392 "1"=>{},
1393 "2"=>{} );
1394my %Library_Symbol = (
1395 "1"=>{},
1396 "2"=>{} );
1397my %DepSymbol_Library = (
1398 "1"=>{},
1399 "2"=>{} );
1400my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001401 "1"=>{},
1402 "2"=>{} );
1403my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001404my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my %AddIntParams;
1406my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001407my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001408my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001409
1410# Headers
1411my %Include_Preamble;
1412my %Registered_Headers;
1413my %HeaderName_Paths;
1414my %Header_Dependency;
1415my %Include_Neighbors;
1416my %Include_Paths;
1417my %INC_PATH_AUTODETECT = (
1418 "1"=>1,
1419 "2"=>1 );
1420my %Add_Include_Paths;
1421my %Skip_Include_Paths;
1422my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001423my %Header_ErrorRedirect;
1424my %Header_Includes;
1425my %Header_ShouldNotBeUsed;
1426my %RecursiveIncludes;
1427my %Header_Include_Prefix;
1428my %SkipHeaders;
1429my %SkipHeadersList=(
1430 "1"=>{},
1431 "2"=>{} );
1432my %SkipLibs;
1433my %Include_Order;
1434my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001435my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001436my %TUnit_Funcs;
1437my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001439my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440 "1"=>0,
1441 "2"=>0 );
1442my %AutoPreambleMode = (
1443 "1"=>0,
1444 "2"=>0 );
1445my %MinGWMode = (
1446 "1"=>0,
1447 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001448my %Cpp0xMode = (
1449 "1"=>0,
1450 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001451
1452# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001453my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001454my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001455my %RegisteredSONAMEs;
1456my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001457
1458# System Objects
1459my %SystemObjects;
1460my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001461my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001462
1463# System Headers
1464my %SystemHeaders;
1465my %DefaultCppPaths;
1466my %DefaultGccPaths;
1467my %DefaultIncPaths;
1468my %DefaultCppHeader;
1469my %DefaultGccHeader;
1470my %UserIncPath;
1471
1472# Merging
1473my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001474my $Version;
1475my %AddedInt;
1476my %RemovedInt;
1477my %AddedInt_Virt;
1478my %RemovedInt_Virt;
1479my %VirtualReplacement;
1480my %ChangedTypedef;
1481my %CompatRules;
1482my %IncompleteRules;
1483my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001484my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001485my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001486my %ReturnedClass;
1487my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001488my %SourceAlternative;
1489my %SourceAlternative_B;
1490my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001491
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001492# Calling Conventions
1493my %UseConv_Real = (
1494 "1"=>0,
1495 "2"=>0 );
1496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001497# OS Compliance
1498my %TargetLibs;
1499my %TargetHeaders;
1500
1501# OS Specifics
1502my $OStarget = $OSgroup;
1503my %TargetTools;
1504
1505# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001506my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001507
1508# Recursion locks
1509my @RecurLib;
1510my @RecurSymlink;
1511my @RecurTypes;
1512my @RecurInclude;
1513my @RecurConstant;
1514
1515# System
1516my %SystemPaths;
1517my %DefaultBinPaths;
1518my $GCC_PATH;
1519
1520# Symbols versioning
1521my %SymVer = (
1522 "1"=>{},
1523 "2"=>{} );
1524
1525# Problem descriptions
1526my %CompatProblems;
1527my %ProblemsWithConstants;
1528my %ImplProblems;
1529my %TotalAffected;
1530
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001531# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001532my $ContentID = 1;
1533my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1534my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanEnd = "</span>\n";
1537my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1538my $ContentDivEnd = "</div>\n";
1539my $Content_Counter = 0;
1540
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001541# XML Dump
1542my $TAG_ID = 0;
1543my $INDENT = " ";
1544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001545# Modes
1546my $JoinReport = 1;
1547my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001548
1549sub get_Modules()
1550{
1551 my $TOOL_DIR = get_dirname($0);
1552 if(not $TOOL_DIR)
1553 { # patch for MS Windows
1554 $TOOL_DIR = ".";
1555 }
1556 my @SEARCH_DIRS = (
1557 # tool's directory
1558 abs_path($TOOL_DIR),
1559 # relative path to modules
1560 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1561 # system directory
1562 "ACC_MODULES_INSTALL_PATH"
1563 );
1564 foreach my $DIR (@SEARCH_DIRS)
1565 {
1566 if(not is_abs($DIR))
1567 { # relative path
1568 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1569 }
1570 if(-d $DIR."/modules") {
1571 return $DIR."/modules";
1572 }
1573 }
1574 exitStatus("Module_Error", "can't find modules");
1575}
1576
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001577my %LoadedModules = ();
1578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001579sub loadModule($)
1580{
1581 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001582 if(defined $LoadedModules{$Name}) {
1583 return;
1584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001585 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1586 if(not -f $Path) {
1587 exitStatus("Module_Error", "can't access \'$Path\'");
1588 }
1589 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001590 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001591}
1592
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001593sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001594{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001595 my $Number = $_[0];
1596 if(not $Number) {
1597 $Number = 1;
1598 }
1599 else {
1600 $Number = int($Number)+1;
1601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001602 if($Number>3) {
1603 return $Number."th";
1604 }
1605 elsif($Number==1) {
1606 return "1st";
1607 }
1608 elsif($Number==2) {
1609 return "2nd";
1610 }
1611 elsif($Number==3) {
1612 return "3rd";
1613 }
1614 else {
1615 return $Number;
1616 }
1617}
1618
1619sub search_Tools($)
1620{
1621 my $Name = $_[0];
1622 return "" if(not $Name);
1623 if(my @Paths = keys(%TargetTools))
1624 {
1625 foreach my $Path (@Paths)
1626 {
1627 if(-f joinPath($Path, $Name)) {
1628 return joinPath($Path, $Name);
1629 }
1630 if($CrossPrefix)
1631 { # user-defined prefix (arm-none-symbianelf, ...)
1632 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1633 if(-f $Candidate) {
1634 return $Candidate;
1635 }
1636 }
1637 }
1638 }
1639 else {
1640 return "";
1641 }
1642}
1643
1644sub synch_Cmd($)
1645{
1646 my $Name = $_[0];
1647 if(not $GCC_PATH)
1648 { # GCC was not found yet
1649 return "";
1650 }
1651 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001652 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001653 return $Candidate;
1654 }
1655 return "";
1656}
1657
1658sub get_CmdPath($)
1659{
1660 my $Name = $_[0];
1661 return "" if(not $Name);
1662 if(defined $Cache{"get_CmdPath"}{$Name}) {
1663 return $Cache{"get_CmdPath"}{$Name};
1664 }
1665 my %BinUtils = map {$_=>1} (
1666 "c++filt",
1667 "objdump",
1668 "readelf"
1669 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001670 if($BinUtils{$Name} and $GCC_PATH)
1671 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 if(my $Dir = get_dirname($GCC_PATH)) {
1673 $TargetTools{$Dir}=1;
1674 }
1675 }
1676 my $Path = search_Tools($Name);
1677 if(not $Path and $OSgroup eq "windows") {
1678 $Path = search_Tools($Name.".exe");
1679 }
1680 if(not $Path and $BinUtils{$Name})
1681 {
1682 if($CrossPrefix)
1683 { # user-defined prefix
1684 $Path = search_Cmd($CrossPrefix."-".$Name);
1685 }
1686 }
1687 if(not $Path and $BinUtils{$Name})
1688 {
1689 if(my $Candidate = synch_Cmd($Name))
1690 { # synch with GCC
1691 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001692 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 if(-f $Candidate) {
1694 $Path = $Candidate;
1695 }
1696 }
1697 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001698 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 $Path = $Candidate;
1700 }
1701 }
1702 }
1703 if(not $Path) {
1704 $Path = search_Cmd($Name);
1705 }
1706 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001707 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001708 $Path=search_Cmd($Name.".exe");
1709 }
1710 if($Path=~/\s/) {
1711 $Path = "\"".$Path."\"";
1712 }
1713 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1714}
1715
1716sub search_Cmd($)
1717{
1718 my $Name = $_[0];
1719 return "" if(not $Name);
1720 if(defined $Cache{"search_Cmd"}{$Name}) {
1721 return $Cache{"search_Cmd"}{$Name};
1722 }
1723 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1724 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1725 }
1726 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1727 {
1728 my $CmdPath = joinPath($Path,$Name);
1729 if(-f $CmdPath)
1730 {
1731 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001732 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001733 }
1734 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1735 }
1736 }
1737 return ($Cache{"search_Cmd"}{$Name} = "");
1738}
1739
1740sub get_CmdPath_Default($)
1741{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001742 return "" if(not $_[0]);
1743 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1744 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001746 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1747}
1748
1749sub get_CmdPath_Default_I($)
1750{ # search in PATH
1751 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 if($Name=~/find/)
1753 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001754 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001755 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001756 }
1757 }
1758 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001759 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001760 }
1761 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001762 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001764 if($OSgroup eq "windows")
1765 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001766 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001767 return $Name;
1768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001769 }
1770 if($Name!~/which/)
1771 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001772 if(my $WhichCmd = get_CmdPath("which"))
1773 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001774 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001775 return $Name;
1776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001777 }
1778 }
1779 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1780 {
1781 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001782 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001783 }
1784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001785 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786}
1787
1788sub clean_path($)
1789{
1790 my $Path = $_[0];
1791 $Path=~s/[\/\\]+\Z//g;
1792 return $Path;
1793}
1794
1795sub classifyPath($)
1796{
1797 my $Path = $_[0];
1798 if($Path=~/[\*\[]/)
1799 { # wildcard
1800 $Path=~s/\*/.*/g;
1801 $Path=~s/\\/\\\\/g;
1802 return ($Path, "Pattern");
1803 }
1804 elsif($Path=~/[\/\\]/)
1805 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001806 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001807 return (path_format($Path, $OSgroup), "Path");
1808 }
1809 else {
1810 return ($Path, "Name");
1811 }
1812}
1813
1814sub readDescriptor($$)
1815{
1816 my ($LibVersion, $Content) = @_;
1817 return if(not $LibVersion);
1818 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1819 if(not $Content) {
1820 exitStatus("Error", "$DName is empty");
1821 }
1822 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001823 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001824 }
1825 $Content=~s/\/\*(.|\n)+?\*\///g;
1826 $Content=~s/<\!--(.|\n)+?-->//g;
1827 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1828 if($TargetVersion{$LibVersion}) {
1829 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1830 }
1831 if(not $Descriptor{$LibVersion}{"Version"}) {
1832 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1833 }
1834 if($Content=~/{RELPATH}/)
1835 {
1836 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1837 $Content =~ s/{RELPATH}/$RelDir/g;
1838 }
1839 else
1840 {
1841 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1842 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1843 }
1844 }
1845
1846 if(not $CheckObjectsOnly_Opt)
1847 {
1848 my $DHeaders = parseTag(\$Content, "headers");
1849 if(not $DHeaders) {
1850 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1851 }
1852 elsif(lc($DHeaders) ne "none")
1853 { # append the descriptor headers list
1854 if($Descriptor{$LibVersion}{"Headers"})
1855 { # multiple descriptors
1856 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1857 }
1858 else {
1859 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1860 }
1861 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1862 {
1863 if(not -e $Path) {
1864 exitStatus("Access_Error", "can't access \'$Path\'");
1865 }
1866 }
1867 }
1868 }
1869 if(not $CheckHeadersOnly_Opt)
1870 {
1871 my $DObjects = parseTag(\$Content, "libs");
1872 if(not $DObjects) {
1873 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1874 }
1875 elsif(lc($DObjects) ne "none")
1876 { # append the descriptor libraries list
1877 if($Descriptor{$LibVersion}{"Libs"})
1878 { # multiple descriptors
1879 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1880 }
1881 else {
1882 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1883 }
1884 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1885 {
1886 if(not -e $Path) {
1887 exitStatus("Access_Error", "can't access \'$Path\'");
1888 }
1889 }
1890 }
1891 }
1892 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1893 {
1894 $Path = clean_path($Path);
1895 if(not -d $Path) {
1896 exitStatus("Access_Error", "can't access directory \'$Path\'");
1897 }
1898 $Path = path_format($Path, $OSgroup);
1899 $SystemPaths{"include"}{$Path}=1;
1900 }
1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1902 {
1903 $Path = clean_path($Path);
1904 if(not -d $Path) {
1905 exitStatus("Access_Error", "can't access directory \'$Path\'");
1906 }
1907 $Path = path_format($Path, $OSgroup);
1908 $SystemPaths{"lib"}{$Path}=1;
1909 }
1910 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1911 {
1912 $Path=clean_path($Path);
1913 if(not -d $Path) {
1914 exitStatus("Access_Error", "can't access directory \'$Path\'");
1915 }
1916 $Path = path_format($Path, $OSgroup);
1917 $SystemPaths{"bin"}{$Path}=1;
1918 $TargetTools{$Path}=1;
1919 }
1920 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1921 $CrossPrefix = $Prefix;
1922 }
1923 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1924 {
1925 $Path=clean_path($Path);
1926 if(not -d $Path) {
1927 exitStatus("Access_Error", "can't access directory \'$Path\'");
1928 }
1929 $Path = path_format($Path, $OSgroup);
1930 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1931 }
1932 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1933 {
1934 $Path=clean_path($Path);
1935 if(not -d $Path) {
1936 exitStatus("Access_Error", "can't access directory \'$Path\'");
1937 }
1938 $Path = path_format($Path, $OSgroup);
1939 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1940 }
1941 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1942 {
1943 # skip some auto-generated include paths
1944 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1945 }
1946 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1947 {
1948 # skip direct including of some headers
1949 my ($CPath, $Type) = classifyPath($Path);
1950 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001951 }
1952 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1953 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1954 $CompilerOptions{$LibVersion} .= " ".$Option;
1955 }
1956 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1957 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1958 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001959 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 my ($CPath, $Type) = classifyPath($Path);
1961 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 }
1963 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1964 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1965 {
1966 my ($CPath, $Type) = classifyPath($Path);
1967 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1968 }
1969 if(my $DDefines = parseTag(\$Content, "defines"))
1970 {
1971 if($Descriptor{$LibVersion}{"Defines"})
1972 { # multiple descriptors
1973 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1974 }
1975 else {
1976 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1977 }
1978 }
1979 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1980 {
1981 if($Order=~/\A(.+):(.+)\Z/) {
1982 $Include_Order{$LibVersion}{$1} = $2;
1983 }
1984 }
1985 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1986 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001987 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001988 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1989 }
1990 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1991 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001992 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1994 }
1995 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1996 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1997 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001998 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1999 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2000 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002001 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2002 $SkipConstants{$LibVersion}{$Constant} = 1;
2003 }
2004 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2005 {
2006 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002007 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002008 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2009 }
2010 else {
2011 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2012 }
2013 }
2014}
2015
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002016sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002017{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002018 my $CodeRef = shift(@_);
2019 my $Tag = shift(@_);
2020 if(not $Tag or not $CodeRef) {
2021 return undef;
2022 }
2023 my $Sp = 0;
2024 if(@_) {
2025 $Sp = shift(@_);
2026 }
2027 my $Start = index(${$CodeRef}, "<$Tag>");
2028 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002029 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002030 my $End = index(${$CodeRef}, "</$Tag>");
2031 if($End!=-1)
2032 {
2033 my $TS = length($Tag)+3;
2034 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2035 substr($Content, 0, $TS-1, ""); # cut start tag
2036 substr($Content, -$TS, $TS, ""); # cut end tag
2037 if(not $Sp)
2038 {
2039 $Content=~s/\A\s+//g;
2040 $Content=~s/\s+\Z//g;
2041 }
2042 if(substr($Content, 0, 1) ne "<") {
2043 $Content = xmlSpecChars_R($Content);
2044 }
2045 return $Content;
2046 }
2047 }
2048 return undef;
2049}
2050
2051sub parseTag_E($$$)
2052{
2053 my ($CodeRef, $Tag, $Info) = @_;
2054 if(not $Tag or not $CodeRef
2055 or not $Info) {
2056 return undef;
2057 }
2058 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2059 {
2060 my ($Ext, $Content) = ($2, $3);
2061 $Content=~s/\A\s+//g;
2062 $Content=~s/\s+\Z//g;
2063 if($Ext)
2064 {
2065 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2066 {
2067 my ($K, $V) = ($1, $2);
2068 $Info->{$K} = xmlSpecChars_R($V);
2069 }
2070 }
2071 if(substr($Content, 0, 1) ne "<") {
2072 $Content = xmlSpecChars_R($Content);
2073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002074 return $Content;
2075 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002076 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002077}
2078
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002079sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002080{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002081 my $Tag = shift(@_);
2082 my $Val = shift(@_);
2083 my @Ext = @_;
2084 my $Content = openTag($Tag, @Ext);
2085 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002086 $Content .= xmlSpecChars($Val);
2087 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002088 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002089
2090 return $Content;
2091}
2092
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002093sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002094{
2095 my $Tag = shift(@_);
2096 my @Ext = @_;
2097 my $Content = "";
2098 foreach (1 .. $TAG_ID) {
2099 $Content .= $INDENT;
2100 }
2101 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002102 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002103 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002104 $Content .= "<".$Tag;
2105 my $P = 0;
2106 while($P<=$#Ext-1)
2107 {
2108 $Content .= " ".$Ext[$P];
2109 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2110 $P+=2;
2111 }
2112 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002113 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002114 else {
2115 $Content .= "<".$Tag.">\n";
2116 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002117 return $Content;
2118}
2119
2120sub closeTag($)
2121{
2122 my $Tag = $_[0];
2123 my $Content = "";
2124 $TAG_ID-=1;
2125 foreach (1 .. $TAG_ID) {
2126 $Content .= $INDENT;
2127 }
2128 $Content .= "</".$Tag.">\n";
2129 return $Content;
2130}
2131
2132sub checkTags()
2133{
2134 if($TAG_ID!=0) {
2135 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2136 }
2137}
2138
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002139sub getInfo($)
2140{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002141 my $DumpPath = $_[0];
2142 return if(not $DumpPath or not -f $DumpPath);
2143
2144 readTUDump($DumpPath);
2145
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 # processing info
2147 setTemplateParams_All();
2148 getTypeInfo_All();
2149 simplifyNames();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002150 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002151 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002153 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154 %LibInfo = ();
2155 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002156 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002157 %TemplateDecl = ();
2158 %StdCxxTypedef = ();
2159 %MissedTypedef = ();
2160 %Typedef_Tr = ();
2161 %Typedef_Eq = ();
2162
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002163 # clean cache
2164 delete($Cache{"getTypeAttr"});
2165 delete($Cache{"getTypeDeclId"});
2166
2167 # remove unused types
2168 if($BinaryOnly and not $ExtendedCheck)
2169 { # --binary
2170 removeUnused($Version, "All");
2171 }
2172 else {
2173 removeUnused($Version, "Derived");
2174 }
2175
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002176 if($Debug) {
2177 # debugMangling($Version);
2178 }
2179}
2180
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002181sub readTUDump($)
2182{
2183 my $DumpPath = $_[0];
2184
2185 open(TU_DUMP, $DumpPath);
2186 local $/ = undef;
2187 my $Content = <TU_DUMP>;
2188 close(TU_DUMP);
2189
2190 unlink($DumpPath);
2191
2192 $Content=~s/\n[ ]+/ /g;
2193 my @Lines = split("\n", $Content);
2194
2195 # clean memory
2196 undef $Content;
2197
2198 $MAX_ID = $#Lines+1;
2199
2200 foreach (0 .. $#Lines)
2201 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002202 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002203 { # get a number and attributes of a node
2204 next if(not $NodeType{$2});
2205 $LibInfo{$Version}{"info_type"}{$1}=$2;
2206 $LibInfo{$Version}{"info"}{$1}=$3;
2207 }
2208
2209 # clean memory
2210 delete($Lines[$_]);
2211 }
2212
2213 # clean memory
2214 undef @Lines;
2215}
2216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002217sub simplifyNames()
2218{
2219 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2220 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002221 if($Typedef_Eq{$Version}{$Base}) {
2222 next;
2223 }
2224 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2225 if($#Translations==0)
2226 {
2227 if(length($Translations[0])<=length($Base)) {
2228 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2229 }
2230 }
2231 else
2232 { # select most appropriate
2233 foreach my $Tr (@Translations)
2234 {
2235 if($Base=~/\A\Q$Tr\E/)
2236 {
2237 $Typedef_Eq{$Version}{$Base} = $Tr;
2238 last;
2239 }
2240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002241 }
2242 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002243 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002245 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 if(not $TypeName) {
2247 next;
2248 }
2249 next if(index($TypeName,"<")==-1);# template instances only
2250 if($TypeName=~/>(::\w+)+\Z/)
2251 { # skip unused types
2252 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002254 foreach my $Base (sort {length($b)<=>length($a)}
2255 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002257 next if(not $Base);
2258 next if(index($TypeName,$Base)==-1);
2259 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002260 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002262 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2263 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2264 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002265 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002266 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2267 {
2268 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2269 {
2270 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2271 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002272 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002273 }
2274 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002275 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002277 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002278 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002279 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2280 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002281 }
2282}
2283
2284sub setTemplateParams_All()
2285{
2286 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2287 {
2288 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2289 setTemplateParams($_);
2290 }
2291 }
2292}
2293
2294sub setTemplateParams($)
2295{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002296 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002298 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002299 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002300 my $TmplInst_Id = $2;
2301 setTemplateInstParams($TmplInst_Id);
2302 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2303 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002305 }
2306 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002307 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002308 {
2309 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2310 {
2311 if($IType eq "record_type") {
2312 $TemplateDecl{$Version}{$TypeId}=1;
2313 }
2314 }
2315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002316}
2317
2318sub setTemplateInstParams($)
2319{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002320 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002321 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002322 my ($Params_InfoId, $ElemId) = ();
2323 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2324 $Params_InfoId = $1;
2325 }
2326 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2327 $ElemId = $1;
2328 }
2329 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002331 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2332 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2333 {
2334 my ($PPos, $PTypeId) = ($1, $2);
2335 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2336 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002337 if($PType eq "template_type_parm")
2338 {
2339 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002340 return;
2341 }
2342 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002343 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2344 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002345 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002346 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002347 else
2348 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002349 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002351 }
2352 }
2353 }
2354}
2355
2356sub getTypeDeclId($)
2357{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002358 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002359 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002360 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2361 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2362 }
2363 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2364 {
2365 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2366 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2367 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002370 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002371}
2372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002373sub getTypeInfo_All()
2374{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002375 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 { # support for GCC < 4.5
2377 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2378 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2379 # FIXME: check GCC versions
2380 addMissedTypes_Pre();
2381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002383 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002384 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2386 if($IType=~/_type\Z/ and $IType ne "function_type"
2387 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002388 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002389 }
2390 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391
2392 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002393 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002394 "Name" => "...",
2395 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002396 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002397 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002398 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002399
2400 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 { # support for GCC < 4.5
2402 addMissedTypes_Post();
2403 }
2404}
2405
2406sub addMissedTypes_Pre()
2407{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002408 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002409 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2410 { # detecting missed typedefs
2411 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2412 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 if($TypeType eq "Unknown")
2417 { # template_type_parm
2418 next;
2419 }
2420 my $TypeDeclId = getTypeDeclId($TypeId);
2421 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2422 my $TypedefName = getNameByInfo($MissedTDid);
2423 next if(not $TypedefName);
2424 next if($TypedefName eq "__float80");
2425 next if(isAnon($TypedefName));
2426 if(not $TypeDeclId
2427 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002428 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002429 }
2430 }
2431 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002432 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002433 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002436 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 next;
2438 }
2439 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002440 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002441 if(not $TypedefName) {
2442 next;
2443 }
2444 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 my %MissedInfo = ( # typedef info
2446 "Name" => $TypedefName,
2447 "NameSpace" => $TypedefNS,
2448 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 "Tid" => $Tid
2450 },
2451 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002452 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 my ($H, $L) = getLocation($MissedTDid);
2454 $MissedInfo{"Header"} = $H;
2455 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002456 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 { # other types
2458 next;
2459 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002460 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 next;
2463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002466 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002468 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 next;
2471 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002472 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 next;
2474 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002475 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 next;
2478 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002479 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 next;
2482 }
2483 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484
2485 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002489 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002490 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002492
2493 # add missed & remove other
2494 $TypeInfo{$Version} = \%AddTypes;
2495 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496}
2497
2498sub addMissedTypes_Post()
2499{
2500 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2501 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002502 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2503 {
2504 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2505 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2506 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2507 }
2508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002509 }
2510}
2511
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002512sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002513{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002514 my $TypeId = $_[0];
2515 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2516 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002518 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002520}
2521
2522sub getArraySize($$)
2523{
2524 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002525 if(my $Size = getSize($TypeId))
2526 {
2527 my $Elems = $Size/$BYTE_SIZE;
2528 while($BaseName=~s/\s*\[(\d+)\]//) {
2529 $Elems/=$1;
2530 }
2531 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2532 {
2533 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2534 $Elems/=$BasicSize;
2535 }
2536 }
2537 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002539 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002540}
2541
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002542sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002543{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002544 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002545 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002546 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2547 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002548 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002549 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2550 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2551 if(not $NodeType)
2552 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002553 return ();
2554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002555 if($NodeType eq "tree_vec")
2556 {
2557 if($Pos!=$#Positions)
2558 { # select last vector of parameters ( ns<P1>::type<P2> )
2559 next;
2560 }
2561 }
2562 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2563 foreach my $P (@Params)
2564 {
2565 if($P eq "") {
2566 return ();
2567 }
2568 elsif($P ne "\@skip\@") {
2569 @TmplParams = (@TmplParams, $P);
2570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002571 }
2572 }
2573 return @TmplParams;
2574}
2575
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002576sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002577{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002578 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002579 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002580 if(defined $TypeInfo{$Version}{$TypeId}
2581 and $TypeInfo{$Version}{$TypeId}{"Name"})
2582 { # already created
2583 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2586 { # incomplete type
2587 return ();
2588 }
2589 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2590
2591 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002592 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002593
2594 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2595 {
2596 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2597 {
2598 if($Info=~/qual[ ]*:/)
2599 {
2600 if(my $NID = ++$MAX_ID)
2601 {
2602 $MissedBase{$Version}{$TypeId}="$NID";
2603 $MissedBase_R{$Version}{$NID}=$TypeId;
2604 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2605 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2606 }
2607 }
2608 }
2609 $TypeAttr{"Type"} = "Typedef";
2610 }
2611 else {
2612 $TypeAttr{"Type"} = getTypeType($TypeId);
2613 }
2614
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002615 if($TypeAttr{"Type"} eq "Unknown") {
2616 return ();
2617 }
2618 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2619 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002620 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002621 if(my $TName = $TypeAttr{"Name"})
2622 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002623 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002624 $TName_Tid{$Version}{$TName} = $TypeId;
2625 return %TypeAttr;
2626 }
2627 else {
2628 return ();
2629 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002630 }
2631 elsif($TypeAttr{"Type"} eq "Array")
2632 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002633 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2634 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002635 return ();
2636 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002637 if(my $Algn = getAlgn($TypeId)) {
2638 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2639 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002640 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002641 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002643 if(not $BTAttr{"Name"}) {
2644 return ();
2645 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002646 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002647 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002648 if(my $Size = getSize($TypeId)) {
2649 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2650 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002651 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002652 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2653 }
2654 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002655 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002657 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002658 else
2659 {
2660 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002661 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002662 $TypeAttr{"Name"} = $1."[]".$2;
2663 }
2664 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002665 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002667 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002668 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002669 if($BTAttr{"Header"}) {
2670 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002673 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2674 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002675 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002676 return ();
2677 }
2678 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2679 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002680 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 if($TypeAttr{"Name"})
2682 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2684 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002685 { # NOTE: register only one int: with built-in decl
2686 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2687 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2688 }
2689 }
2690 return %TypeAttr;
2691 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002692 else {
2693 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002694 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002696 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002697 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002698 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2699 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002700 return ();
2701 }
2702 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002703 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002704 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002705 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002707 if($MissedTDid ne $TypeDeclId) {
2708 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 }
2711 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002712 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002713 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 return ();
2716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002717 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2720 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002721 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 }
2723 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002724 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002725 {
2726 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002727 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002728 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2731 }
2732 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002734 }
2735 }
2736 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
2739 if($TypeAttr{"Type"} eq "Typedef")
2740 {
2741 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002742 if(isAnon($TypeAttr{"Name"}))
2743 { # anon typedef to anon type: ._N
2744 return ();
2745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 if(my $NS = getNameSpace($TypeDeclId))
2747 {
2748 my $TypeName = $TypeAttr{"Name"};
2749 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2750 { # "some_type" is the typedef to "struct some_type" in C++
2751 if($3) {
2752 $TypeAttr{"Name"} = $3."::".$TypeName;
2753 }
2754 }
2755 else
2756 {
2757 $TypeAttr{"NameSpace"} = $NS;
2758 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002759
2760 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2761 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002763 if($BTAttr{"NameSpace"}
2764 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002765 { # types like "std::fpos<__mbstate_t>" are
2766 # not covered by typedefs in the TU dump
2767 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002768 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2769 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002770 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002771 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002772 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002773 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002775 }
2776 }
2777 }
2778 }
2779 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002780 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2781 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002783 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2784 { # typedef int*const TYPEDEF; // first
2785 # int foo(TYPEDEF p); // const is optimized out
2786 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2787 if($BTAttr{"Name"}=~/</)
2788 {
2789 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2790 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002792 }
2793 }
2794 }
2795 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2796 }
2797 if(not $TypeAttr{"Size"})
2798 {
2799 if($TypeAttr{"Type"} eq "Pointer") {
2800 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2801 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002802 elsif($BTAttr{"Size"}) {
2803 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002804 }
2805 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002806 if(my $Algn = getAlgn($TypeId)) {
2807 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2808 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002809 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002810 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2811 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002813 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002814 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 { # typedef to "class Class"
2816 # should not be registered in TName_Tid
2817 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2818 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002820 }
2821 return %TypeAttr;
2822 }
2823}
2824
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002825sub getTreeVec($)
2826{
2827 my %Vector = ();
2828 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2829 {
2830 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2831 { # string length is N-1 because of the null terminator
2832 $Vector{$1} = $2;
2833 }
2834 }
2835 return \%Vector;
2836}
2837
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002838sub get_TemplateParam($$)
2839{
2840 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002841 return () if(not $Type_Id);
2842 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2843 return () if(not $NodeType);
2844 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002845 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002846 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002847 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002848 my $Num = getNodeIntCst($Type_Id);
2849 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002850 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002851 }
2852 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002853 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002854 }
2855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002856 elsif($NodeType eq "string_cst") {
2857 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002859 elsif($NodeType eq "tree_vec")
2860 {
2861 my $Vector = getTreeVec($Type_Id);
2862 my @Params = ();
2863 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2864 {
2865 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2866 push(@Params, $P2);
2867 }
2868 }
2869 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 }
2871 else
2872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002873 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002874 my $PName = $ParamAttr{"Name"};
2875 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002876 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002878 if($PName=~/\>/)
2879 {
2880 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 $PName = $Cover;
2882 }
2883 }
2884 if($Pos>=1 and
2885 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2886 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2887 # template<typename _Key, typename _Compare = std::less<_Key>
2888 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2889 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2890 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2891 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002892 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 }
2896}
2897
2898sub cover_stdcxx_typedef($)
2899{
2900 my $TypeName = $_[0];
2901 if(my @Covers = sort {length($a)<=>length($b)}
2902 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2903 { # take the shortest typedef
2904 # FIXME: there may be more than
2905 # one typedefs to the same type
2906 return $Covers[0];
2907 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002908 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2910 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2911 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002912 if(my $Cover = $Covers[0])
2913 {
2914 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2915 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002917 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002918 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002919}
2920
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002921sub getNodeIntCst($)
2922{
2923 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002924 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 if($EnumMembName_Id{$Version}{$CstId}) {
2926 return $EnumMembName_Id{$Version}{$CstId};
2927 }
2928 elsif((my $Value = getTreeValue($CstId)) ne "")
2929 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002930 if($Value eq "0")
2931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002932 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933 return "false";
2934 }
2935 else {
2936 return "0";
2937 }
2938 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002939 elsif($Value eq "1")
2940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002941 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002942 return "true";
2943 }
2944 else {
2945 return "1";
2946 }
2947 }
2948 else {
2949 return $Value;
2950 }
2951 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002952 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002953}
2954
2955sub getNodeStrCst($)
2956{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002957 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2958 {
2959 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002960 {
2961 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2962 { # string length is N-1 because of the null terminator
2963 return substr($1, 0, $2-1);
2964 }
2965 else
2966 { # identifier_node
2967 return substr($1, 0, $2);
2968 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002972}
2973
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002974sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002975{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002976 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002977 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2978 if($Type eq "FieldPtr") {
2979 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2980 }
2981 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2982 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002983 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 if($Type eq "MethodPtr")
2985 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002986 if(my $Size = getSize($TypeId))
2987 {
2988 $Size/=$BYTE_SIZE;
2989 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002992 if(my $Algn = getAlgn($TypeId)) {
2993 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2994 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002995 # Return
2996 if($Type eq "FieldPtr")
2997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002998 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002999 if($ReturnAttr{"Name"}) {
3000 $MemPtrName .= $ReturnAttr{"Name"};
3001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003002 $TypeAttr{"Return"} = $PtrId;
3003 }
3004 else
3005 {
3006 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3007 {
3008 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003009 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3010 if(not $ReturnAttr{"Name"})
3011 { # templates
3012 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 $TypeAttr{"Return"} = $ReturnTypeId;
3016 }
3017 }
3018 # Class
3019 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3020 {
3021 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003022 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003023 if($Class{"Name"}) {
3024 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3025 }
3026 else {
3027 $MemPtrName .= " (*)";
3028 }
3029 }
3030 else {
3031 $MemPtrName .= " (*)";
3032 }
3033 # Parameters
3034 if($Type eq "FuncPtr"
3035 or $Type eq "MethodPtr")
3036 {
3037 my @ParamTypeName = ();
3038 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3039 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003040 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003041 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003042 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003043 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003044 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3045 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003046 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003047 my $PTypeId = $1;
3048 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003049 if(not $ParamAttr{"Name"})
3050 { # templates (template_type_parm), etc.
3051 return ();
3052 }
3053 if($ParamAttr{"Name"} eq "void") {
3054 last;
3055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003057 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003058 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003059 push(@ParamTypeName, $ParamAttr{"Name"});
3060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003061 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3062 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003063 }
3064 else {
3065 last;
3066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003067 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003068 else {
3069 last;
3070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003071 }
3072 }
3073 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3074 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003075 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 return %TypeAttr;
3077}
3078
3079sub getTreeTypeName($)
3080{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 my $TypeId = $_[0];
3082 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003084 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003086 if(my $Name = getNameByInfo($TypeId))
3087 { # bit_size_type
3088 return $Name;
3089 }
3090 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 return "unsigned int";
3092 }
3093 else {
3094 return "int";
3095 }
3096 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3098 {
3099 return getNameByInfo($1);
3100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003101 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003102 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003103}
3104
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003105sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003107 my $Ptd = pointTo($_[0]);
3108 return 0 if(not $Ptd);
3109 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003111 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3112 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003113 }
3114 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003115 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3116 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003118 if($InfoT1 eq "pointer_type"
3119 and $InfoT2 eq "function_type") {
3120 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003121 }
3122 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003123 return 0;
3124}
3125
3126sub isMethodPtr($)
3127{
3128 my $Ptd = pointTo($_[0]);
3129 return 0 if(not $Ptd);
3130 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3131 {
3132 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3133 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3134 and $Info=~/ ptrmem /) {
3135 return 1;
3136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 return 0;
3139}
3140
3141sub isFieldPtr($)
3142{
3143 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3144 {
3145 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3146 and $Info=~/ ptrmem /) {
3147 return 1;
3148 }
3149 }
3150 return 0;
3151}
3152
3153sub pointTo($)
3154{
3155 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3156 {
3157 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3158 return $1;
3159 }
3160 }
3161 return "";
3162}
3163
3164sub getTypeTypeByTypeId($)
3165{
3166 my $TypeId = $_[0];
3167 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3168 {
3169 my $NType = $NodeType{$TType};
3170 if($NType eq "Intrinsic") {
3171 return $NType;
3172 }
3173 elsif(isFuncPtr($TypeId)) {
3174 return "FuncPtr";
3175 }
3176 elsif(isMethodPtr($TypeId)) {
3177 return "MethodPtr";
3178 }
3179 elsif(isFieldPtr($TypeId)) {
3180 return "FieldPtr";
3181 }
3182 elsif($NType ne "Other") {
3183 return $NType;
3184 }
3185 }
3186 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003187}
3188
3189sub getQual($)
3190{
3191 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003192 my %UnQual = (
3193 "r"=>"restrict",
3194 "v"=>"volatile",
3195 "c"=>"const",
3196 "cv"=>"const volatile"
3197 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003198 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3199 {
3200 my ($Qual, $To) = ();
3201 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3202 $Qual = $UnQual{$1};
3203 }
3204 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3205 $To = $1;
3206 }
3207 if($Qual and $To) {
3208 return ($Qual, $To);
3209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003210 }
3211 return ();
3212}
3213
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003214sub getQualType($)
3215{
3216 if($_[0] eq "const volatile") {
3217 return "ConstVolatile";
3218 }
3219 return ucfirst($_[0]);
3220}
3221
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003222sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003223{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003224 my $TypeId = $_[0];
3225 my $TypeDeclId = getTypeDeclId($TypeId);
3226 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003227 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003228 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3229 return "Typedef";
3230 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003231 }
3232 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3233 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003234 if(($Qual or $To) and $TypeDeclId
3235 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003236 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003237 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003239 elsif(not $MissedBase_R{$Version}{$TypeId}
3240 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003241 return "Typedef";
3242 }
3243 elsif($Qual)
3244 { # qualified types
3245 return getQualType($Qual);
3246 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003247
3248 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3249 { # typedef struct { ... } name
3250 $TypeTypedef{$Version}{$TypeId} = $1;
3251 }
3252
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003253 my $TypeType = getTypeTypeByTypeId($TypeId);
3254 if($TypeType eq "Struct")
3255 {
3256 if($TypeDeclId
3257 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3258 return "Template";
3259 }
3260 }
3261 return $TypeType;
3262}
3263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003264sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003266 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3267 {
3268 my $TDid = getTypeDeclId($_[0]);
3269 if(getNameByInfo($TDid)
3270 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3271 and getTypeId($TDid) eq $_[0]) {
3272 return $1;
3273 }
3274 }
3275 return 0;
3276}
3277
3278sub selectBaseType($)
3279{
3280 my $TypeId = $_[0];
3281 if(defined $MissedTypedef{$Version}{$TypeId})
3282 { # add missed typedefs
3283 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3284 return ($TypeId, "");
3285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003286 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003287 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3288 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003289
3290 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3291 my $MB = $MissedBase{$Version}{$TypeId};
3292
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003293 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003294 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003295 and (getTypeId($1) ne $TypeId)
3296 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003297 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003298 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003300 elsif($MB)
3301 { # add base
3302 return ($MB, "");
3303 }
3304 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003305 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003306 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003307 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003308 elsif($Qual or $To)
3309 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003310 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003311 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003312 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003313 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003314 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003315 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003316 }
3317 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003318 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003319 }
3320 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003321 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003323 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 }
3326 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003327 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328 }
3329 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003330 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003331 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003332 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003333 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003334 }
3335 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003337 }
3338 }
3339 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003340 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003341 }
3342}
3343
3344sub getSymbolInfo_All()
3345{
3346 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3347 { # reverse order
3348 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003350 }
3351 }
3352}
3353
3354sub getVarInfo_All()
3355{
3356 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3357 { # reverse order
3358 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003359 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003360 }
3361 }
3362}
3363
3364sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003365 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366}
3367
3368sub getVarInfo($)
3369{
3370 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003371 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003372 {
3373 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3374 if($NSInfoType and $NSInfoType eq "function_decl") {
3375 return;
3376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003377 }
3378 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3379 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3380 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3381 delete($SymbolInfo{$Version}{$InfoId});
3382 return;
3383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003385 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003386 delete($SymbolInfo{$Version}{$InfoId});
3387 return;
3388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003389 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3390 delete($SymbolInfo{$Version}{$InfoId});
3391 return;
3392 }
3393 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003394 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3395 {
3396 if($OSgroup eq "windows")
3397 { # cut the offset
3398 $MnglName=~s/\@\d+\Z//g;
3399 }
3400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003402 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003403 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003404 { # validate mangled name
3405 delete($SymbolInfo{$Version}{$InfoId});
3406 return;
3407 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003408 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003409 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003410 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003411 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003412 }
3413 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3414 { # non-public global data
3415 delete($SymbolInfo{$Version}{$InfoId});
3416 return;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003421 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003422 { # typename_type
3423 delete($SymbolInfo{$Version}{$InfoId});
3424 return;
3425 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003426 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3427 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003428 if(defined $Val) {
3429 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003431 }
3432 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003433 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3434 {
3435 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3436 { # templates
3437 delete($SymbolInfo{$Version}{$InfoId});
3438 return;
3439 }
3440 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003441 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3442 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003444 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003446 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003448 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003449 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003450 if(not $CheckHeadersOnly)
3451 {
3452 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3453 {
3454 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3455 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3456 {
3457 if(link_symbol($ShortName, $Version, "-Deps"))
3458 { # "const" global data is mangled as _ZL... in the TU dump
3459 # but not mangled when compiling a C shared library
3460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3461 }
3462 }
3463 }
3464 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003465 if($COMMON_LANGUAGE{$Version} eq "C++")
3466 {
3467 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3468 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003469 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003470 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3471 }
3472 }
3473 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3474 { # try to mangle symbol (link with libraries)
3475 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3476 }
3477 if($OStarget eq "windows")
3478 {
3479 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3480 { # link MS C++ symbols from library with GCC symbols from headers
3481 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3482 }
3483 }
3484 }
3485 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3486 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3487 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003488 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3489 {
3490 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3491 { # non-target symbols
3492 delete($SymbolInfo{$Version}{$InfoId});
3493 return;
3494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003495 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003496 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3497 {
3498 if(defined $MissedTypedef{$Version}{$Rid})
3499 {
3500 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3501 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3502 }
3503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003504 }
3505 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003506 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3508 }
3509 if($ShortName=~/\A(_Z|\?)/) {
3510 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3511 }
3512}
3513
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003514sub isConstType($$)
3515{
3516 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003517 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003518 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003519 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003520 }
3521 return ($Base{"Type"} eq "Const");
3522}
3523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003524sub getTrivialName($$)
3525{
3526 my ($TypeInfoId, $TypeId) = @_;
3527 my %TypeAttr = ();
3528 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3529 if(not $TypeAttr{"Name"}) {
3530 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3531 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003532 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003534 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003535 if(isAnon($TypeAttr{"Name"}))
3536 {
3537 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003538 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003539 { # searching for a first not anon scope
3540 if($NSId eq $NameSpaceId) {
3541 last;
3542 }
3543 else
3544 {
3545 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3546 if(not $TypeAttr{"NameSpace"}
3547 or isNotAnon($TypeAttr{"NameSpace"})) {
3548 last;
3549 }
3550 }
3551 $NameSpaceId=$NSId;
3552 }
3553 }
3554 else
3555 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003556 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003557 {
3558 if($NameSpaceId ne $TypeId) {
3559 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003561 }
3562 }
3563 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3564 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3565 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003566 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003567 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003568 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003569 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003570 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003571 if($TypeAttr{"NameSpace"}) {
3572 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003574 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003575 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3576 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003578 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003579 if(not @TParams)
3580 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581 return ("", "");
3582 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003583 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584 }
3585 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3586}
3587
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003588sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003589{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003590 my $TypeId = $_[0];
3591 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003592
3593 if($TemplateDecl{$Version}{$TypeId})
3594 { # template_decl
3595 return ();
3596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003597 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3598 {
3599 if($TemplateDecl{$Version}{$ScopeId})
3600 { # template_decl
3601 return ();
3602 }
3603 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 my %TypeAttr = ();
3606 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3607 return ();
3608 }
3609 setTypeAccess($TypeId, \%TypeAttr);
3610 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3611 if(isBuiltIn($TypeAttr{"Header"}))
3612 {
3613 delete($TypeAttr{"Header"});
3614 delete($TypeAttr{"Line"});
3615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003616 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003617 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3618 if(not $TypeAttr{"Name"}) {
3619 return ();
3620 }
3621 if(not $TypeAttr{"NameSpace"}) {
3622 delete($TypeAttr{"NameSpace"});
3623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003624 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003625 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003626 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003627 {
3628 foreach my $Pos (0 .. $#TParams) {
3629 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3630 }
3631 }
3632 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003633 if(my $Size = getSize($TypeId))
3634 {
3635 $Size = $Size/$BYTE_SIZE;
3636 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003637 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003638 else
3639 { # declaration only
3640 $TypeAttr{"Forward"} = 1;
3641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003642 if($TypeAttr{"Type"} eq "Struct"
3643 and detect_lang($TypeId))
3644 {
3645 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003646 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 }
3648 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003649 or $TypeAttr{"Type"} eq "Class")
3650 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003651 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003652 if($Skip) {
3653 return ();
3654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003655 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003656 if(my $Algn = getAlgn($TypeId)) {
3657 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003659 setSpec($TypeId, \%TypeAttr);
3660 setTypeMemb($TypeId, \%TypeAttr);
3661 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003662 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3663 {
3664 my @Entries = split(/\n/, $VTable);
3665 foreach (1 .. $#Entries)
3666 {
3667 my $Entry = $Entries[$_];
3668 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3669 $TypeAttr{"VTable"}{$1} = $2;
3670 }
3671 }
3672 }
3673 return %TypeAttr;
3674}
3675
3676sub detect_lang($)
3677{
3678 my $TypeId = $_[0];
3679 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003680 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003681 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003682 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3683 }
3684 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003685 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003686 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003687 while($Fncs)
3688 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003689 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003690 return 1;
3691 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003692 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003693 }
3694 }
3695 return 0;
3696}
3697
3698sub setSpec($$)
3699{
3700 my ($TypeId, $TypeAttr) = @_;
3701 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3702 if($Info=~/\s+spec\s+/) {
3703 $TypeAttr->{"Spec"} = 1;
3704 }
3705}
3706
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003707sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003708{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003709 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003710 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3711 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3712 {
3713 $Info = $LibInfo{$Version}{"info"}{$1};
3714 my $Pos = 0;
3715 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3716 {
3717 my ($Access, $BInfoId) = ($1, $2);
3718 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003719 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3720 if(not $CType or $CType eq "template_type_parm"
3721 or $CType eq "typename_type")
3722 { # skip
3723 return 1;
3724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003725 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3726 if($Access=~/prot/)
3727 {
3728 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3729 }
3730 elsif($Access=~/priv/)
3731 {
3732 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3733 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003734 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003735 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003736 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003737 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3738 }
3739 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003740 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003741 }
3742 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003743 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003744}
3745
3746sub getBinfClassId($)
3747{
3748 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3749 $Info=~/type[ ]*:[ ]*@(\d+) /;
3750 return $1;
3751}
3752
3753sub unmangledFormat($$)
3754{
3755 my ($Name, $LibVersion) = @_;
3756 $Name = uncover_typedefs($Name, $LibVersion);
3757 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3758 $Name=~s/\(\w+\)(\d)/$1/;
3759 return $Name;
3760}
3761
3762sub modelUnmangled($$)
3763{
3764 my ($InfoId, $Compiler) = @_;
3765 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3766 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3767 }
3768 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3769 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3770 $PureSignature = "~".$PureSignature;
3771 }
3772 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3773 {
3774 my (@Params, @ParamTypes) = ();
3775 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3776 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3777 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3778 }
3779 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3780 { # checking parameters
3781 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003782 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003783 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003784 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003785 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003786 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003787 }
3788 @ParamTypes = (@ParamTypes, $PTName);
3789 }
3790 if(@ParamTypes) {
3791 $PureSignature .= "(".join(", ", @ParamTypes).")";
3792 }
3793 else
3794 {
3795 if($Compiler eq "MSVC")
3796 {
3797 $PureSignature .= "(void)";
3798 }
3799 else
3800 { # GCC
3801 $PureSignature .= "()";
3802 }
3803 }
3804 $PureSignature = delete_keywords($PureSignature);
3805 }
3806 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003808 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 $PureSignature = $ClassName."::".$PureSignature;
3810 }
3811 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3812 $PureSignature = $NS."::".$PureSignature;
3813 }
3814 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3815 $PureSignature .= " const";
3816 }
3817 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3818 $PureSignature .= " volatile";
3819 }
3820 my $ShowReturn = 0;
3821 if($Compiler eq "MSVC"
3822 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3823 {
3824 $ShowReturn=1;
3825 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003826 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3827 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003828 {
3829 $ShowReturn=1;
3830 }
3831 if($ShowReturn)
3832 { # mangled names for template function specializations include return value
3833 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3834 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003835 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003836 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3837 $PureSignature = $ReturnName." ".$PureSignature;
3838 }
3839 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003840 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003841}
3842
3843sub mangle_symbol($$$)
3844{ # mangling for simple methods
3845 # see gcc-4.6.0/gcc/cp/mangle.c
3846 my ($InfoId, $LibVersion, $Compiler) = @_;
3847 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3848 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3849 }
3850 my $Mangled = "";
3851 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003852 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003853 }
3854 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003855 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003856 }
3857 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3858}
3859
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003860sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003861{
3862 my ($InfoId, $LibVersion) = @_;
3863 return "";
3864}
3865
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003866sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003867{ # see gcc-4.6.0/gcc/cp/mangle.c
3868 my ($InfoId, $LibVersion) = @_;
3869 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003870 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003871 my %Repl = ();# SN_ replacements
3872 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3873 {
3874 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3875 if($MangledClass!~/\AN/) {
3876 $MangledClass = "N".$MangledClass;
3877 }
3878 else {
3879 $MangledClass=~s/E\Z//;
3880 }
3881 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3882 $MangledClass=~s/\AN/NV/;
3883 }
3884 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3885 $MangledClass=~s/\AN/NK/;
3886 }
3887 $Mangled .= $MangledClass;
3888 }
3889 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3890 { # mangled by name due to the absence of structured info
3891 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3892 if($MangledNS!~/\AN/) {
3893 $MangledNS = "N".$MangledNS;
3894 }
3895 else {
3896 $MangledNS=~s/E\Z//;
3897 }
3898 $Mangled .= $MangledNS;
3899 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003900 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003901 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003902 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003903 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003904 foreach (@TPos) {
3905 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3906 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003907 }
3908 elsif($TmplParams)
3909 { # remangling mode
3910 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003911 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003912 }
3913 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3914 $Mangled .= "C1";
3915 }
3916 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3917 $Mangled .= "D0";
3918 }
3919 elsif($ShortName)
3920 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003921 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3922 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003923 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003924 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003925 { # "const" global data is mangled as _ZL...
3926 $Mangled .= "L";
3927 }
3928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003929 if($ShortName=~/\Aoperator(\W.*)\Z/)
3930 {
3931 my $Op = $1;
3932 $Op=~s/\A[ ]+//g;
3933 if(my $OpMngl = $OperatorMangling{$Op}) {
3934 $Mangled .= $OpMngl;
3935 }
3936 else { # conversion operator
3937 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3938 }
3939 }
3940 else {
3941 $Mangled .= length($ShortName).$ShortName;
3942 }
3943 if(@TParams)
3944 { # templates
3945 $Mangled .= "I";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003946 my $FP = $TParams[0];
3947 foreach my $TPos (0 .. $#TParams)
3948 {
3949 my $TParam = $TParams[$TPos];
3950 if($TPos>=1)
3951 {
3952 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FP\E>\Z/)
3953 { # default allocators are not mangled
3954 next;
3955 }
3956 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003957 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3958 }
3959 $Mangled .= "E";
3960 }
3961 if(not $ClassId and @TParams) {
3962 add_substitution($ShortName, \%Repl, 0);
3963 }
3964 }
3965 if($ClassId or $NameSpace) {
3966 $Mangled .= "E";
3967 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003968 if(@TParams)
3969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003970 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003971 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3972 }
3973 }
3974 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3975 {
3976 my @Params = ();
3977 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3978 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3979 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3980 }
3981 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3982 { # checking parameters
3983 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3984 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3985 }
3986 if(not @Params) {
3987 $Mangled .= "v";
3988 }
3989 }
3990 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3991 $Mangled = write_stdcxx_substitution($Mangled);
3992 if($Mangled eq "_Z") {
3993 return "";
3994 }
3995 return $Mangled;
3996}
3997
3998sub correct_incharge($$$)
3999{
4000 my ($InfoId, $LibVersion, $Mangled) = @_;
4001 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4002 {
4003 if($MangledNames{$LibVersion}{$Mangled}) {
4004 $Mangled=~s/C1E/C2E/;
4005 }
4006 }
4007 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4008 {
4009 if($MangledNames{$LibVersion}{$Mangled}) {
4010 $Mangled=~s/D0E/D1E/;
4011 }
4012 if($MangledNames{$LibVersion}{$Mangled}) {
4013 $Mangled=~s/D1E/D2E/;
4014 }
4015 }
4016 return $Mangled;
4017}
4018
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004019sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004020{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004021 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004022 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004023 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004024 return $Name;
4025 }
4026 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004027 while(my $CPos = find_center($TParams, "<"))
4028 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004029 $TParams = substr($TParams, $CPos);
4030 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004031 if($TParams=~s/\A<(.+)>\Z/$1/) {
4032 $Name=~s/<\Q$TParams\E>\Z//;
4033 }
4034 else
4035 { # error
4036 $TParams = "";
4037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004038 return ($Name, $TParams);
4039}
4040
4041sub get_sub_ns($)
4042{
4043 my $Name = $_[0];
4044 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004045 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004046 {
4047 push(@NS, substr($Name, 0, $CPos));
4048 $Name = substr($Name, $CPos);
4049 $Name=~s/\A:://;
4050 }
4051 return (join("::", @NS), $Name);
4052}
4053
4054sub mangle_ns($$$)
4055{
4056 my ($Name, $LibVersion, $Repl) = @_;
4057 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4058 {
4059 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4060 $Mangled=~s/\AN(.+)E\Z/$1/;
4061 return $Mangled;
4062
4063 }
4064 else
4065 {
4066 my ($MangledNS, $SubNS) = ("", "");
4067 ($SubNS, $Name) = get_sub_ns($Name);
4068 if($SubNS) {
4069 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4070 }
4071 $MangledNS .= length($Name).$Name;
4072 add_substitution($MangledNS, $Repl, 0);
4073 return $MangledNS;
4074 }
4075}
4076
4077sub mangle_param($$$)
4078{
4079 my ($PTid, $LibVersion, $Repl) = @_;
4080 my ($MPrefix, $Mangled) = ("", "");
4081 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004082 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004083 my $BaseType_Name = $BaseType{"Name"};
4084 if(not $BaseType_Name) {
4085 return "";
4086 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004087 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004088 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004089 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4090 while($Suffix=~/(&|\*|const)\Z/)
4091 {
4092 if($Suffix=~s/[ ]*&\Z//) {
4093 $MPrefix .= "R";
4094 }
4095 if($Suffix=~s/[ ]*\*\Z//) {
4096 $MPrefix .= "P";
4097 }
4098 if($Suffix=~s/[ ]*const\Z//)
4099 {
4100 if($MPrefix=~/R|P/
4101 or $Suffix=~/&|\*/) {
4102 $MPrefix .= "K";
4103 }
4104 }
4105 if($Suffix=~s/[ ]*volatile\Z//) {
4106 $MPrefix .= "V";
4107 }
4108 #if($Suffix=~s/[ ]*restrict\Z//) {
4109 #$MPrefix .= "r";
4110 #}
4111 }
4112 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4113 $Mangled .= $Token;
4114 }
4115 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4116 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004117 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004118 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004119 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004120 foreach (@TPos) {
4121 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4122 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004123 }
4124 elsif($TmplParams)
4125 { # remangling mode
4126 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004127 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004128 }
4129 my $MangledNS = "";
4130 my ($SubNS, $SName) = get_sub_ns($ShortName);
4131 if($SubNS) {
4132 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4133 }
4134 $MangledNS .= length($SName).$SName;
4135 if(@TParams) {
4136 add_substitution($MangledNS, $Repl, 0);
4137 }
4138 $Mangled .= "N".$MangledNS;
4139 if(@TParams)
4140 { # templates
4141 $Mangled .= "I";
4142 foreach my $TParam (@TParams) {
4143 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4144 }
4145 $Mangled .= "E";
4146 }
4147 $Mangled .= "E";
4148 }
4149 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4150 {
4151 if($BaseType{"Type"} eq "MethodPtr") {
4152 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4153 }
4154 else {
4155 $Mangled .= "PF";
4156 }
4157 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4158 my @Params = keys(%{$BaseType{"Param"}});
4159 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4160 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4161 }
4162 if(not @Params) {
4163 $Mangled .= "v";
4164 }
4165 $Mangled .= "E";
4166 }
4167 elsif($BaseType{"Type"} eq "FieldPtr")
4168 {
4169 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4170 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4171 }
4172 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4173 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4174 {
4175 if($Mangled eq $Optimized)
4176 {
4177 if($ShortName!~/::/)
4178 { # remove "N ... E"
4179 if($MPrefix) {
4180 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4181 }
4182 else {
4183 $Mangled=~s/\AN(.+)E\Z/$1/g;
4184 }
4185 }
4186 }
4187 else {
4188 $Mangled = $Optimized;
4189 }
4190 }
4191 add_substitution($Mangled, $Repl, 1);
4192 return $Mangled;
4193}
4194
4195sub mangle_template_param($$$)
4196{ # types + literals
4197 my ($TParam, $LibVersion, $Repl) = @_;
4198 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4199 return mangle_param($TPTid, $LibVersion, $Repl);
4200 }
4201 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4202 { # class_name<1u>::method(...)
4203 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4204 }
4205 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4206 { # class_name<(signed char)1>::method(...)
4207 return "L".$IntrinsicMangling{$1}.$2."E";
4208 }
4209 elsif($TParam eq "true")
4210 { # class_name<true>::method(...)
4211 return "Lb1E";
4212 }
4213 elsif($TParam eq "false")
4214 { # class_name<true>::method(...)
4215 return "Lb0E";
4216 }
4217 else { # internal error
4218 return length($TParam).$TParam;
4219 }
4220}
4221
4222sub add_substitution($$$)
4223{
4224 my ($Value, $Repl, $Rec) = @_;
4225 if($Rec)
4226 { # subtypes
4227 my @Subs = ($Value);
4228 while($Value=~s/\A(R|P|K)//) {
4229 push(@Subs, $Value);
4230 }
4231 foreach (reverse(@Subs)) {
4232 add_substitution($_, $Repl, 0);
4233 }
4234 return;
4235 }
4236 return if($Value=~/\AS(\d*)_\Z/);
4237 $Value=~s/\AN(.+)E\Z/$1/g;
4238 return if(defined $Repl->{$Value});
4239 return if(length($Value)<=1);
4240 return if($StdcxxMangling{$Value});
4241 # check for duplicates
4242 my $Base = $Value;
4243 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4244 {
4245 my $Num = $Repl->{$Type};
4246 my $Replace = macro_mangle($Num);
4247 $Base=~s/\Q$Replace\E/$Type/;
4248 }
4249 if(my $OldNum = $Repl->{$Base})
4250 {
4251 $Repl->{$Value} = $OldNum;
4252 return;
4253 }
4254 my @Repls = sort {$b<=>$a} values(%{$Repl});
4255 if(@Repls) {
4256 $Repl->{$Value} = $Repls[0]+1;
4257 }
4258 else {
4259 $Repl->{$Value} = -1;
4260 }
4261 # register duplicates
4262 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004263 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004264 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4265 {
4266 next if($Base eq $Type);
4267 my $Num = $Repl->{$Type};
4268 my $Replace = macro_mangle($Num);
4269 $Base=~s/\Q$Type\E/$Replace/;
4270 $Repl->{$Base} = $Repl->{$Value};
4271 }
4272}
4273
4274sub macro_mangle($)
4275{
4276 my $Num = $_[0];
4277 if($Num==-1) {
4278 return "S_";
4279 }
4280 else
4281 {
4282 my $Code = "";
4283 if($Num<10)
4284 { # S0_, S1_, S2_, ...
4285 $Code = $Num;
4286 }
4287 elsif($Num>=10 and $Num<=35)
4288 { # SA_, SB_, SC_, ...
4289 $Code = chr(55+$Num);
4290 }
4291 else
4292 { # S10_, S11_, S12_
4293 $Code = $Num-26; # 26 is length of english alphabet
4294 }
4295 return "S".$Code."_";
4296 }
4297}
4298
4299sub write_stdcxx_substitution($)
4300{
4301 my $Mangled = $_[0];
4302 if($StdcxxMangling{$Mangled}) {
4303 return $StdcxxMangling{$Mangled};
4304 }
4305 else
4306 {
4307 my @Repls = keys(%StdcxxMangling);
4308 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4309 foreach my $MangledType (@Repls)
4310 {
4311 my $Replace = $StdcxxMangling{$MangledType};
4312 #if($Mangled!~/$Replace/) {
4313 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4314 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4315 #}
4316 }
4317 }
4318 return $Mangled;
4319}
4320
4321sub write_substitution($$)
4322{
4323 my ($Mangled, $Repl) = @_;
4324 if(defined $Repl->{$Mangled}
4325 and my $MnglNum = $Repl->{$Mangled}) {
4326 $Mangled = macro_mangle($MnglNum);
4327 }
4328 else
4329 {
4330 my @Repls = keys(%{$Repl});
4331 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4332 # FIXME: how to apply replacements? by num or by pos
4333 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4334 foreach my $MangledType (@Repls)
4335 {
4336 my $Replace = macro_mangle($Repl->{$MangledType});
4337 if($Mangled!~/$Replace/) {
4338 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4339 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4340 }
4341 }
4342 }
4343 return $Mangled;
4344}
4345
4346sub delete_keywords($)
4347{
4348 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004349 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 return $TypeName;
4351}
4352
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353sub uncover_typedefs($$)
4354{
4355 my ($TypeName, $LibVersion) = @_;
4356 return "" if(not $TypeName);
4357 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4358 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4359 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004360 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004361 while($TypeName_New ne $TypeName_Pre)
4362 {
4363 $TypeName_Pre = $TypeName_New;
4364 my $TypeName_Copy = $TypeName_New;
4365 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004366 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004368 if(not $Intrinsic_Keywords{$1}) {
4369 $Words{$1} = 1;
4370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 }
4372 foreach my $Word (keys(%Words))
4373 {
4374 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4375 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004376 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004377 if($BaseType_Name=~/\([\*]+\)/)
4378 { # FuncPtr
4379 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4380 {
4381 my $Type_Suffix = $1;
4382 $TypeName_New = $BaseType_Name;
4383 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004384 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004385 }
4386 }
4387 }
4388 else
4389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004390 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004391 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004392 }
4393 }
4394 }
4395 }
4396 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4397}
4398
4399sub isInternal($)
4400{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004401 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4402 {
4403 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4404 {
4405 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4406 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4407 return 1;
4408 }
4409 }
4410 }
4411 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004412}
4413
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004414sub getDataVal($$)
4415{
4416 my ($InfoId, $TypeId) = @_;
4417 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4418 {
4419 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4420 {
4421 if(defined $LibInfo{$Version}{"info_type"}{$1}
4422 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4423 { # char const* data = "str"
4424 # NOTE: disabled
4425 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4426 {
4427 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4428 {
4429 if(defined $LibInfo{$Version}{"info_type"}{$1}
4430 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4431 {
4432 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4433 {
4434 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4435 {
4436 return getInitVal($1, $TypeId);
4437 }
4438 }
4439 }
4440 }
4441 }
4442 }
4443 else {
4444 return getInitVal($1, $TypeId);
4445 }
4446 }
4447 }
4448 return undef;
4449}
4450
4451sub getInitVal($$)
4452{
4453 my ($InfoId, $TypeId) = @_;
4454 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4455 {
4456 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4457 {
4458 if($InfoType eq "integer_cst")
4459 {
4460 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004461 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004462 { # characters
4463 $Val = chr($Val);
4464 }
4465 return $Val;
4466 }
4467 elsif($InfoType eq "string_cst") {
4468 return getNodeStrCst($InfoId);
4469 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004470 elsif($InfoType eq "var_decl")
4471 {
4472 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4473 return $Name;
4474 }
4475 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004476 }
4477 }
4478 return undef;
4479}
4480
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004481sub set_Class_And_Namespace($)
4482{
4483 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004484 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004485 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004486 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004487 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004488 my $NSInfoId = $1;
4489 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4490 {
4491 if($InfoType eq "namespace_decl") {
4492 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4493 }
4494 elsif($InfoType eq "record_type") {
4495 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4496 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004497 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004498 }
4499 }
4500 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4501 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4502 { # identify language
4503 setLanguage($Version, "C++");
4504 }
4505}
4506
4507sub debugType($$)
4508{
4509 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004510 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004511 printMsg("INFO", Dumper(\%Type));
4512}
4513
4514sub debugMangling($)
4515{
4516 my $LibVersion = $_[0];
4517 my %Mangled = ();
4518 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4519 {
4520 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4521 {
4522 if($Mngl=~/\A(_Z|\?)/) {
4523 $Mangled{$Mngl}=$InfoId;
4524 }
4525 }
4526 }
4527 translateSymbols(keys(%Mangled), $LibVersion);
4528 foreach my $Mngl (keys(%Mangled))
4529 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004530 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4531 my $U2 = $tr_name{$Mngl};
4532 if($U1 ne $U2) {
4533 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004534 }
4535 }
4536}
4537
4538sub linkSymbol($)
4539{ # link symbols from shared libraries
4540 # with the symbols from header files
4541 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004542 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004543 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4544 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4546 # 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 +04004547 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004548 {
4549 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4550 return correct_incharge($InfoId, $Version, $Mangled);
4551 }
4552 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004553 if($CheckHeadersOnly
4554 or not $BinaryOnly)
4555 { # 1. --headers-only mode
4556 # 2. not mangled src-only symbols
4557 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4558 return $Mangled;
4559 }
4560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004561 }
4562 return "";
4563}
4564
4565sub setLanguage($$)
4566{
4567 my ($LibVersion, $Lang) = @_;
4568 if(not $UserLang) {
4569 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4570 }
4571}
4572
4573sub getSymbolInfo($)
4574{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004575 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004576 if(isInternal($InfoId)) {
4577 return;
4578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004579 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4580 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004581 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4582 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004583 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004584 return;
4585 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004586 setFuncAccess($InfoId);
4587 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004588 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004590 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004591 return;
4592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004593 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004594 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4595 {
4596 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4597 { # templates
4598 delete($SymbolInfo{$Version}{$InfoId});
4599 return;
4600 }
4601 }
4602 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4603 {
4604 if(defined $MissedTypedef{$Version}{$Rid})
4605 {
4606 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4607 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4608 }
4609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004611 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4612 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004614 my $Orig = getFuncOrig($InfoId);
4615 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4616 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4617 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004618 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004619 return;
4620 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004621
4622 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004623 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004624 my @TParams = getTParams($Orig, "Func");
4625 if(not @TParams)
4626 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004627 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004628 return;
4629 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004630 foreach my $Pos (0 .. $#TParams) {
4631 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004633 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004634 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4635 { # operator<< <T>, operator>> <T>
4636 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004638 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004639 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004640 }
4641 else
4642 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004643 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004645 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4646 {
4647 if($OSgroup eq "windows")
4648 { # cut the offset
4649 $MnglName=~s/\@\d+\Z//g;
4650 }
4651 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4652
4653 # NOTE: mangling of some symbols may change depending on GCC version
4654 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4655 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4656 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004657
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004658 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004659 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004661 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004662 return;
4663 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004664 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004665 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004666 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004667 if($Skip)
4668 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004669 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004670 return;
4671 }
4672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004673 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4675 {
4676 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4677 { # templates
4678 delete($SymbolInfo{$Version}{$InfoId});
4679 return;
4680 }
4681 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004682 if(not $CheckHeadersOnly)
4683 {
4684 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4685 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4686 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4687 { # functions (C++): not mangled in library, but are mangled in TU dump
4688 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4689 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4690 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4691 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 }
4693 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004694 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4695 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004696 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004697 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004698 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004699 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004700 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004701 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004702 }
4703 if($COMMON_LANGUAGE{$Version} eq "C++")
4704 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004705 # C++ or --headers-only mode
4706 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004708 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4709 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004711 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004713 if(my $Mangled = linkSymbol($InfoId)) {
4714 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004715 }
4716 }
4717 if($OStarget eq "windows")
4718 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004719 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004721 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004723 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004725 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004726 }
4727 }
4728 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004729 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004730 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004731 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 return;
4733 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004734 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004735 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004736 { # identify virtual and pure virtual functions
4737 # NOTE: constructors cannot be virtual
4738 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4739 # in the TU dump, so taking it from the original symbol
4740 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4741 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4742 { # NOTE: D2 destructors are not present in a v-table
4743 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4744 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004746 if(isInline($InfoId)) {
4747 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004748 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004749 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4750 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4751 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004752 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4753 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004755 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004756 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004758 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004759 }
4760 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004761 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4762 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004763 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4764 { # non-target symbols
4765 delete($SymbolInfo{$Version}{$InfoId});
4766 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004767 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004769 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4770 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4771 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4772 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004773 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004774 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4775 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004776 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004777 return;
4778 }
4779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004780 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004781 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004782 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004783 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004784 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004785 return;
4786 }
4787 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789 }
4790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004791 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4792 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4793 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004794 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004795 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4796 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004797 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004798 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004799 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004800 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004801 }
4802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004803 if(getFuncLink($InfoId) eq "Static") {
4804 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004805 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004806 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4807 {
4808 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4809 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004810 if($Unmangled=~/\.\_\d/)
4811 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004812 delete($SymbolInfo{$Version}{$InfoId});
4813 return;
4814 }
4815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004816 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004817 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4818 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4819 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004821 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4822 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004823 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004824
4825 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4826 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4827 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828}
4829
4830sub isInline($)
4831{ # "body: undefined" in the tree
4832 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004833 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4834 {
4835 if($Info=~/ undefined /i) {
4836 return 0;
4837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004838 }
4839 return 1;
4840}
4841
4842sub getTypeId($)
4843{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004844 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4845 {
4846 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4847 return $1;
4848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004849 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004850 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004851}
4852
4853sub setTypeMemb($$)
4854{
4855 my ($TypeId, $TypeAttr) = @_;
4856 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004857 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004858 if($TypeType eq "Enum")
4859 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004860 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004861 while($TypeMembInfoId)
4862 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004863 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004864 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4865 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4866 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4867 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004868 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 }
4870 }
4871 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004873 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004874 while($TypeMembInfoId)
4875 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004876 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004877 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004878 if(not $IType or $IType ne "field_decl")
4879 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004880 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004881 next;
4882 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004883 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4884 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004885 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004886 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004887 next;
4888 }
4889 if(not $StructMembName)
4890 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004891 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004892 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004893 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004894 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4895 if(isAnon($UnnamedTName))
4896 { # rename unnamed fields to unnamed0, unnamed1, ...
4897 $StructMembName = "unnamed".($UnnamedPos++);
4898 }
4899 }
4900 }
4901 if(not $StructMembName)
4902 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004903 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004904 next;
4905 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004906 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4907 if(defined $MissedTypedef{$Version}{$MembTypeId})
4908 {
4909 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4910 $MembTypeId = $AddedTid;
4911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004912 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004913 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4914 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004915 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004916 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004917 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4918 }
4919 if($MInfo=~/spec:\s*mutable /)
4920 { # mutable fields
4921 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004922 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004923 if(my $Algn = getAlgn($TypeMembInfoId)) {
4924 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4925 }
4926 if(my $BFSize = getBitField($TypeMembInfoId))
4927 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004928 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004929 }
4930 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004931 { # in bytes
4932 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004934
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004935 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004936 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004937 }
4938 }
4939}
4940
4941sub setFuncParams($)
4942{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004943 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004944 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004945 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004946 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004947 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4948 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004949 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004950 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004951 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004953 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004954 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004957 else
4958 { # skip
4959 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004960 }
4961 $ParamInfoId = getNextElem($ParamInfoId);
4962 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004963 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004964 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004965 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004966 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4967 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4968 if(not $ParamName)
4969 { # unnamed
4970 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004971 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004972 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4973 {
4974 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4975 $ParamTypeId = $AddedTid;
4976 }
4977 }
4978 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004979 if(not $PType or $PType eq "Unknown") {
4980 return 1;
4981 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004982 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004983 if(not $PTName) {
4984 return 1;
4985 }
4986 if($PTName eq "void") {
4987 last;
4988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004989 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004990 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004991 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004992 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004993 $ParamInfoId = getNextElem($ParamInfoId);
4994 next;
4995 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004996 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4997 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004998 if(my $Algn = getAlgn($ParamInfoId)) {
4999 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5000 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005001 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5002 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005003 }
5004 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5005 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005006 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
5008 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005009 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005010 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005011 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005012 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005013 }
5014 return 0;
5015}
5016
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005017sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005018{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005019 my ($InfoId, $Vtt_Pos) = @_;
5020 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005021 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005022 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005023 $ParamListElemId = getNextElem($ParamListElemId);
5024 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005025 if(not $ParamListElemId)
5026 { # foo(...)
5027 return 1;
5028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005029 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005030 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005031 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005032 { # actual params: may differ from formal args
5033 # formal int*const
5034 # actual: int*
5035 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005036 {
5037 $Vtt_Pos=-1;
5038 $ParamListElemId = getNextElem($ParamListElemId);
5039 next;
5040 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005041 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5042 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005043 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005044 $HaveVoid = 1;
5045 last;
5046 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005047 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005048 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005049 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005050 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5051 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005052 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5053 }
5054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005055 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005056 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005057 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5058 {
5059 my $Val = getInitVal($PurpId, $ParamTypeId);
5060 if(defined $Val) {
5061 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 }
5064 }
5065 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005068 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005069}
5070
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005071sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005072{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005073 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5074 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005075 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5076 return $1;
5077 }
5078 }
5079 return "";
5080}
5081
5082sub getTreeAttr_Chain($)
5083{
5084 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5085 {
5086 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5087 return $1;
5088 }
5089 }
5090 return "";
5091}
5092
5093sub getTreeAttr_Scpe($)
5094{
5095 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5096 {
5097 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5098 return $1;
5099 }
5100 }
5101 return "";
5102}
5103
5104sub getTreeAttr_Type($)
5105{
5106 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5107 {
5108 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5109 return $1;
5110 }
5111 }
5112 return "";
5113}
5114
5115sub getTreeAttr_Name($)
5116{
5117 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5118 {
5119 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5120 return $1;
5121 }
5122 }
5123 return "";
5124}
5125
5126sub getTreeAttr_Mngl($)
5127{
5128 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5129 {
5130 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5131 return $1;
5132 }
5133 }
5134 return "";
5135}
5136
5137sub getTreeAttr_Prms($)
5138{
5139 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5140 {
5141 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5142 return $1;
5143 }
5144 }
5145 return "";
5146}
5147
5148sub getTreeAttr_Fncs($)
5149{
5150 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5151 {
5152 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5153 return $1;
5154 }
5155 }
5156 return "";
5157}
5158
5159sub getTreeAttr_Csts($)
5160{
5161 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5162 {
5163 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5164 return $1;
5165 }
5166 }
5167 return "";
5168}
5169
5170sub getTreeAttr_Purp($)
5171{
5172 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5173 {
5174 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5175 return $1;
5176 }
5177 }
5178 return "";
5179}
5180
5181sub getTreeAttr_Valu($)
5182{
5183 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5184 {
5185 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5186 return $1;
5187 }
5188 }
5189 return "";
5190}
5191
5192sub getTreeAttr_Flds($)
5193{
5194 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5195 {
5196 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5197 return $1;
5198 }
5199 }
5200 return "";
5201}
5202
5203sub getTreeAttr_Args($)
5204{
5205 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5206 {
5207 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005208 return $1;
5209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005210 }
5211 return "";
5212}
5213
5214sub getTreeValue($)
5215{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005216 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5217 {
5218 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5219 return $1;
5220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005221 }
5222 return "";
5223}
5224
5225sub getTreeAccess($)
5226{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005227 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005228 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005229 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5230 {
5231 my $Access = $1;
5232 if($Access eq "prot") {
5233 return "protected";
5234 }
5235 elsif($Access eq "priv") {
5236 return "private";
5237 }
5238 }
5239 elsif($Info=~/ protected /)
5240 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005241 return "protected";
5242 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005243 elsif($Info=~/ private /)
5244 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005245 return "private";
5246 }
5247 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005248 return "public";
5249}
5250
5251sub setFuncAccess($)
5252{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005253 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005254 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005255 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 }
5257 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005258 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005259 }
5260}
5261
5262sub setTypeAccess($$)
5263{
5264 my ($TypeId, $TypeAttr) = @_;
5265 my $Access = getTreeAccess($TypeId);
5266 if($Access eq "protected") {
5267 $TypeAttr->{"Protected"} = 1;
5268 }
5269 elsif($Access eq "private") {
5270 $TypeAttr->{"Private"} = 1;
5271 }
5272}
5273
5274sub setFuncKind($)
5275{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005276 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5277 {
5278 if($Info=~/pseudo tmpl/) {
5279 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5280 }
5281 elsif($Info=~/ constructor /) {
5282 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5283 }
5284 elsif($Info=~/ destructor /) {
5285 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5286 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005287 }
5288}
5289
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005290sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005291{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005292 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5293 {
5294 if($Info=~/spec[ ]*:[ ]*pure /) {
5295 return "PureVirt";
5296 }
5297 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5298 return "Virt";
5299 }
5300 elsif($Info=~/ pure\s+virtual /)
5301 { # support for old GCC versions
5302 return "PureVirt";
5303 }
5304 elsif($Info=~/ virtual /)
5305 { # support for old GCC versions
5306 return "Virt";
5307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005308 }
5309 return "";
5310}
5311
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005312sub getFuncLink($)
5313{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005314 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5315 {
5316 if($Info=~/link[ ]*:[ ]*static /) {
5317 return "Static";
5318 }
5319 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005320 return $1;
5321 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005322 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005323 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005324}
5325
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005326sub get_IntNameSpace($$)
5327{
5328 my ($Interface, $LibVersion) = @_;
5329 return "" if(not $Interface or not $LibVersion);
5330 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5331 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5332 }
5333 my $Signature = get_Signature($Interface, $LibVersion);
5334 if($Signature=~/\:\:/)
5335 {
5336 my $FounNameSpace = 0;
5337 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5338 {
5339 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5340 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5341 }
5342 }
5343 }
5344 else {
5345 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5346 }
5347}
5348
5349sub parse_TypeNameSpace($$)
5350{
5351 my ($TypeName, $LibVersion) = @_;
5352 return "" if(not $TypeName or not $LibVersion);
5353 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5354 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5355 }
5356 if($TypeName=~/\:\:/)
5357 {
5358 my $FounNameSpace = 0;
5359 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5360 {
5361 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5362 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5363 }
5364 }
5365 }
5366 else {
5367 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5368 }
5369}
5370
5371sub getNameSpace($)
5372{
5373 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005374 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005375 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005376 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005377 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005378 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005379 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005380 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5381 {
5382 my $NameSpace = getTreeStr($1);
5383 if($NameSpace eq "::")
5384 { # global namespace
5385 return "";
5386 }
5387 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5388 $NameSpace = $BaseNameSpace."::".$NameSpace;
5389 }
5390 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5391 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005393 else {
5394 return "";
5395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005396 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005397 elsif($InfoType eq "record_type")
5398 { # inside data type
5399 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5400 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005402 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005403 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005404 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005405}
5406
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005407sub getEnumMembVal($)
5408{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005409 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005410 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005411 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5412 {
5413 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5414 {
5415 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5416 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5417 return getTreeValue($1);
5418 }
5419 else
5420 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5421 return getTreeValue($1);
5422 }
5423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005424 }
5425 }
5426 return "";
5427}
5428
5429sub getSize($)
5430{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005431 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5432 {
5433 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5434 return getTreeValue($1);
5435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005436 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005437 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005438}
5439
5440sub getAlgn($)
5441{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005442 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5443 {
5444 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5445 return $1;
5446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005447 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005448 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005449}
5450
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005451sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005453 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5454 {
5455 if($Info=~/ bitfield /) {
5456 return getSize($_[0]);
5457 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005458 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005459 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005460}
5461
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005462sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005463{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005464 if(my $Chan = getTreeAttr_Chan($_[0])) {
5465 return $Chan;
5466 }
5467 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5468 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005469 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005470 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005471}
5472
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005473sub registerHeader($$)
5474{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005475 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005476 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005477 return "";
5478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005479 if(is_abs($Header) and not -f $Header)
5480 { # incorrect absolute path
5481 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005482 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005483 if(skipHeader($Header, $LibVersion))
5484 { # skip
5485 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005487 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5488 {
5489 detect_header_includes($Header_Path, $LibVersion);
5490
5491 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5492 { # redirect
5493 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5494 or skipHeader($RHeader_Path, $LibVersion))
5495 { # skip
5496 return "";
5497 }
5498 $Header_Path = $RHeader_Path;
5499 }
5500 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5501 { # skip
5502 return "";
5503 }
5504
5505 if(my $HName = get_filename($Header_Path))
5506 { # register
5507 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5508 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5509 }
5510
5511 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5512 or $Header!~/\.(\w+)\Z/)
5513 { # hpp, hh
5514 setLanguage($LibVersion, "C++");
5515 }
5516
5517 if($CheckHeadersOnly
5518 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5519 { # /usr/include/c++/4.6.1/...
5520 $STDCXX_TESTING = 1;
5521 }
5522
5523 return $Header_Path;
5524 }
5525 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005526}
5527
5528sub register_directory($$$)
5529{
5530 my ($Dir, $WithDeps, $LibVersion) = @_;
5531 $Dir=~s/[\/\\]+\Z//g;
5532 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005533 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005534 $Dir = get_abs_path($Dir);
5535 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005536 if($WithDeps)
5537 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005538 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5539 return;
5540 }
5541 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5542 $Mode = "DepsOnly";
5543 }
5544 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005545 else
5546 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005547 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5548 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5549 return;
5550 }
5551 }
5552 $Header_Dependency{$LibVersion}{$Dir} = 1;
5553 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5554 if($Mode eq "DepsOnly")
5555 {
5556 foreach my $Path (cmd_find($Dir,"d","","")) {
5557 $Header_Dependency{$LibVersion}{$Path} = 1;
5558 }
5559 return;
5560 }
5561 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5562 {
5563 if($WithDeps)
5564 {
5565 my $SubDir = $Path;
5566 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5567 { # register all sub directories
5568 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5569 }
5570 }
5571 next if(is_not_header($Path));
5572 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005573 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005574 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005575 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005576 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5577 }
5578 }
5579 if(get_filename($Dir) eq "include")
5580 { # search for "lib/include/" directory
5581 my $LibDir = $Dir;
5582 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5583 register_directory($LibDir, $WithDeps, $LibVersion);
5584 }
5585 }
5586}
5587
5588sub parse_redirect($$$)
5589{
5590 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005591 my @Errors = ();
5592 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5593 push(@Errors, $1);
5594 }
5595 my $Redirect = "";
5596 foreach (@Errors)
5597 {
5598 s/\s{2,}/ /g;
5599 if(/(only|must\ include
5600 |update\ to\ include
5601 |replaced\ with
5602 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005603 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005604 {
5605 $Redirect = $2;
5606 last;
5607 }
5608 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5609 {
5610 $Redirect = $2;
5611 last;
5612 }
5613 elsif(/this\ header\ should\ not\ be\ used
5614 |programs\ should\ not\ directly\ include
5615 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5616 |is\ not\ supported\ API\ for\ general\ use
5617 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005618 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5620 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5621 }
5622 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005623 if($Redirect)
5624 {
5625 $Redirect=~s/\A<//g;
5626 $Redirect=~s/>\Z//g;
5627 }
5628 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005629}
5630
5631sub parse_includes($$)
5632{
5633 my ($Content, $Path) = @_;
5634 my %Includes = ();
5635 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005636 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005637 my ($Header, $Method) = ($5, $4);
5638 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005639 if($Method eq "\"" or is_abs($Header))
5640 {
5641 if(-e joinPath(get_dirname($Path), $Header))
5642 { # relative path exists
5643 $Includes{$Header} = -1;
5644 }
5645 else
5646 { # include "..." that doesn't exist is equal to include <...>
5647 $Includes{$Header} = 2;
5648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005649 }
5650 else {
5651 $Includes{$Header} = 1;
5652 }
5653 }
5654 return \%Includes;
5655}
5656
5657sub ignore_path($)
5658{
5659 my $Path = $_[0];
5660 if($Path=~/\~\Z/)
5661 {# skipping system backup files
5662 return 1;
5663 }
5664 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5665 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5666 return 1;
5667 }
5668 return 0;
5669}
5670
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005671sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005672{
5673 my ($ArrRef, $W) = @_;
5674 return if(length($W)<2);
5675 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5676}
5677
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005678sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005679{
5680 my ($H1, $H2) = @_;
5681 $H1=~s/\.[a-z]+\Z//ig;
5682 $H2=~s/\.[a-z]+\Z//ig;
5683 my ($HDir1, $Hname1) = separate_path($H1);
5684 my ($HDir2, $Hname2) = separate_path($H2);
5685 my $Dirname1 = get_filename($HDir1);
5686 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005687 if($_[0] eq $_[1]
5688 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005689 return 0;
5690 }
5691 elsif($H1=~/\A\Q$H2\E/) {
5692 return 1;
5693 }
5694 elsif($H2=~/\A\Q$H1\E/) {
5695 return -1;
5696 }
5697 elsif($HDir1=~/\Q$Hname1\E/i
5698 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005699 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005700 return -1;
5701 }
5702 elsif($HDir2=~/\Q$Hname2\E/i
5703 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005704 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005705 return 1;
5706 }
5707 elsif($Hname1=~/\Q$Dirname1\E/i
5708 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005709 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005710 return -1;
5711 }
5712 elsif($Hname2=~/\Q$Dirname2\E/i
5713 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005714 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005715 return 1;
5716 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005717 elsif($Hname1=~/(config|lib|util)/i
5718 and $Hname2!~/(config|lib|util)/i)
5719 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005720 return -1;
5721 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005722 elsif($Hname2=~/(config|lib|util)/i
5723 and $Hname1!~/(config|lib|util)/i)
5724 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005725 return 1;
5726 }
5727 elsif(checkRelevance($H1)
5728 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005729 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005730 return -1;
5731 }
5732 elsif(checkRelevance($H2)
5733 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005734 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005735 return 1;
5736 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005737 else
5738 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005739 return (lc($H1) cmp lc($H2));
5740 }
5741}
5742
5743sub searchForHeaders($)
5744{
5745 my $LibVersion = $_[0];
5746 # gcc standard include paths
5747 find_gcc_cxx_headers($LibVersion);
5748 # processing header paths
5749 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5750 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5751 {
5752 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005753 if($SystemRoot)
5754 {
5755 if(is_abs($Path)) {
5756 $Path = $SystemRoot.$Path;
5757 }
5758 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005759 if(not -e $Path) {
5760 exitStatus("Access_Error", "can't access \'$Path\'");
5761 }
5762 elsif(-f $Path) {
5763 exitStatus("Access_Error", "\'$Path\' - not a directory");
5764 }
5765 elsif(-d $Path)
5766 {
5767 $Path = get_abs_path($Path);
5768 register_directory($Path, 0, $LibVersion);
5769 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5770 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5771 }
5772 else {
5773 $Include_Paths{$LibVersion}{$Path} = 1;
5774 }
5775 }
5776 }
5777 if(keys(%{$Include_Paths{$LibVersion}})) {
5778 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5779 }
5780 # registering directories
5781 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5782 {
5783 next if(not -e $Path);
5784 $Path = get_abs_path($Path);
5785 $Path = path_format($Path, $OSgroup);
5786 if(-d $Path) {
5787 register_directory($Path, 1, $LibVersion);
5788 }
5789 elsif(-f $Path)
5790 {
5791 my $Dir = get_dirname($Path);
5792 if(not $SystemPaths{"include"}{$Dir}
5793 and not $LocalIncludes{$Dir})
5794 {
5795 register_directory($Dir, 1, $LibVersion);
5796 if(my $OutDir = get_dirname($Dir))
5797 { # registering the outer directory
5798 if(not $SystemPaths{"include"}{$OutDir}
5799 and not $LocalIncludes{$OutDir}) {
5800 register_directory($OutDir, 0, $LibVersion);
5801 }
5802 }
5803 }
5804 }
5805 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005806
5807 # clean memory
5808 %RegisteredDirs = ();
5809
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005810 # registering headers
5811 my $Position = 0;
5812 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5813 {
5814 if(is_abs($Dest) and not -e $Dest) {
5815 exitStatus("Access_Error", "can't access \'$Dest\'");
5816 }
5817 $Dest = path_format($Dest, $OSgroup);
5818 if(is_header($Dest, 1, $LibVersion))
5819 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005820 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005821 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5822 }
5823 }
5824 elsif(-d $Dest)
5825 {
5826 my @Registered = ();
5827 foreach my $Path (cmd_find($Dest,"f","",""))
5828 {
5829 next if(ignore_path($Path));
5830 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005831 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005832 push(@Registered, $HPath);
5833 }
5834 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005835 @Registered = sort {sortHeaders($a, $b)} @Registered;
5836 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005837 foreach my $Path (@Registered) {
5838 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5839 }
5840 }
5841 else {
5842 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5843 }
5844 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005845 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5846 { # preparing preamble headers
5847 my $PPos=0;
5848 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005849 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005850 if(is_abs($Header) and not -f $Header) {
5851 exitStatus("Access_Error", "can't access file \'$Header\'");
5852 }
5853 $Header = path_format($Header, $OSgroup);
5854 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5855 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005856 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5857 { # duplicate
5858 next;
5859 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005860 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005861 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5862 }
5863 else {
5864 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5865 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 }
5867 }
5868 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5869 { # set relative paths (for duplicates)
5870 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5871 { # search for duplicates
5872 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5873 my $Prefix = get_dirname($FirstPath);
5874 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5875 { # detect a shortest distinguishing prefix
5876 my $NewPrefix = $1;
5877 my %Identity = ();
5878 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5879 {
5880 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5881 $Identity{$Path} = $1;
5882 }
5883 }
5884 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5885 { # all names are differend with current prefix
5886 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5887 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5888 }
5889 last;
5890 }
5891 $Prefix = $NewPrefix; # increase prefix
5892 }
5893 }
5894 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005895
5896 # clean memory
5897 %HeaderName_Paths = ();
5898
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005899 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5900 { # ordering headers according to descriptor
5901 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5902 my ($Pos, $PairPos) = (-1, -1);
5903 my ($Path, $PairPath) = ();
5904 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5905 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5906 foreach my $Header_Path (@Paths)
5907 {
5908 if(get_filename($Header_Path) eq $PairName)
5909 {
5910 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5911 $PairPath = $Header_Path;
5912 }
5913 if(get_filename($Header_Path) eq $HeaderName)
5914 {
5915 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5916 $Path = $Header_Path;
5917 }
5918 }
5919 if($PairPos!=-1 and $Pos!=-1
5920 and int($PairPos)<int($Pos))
5921 {
5922 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5923 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5924 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5925 }
5926 }
5927 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5928 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5929 }
5930}
5931
5932sub detect_real_includes($$)
5933{
5934 my ($AbsPath, $LibVersion) = @_;
5935 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5936 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5937 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5938 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5939 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005940 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5941
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005942 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5943 return () if(not $Path);
5944 open(PREPROC, $Path);
5945 while(<PREPROC>)
5946 {
5947 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5948 {
5949 my $Include = path_format($1, $OSgroup);
5950 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5951 next;
5952 }
5953 if($Include eq $AbsPath) {
5954 next;
5955 }
5956 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5957 }
5958 }
5959 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005960 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5961}
5962
5963sub detect_header_includes($$)
5964{
5965 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005966 return if(not $LibVersion or not $Path);
5967 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5968 return;
5969 }
5970 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5971
5972 if(not -e $Path) {
5973 return;
5974 }
5975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005977 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5978 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005979 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005980 {
5981 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005982 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005983 }
5984 if($RedirectPath ne $Path) {
5985 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5986 }
5987 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005988 else
5989 { # can't find
5990 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005992 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005993 if(my $Inc = parse_includes($Content, $Path))
5994 {
5995 foreach my $Include (keys(%{$Inc}))
5996 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005997 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5998 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006000}
6001
6002sub simplify_path($)
6003{
6004 my $Path = $_[0];
6005 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6006 return $Path;
6007}
6008
6009sub fromLibc($)
6010{ # GLIBC header
6011 my $Path = $_[0];
6012 my ($Dir, $Name) = separate_path($Path);
6013 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006014 { # /usr/include/{stdio, ...}.h
6015 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006016 return 1;
6017 }
6018 if(isLibcDir($Dir)) {
6019 return 1;
6020 }
6021 return 0;
6022}
6023
6024sub isLibcDir($)
6025{ # GLIBC directory
6026 my $Dir = $_[0];
6027 my ($OutDir, $Name) = separate_path($Dir);
6028 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6029 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6030 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6031 return 1;
6032 }
6033 return 0;
6034}
6035
6036sub detect_recursive_includes($$)
6037{
6038 my ($AbsPath, $LibVersion) = @_;
6039 return () if(not $AbsPath);
6040 if(isCyclical(\@RecurInclude, $AbsPath)) {
6041 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6042 }
6043 my ($AbsDir, $Name) = separate_path($AbsPath);
6044 if(isLibcDir($AbsDir))
6045 { # GLIBC internals
6046 return ();
6047 }
6048 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6049 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6050 }
6051 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6052 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6053 push(@RecurInclude, $AbsPath);
6054 if($DefaultGccPaths{$AbsDir}
6055 or fromLibc($AbsPath))
6056 { # check "real" (non-"model") include paths
6057 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6058 pop(@RecurInclude);
6059 return @Paths;
6060 }
6061 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6062 detect_header_includes($AbsPath, $LibVersion);
6063 }
6064 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6065 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006066 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006067 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006068 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006069 { # for #include "..."
6070 my $Candidate = joinPath($AbsDir, $Include);
6071 if(-f $Candidate) {
6072 $HPath = simplify_path($Candidate);
6073 }
6074 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006075 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006076 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006077 { # search for the nearest header
6078 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6079 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6080 if(-f $Candidate) {
6081 $HPath = $Candidate;
6082 }
6083 }
6084 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006085 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006086 }
6087 next if(not $HPath);
6088 if($HPath eq $AbsPath) {
6089 next;
6090 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006091
6092 if($Debug)
6093 { # boundary headers
6094 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6095 #{
6096 # print STDERR "$AbsPath -> $HPath\n";
6097 #}
6098 }
6099
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006100 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6101 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006102 { # only include <...>, skip include "..." prefixes
6103 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6104 }
6105 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6106 {
6107 if($IncPath eq $AbsPath) {
6108 next;
6109 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006110 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6111 if($RIncType==-1)
6112 { # include "..."
6113 $RIncType = $IncType;
6114 }
6115 elsif($RIncType==2)
6116 {
6117 if($IncType!=-1) {
6118 $RIncType = $IncType;
6119 }
6120 }
6121 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6123 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6124 }
6125 }
6126 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6127 {
6128 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6129 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6130 { # distinguish math.h from glibc and math.h from the tested library
6131 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6132 last;
6133 }
6134 }
6135 }
6136 pop(@RecurInclude);
6137 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6138}
6139
6140sub find_in_framework($$$)
6141{
6142 my ($Header, $Framework, $LibVersion) = @_;
6143 return "" if(not $Header or not $Framework or not $LibVersion);
6144 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6145 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6146 }
6147 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6148 {
6149 if(get_filename($Dependency) eq $Framework
6150 and -f get_dirname($Dependency)."/".$Header) {
6151 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6152 }
6153 }
6154 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6155}
6156
6157sub find_in_defaults($)
6158{
6159 my $Header = $_[0];
6160 return "" if(not $Header);
6161 if(defined $Cache{"find_in_defaults"}{$Header}) {
6162 return $Cache{"find_in_defaults"}{$Header};
6163 }
6164 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6165 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6166 {
6167 next if(not $Dir);
6168 if(-f $Dir."/".$Header) {
6169 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6170 }
6171 }
6172 return ($Cache{"find_in_defaults"}{$Header}="");
6173}
6174
6175sub cmp_paths($$)
6176{
6177 my ($Path1, $Path2) = @_;
6178 my @Parts1 = split(/[\/\\]/, $Path1);
6179 my @Parts2 = split(/[\/\\]/, $Path2);
6180 foreach my $Num (0 .. $#Parts1)
6181 {
6182 my $Part1 = $Parts1[$Num];
6183 my $Part2 = $Parts2[$Num];
6184 if($GlibcDir{$Part1}
6185 and not $GlibcDir{$Part2}) {
6186 return 1;
6187 }
6188 elsif($GlibcDir{$Part2}
6189 and not $GlibcDir{$Part1}) {
6190 return -1;
6191 }
6192 elsif($Part1=~/glib/
6193 and $Part2!~/glib/) {
6194 return 1;
6195 }
6196 elsif($Part1!~/glib/
6197 and $Part2=~/glib/) {
6198 return -1;
6199 }
6200 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6201 return $CmpRes;
6202 }
6203 }
6204 return 0;
6205}
6206
6207sub checkRelevance($)
6208{
6209 my ($Path) = @_;
6210 return 0 if(not $Path);
6211 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006212 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006213 }
6214 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006215 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006216 my @Tokens = split(/[_\d\W]+/, $Name);
6217 foreach (@Tokens)
6218 {
6219 next if(not $_);
6220 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6221 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6222 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6223 # include/evolution-data-server-1.4/libebook/e-book.h
6224 return 1;
6225 }
6226 }
6227 return 0;
6228}
6229
6230sub checkFamily(@)
6231{
6232 my @Paths = @_;
6233 return 1 if($#Paths<=0);
6234 my %Prefix = ();
6235 foreach my $Path (@Paths)
6236 {
6237 if($SystemRoot) {
6238 $Path = cut_path_prefix($Path, $SystemRoot);
6239 }
6240 if(my $Dir = get_dirname($Path))
6241 {
6242 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6243 $Prefix{$Dir} += 1;
6244 $Prefix{get_dirname($Dir)} += 1;
6245 }
6246 }
6247 foreach (sort keys(%Prefix))
6248 {
6249 if(get_depth($_)>=3
6250 and $Prefix{$_}==$#Paths+1) {
6251 return 1;
6252 }
6253 }
6254 return 0;
6255}
6256
6257sub isAcceptable($$$)
6258{
6259 my ($Header, $Candidate, $LibVersion) = @_;
6260 my $HName = get_filename($Header);
6261 if(get_dirname($Header))
6262 { # with prefix
6263 return 1;
6264 }
6265 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6266 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6267 return 1;
6268 }
6269 if(checkRelevance($Candidate))
6270 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6271 return 1;
6272 }
6273 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6274 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6275 # /usr/include/qt4/Qt/qsslconfiguration.h
6276 return 1;
6277 }
6278 if($OStarget eq "symbian")
6279 {
6280 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6281 return 1;
6282 }
6283 }
6284 return 0;
6285}
6286
6287sub isRelevant($$$)
6288{ # disallow to search for "abstract" headers in too deep directories
6289 my ($Header, $Candidate, $LibVersion) = @_;
6290 my $HName = get_filename($Header);
6291 if($OStarget eq "symbian")
6292 {
6293 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6294 return 0;
6295 }
6296 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006297 if($OStarget ne "bsd")
6298 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006299 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6300 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6301 return 0;
6302 }
6303 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006304 if($OStarget ne "windows")
6305 {
6306 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6307 { # skip /usr/include/wine/msvcrt
6308 return 0;
6309 }
6310 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006311 if(not get_dirname($Header)
6312 and $Candidate=~/[\/\\]wx[\/\\]/)
6313 { # do NOT search in system /wx/ directory
6314 # for headers without a prefix: sstream.h
6315 return 0;
6316 }
6317 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6318 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6319 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6320 return 0;
6321 }
6322 if($Candidate=~/[\/\\]asm-/
6323 and (my $Arch = getArch($LibVersion)) ne "unknown")
6324 { # arch-specific header files
6325 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6326 {# skip ../asm-arm/ if using x86 architecture
6327 return 0;
6328 }
6329 }
6330 my @Candidates = getSystemHeaders($HName, $LibVersion);
6331 if($#Candidates==1)
6332 { # unique header
6333 return 1;
6334 }
6335 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6336 if($#SCandidates==1)
6337 { # unique name
6338 return 1;
6339 }
6340 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6341 if(get_depth($Candidate)-$SystemDepth>=5)
6342 { # abstract headers in too deep directories
6343 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6344 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6345 return 0;
6346 }
6347 }
6348 if($Header eq "parser.h"
6349 and $Candidate!~/\/libxml2\//)
6350 { # select parser.h from xml2 library
6351 return 0;
6352 }
6353 if(not get_dirname($Header)
6354 and keys(%{$SystemHeaders{$HName}})>=3)
6355 { # many headers with the same name
6356 # like thread.h included without a prefix
6357 if(not checkFamily(@Candidates)) {
6358 return 0;
6359 }
6360 }
6361 return 1;
6362}
6363
6364sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006365{ # cache function
6366 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6367 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6368 }
6369 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6370}
6371
6372sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006373{
6374 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006375 if(-f $Header) {
6376 return $Header;
6377 }
6378 if(is_abs($Header) and not -f $Header)
6379 { # incorrect absolute path
6380 return "";
6381 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006382 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006383 { # too abstract configuration headers
6384 return "";
6385 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006386 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006387 if($OSgroup ne "windows")
6388 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006389 if(defined $WinHeaders{lc($HName)}
6390 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006391 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006392 return "";
6393 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006394 }
6395 if($OSgroup ne "macos")
6396 {
6397 if($HName eq "fp.h")
6398 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006399 return "";
6400 }
6401 }
6402 if($OSgroup ne "solaris")
6403 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006404 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006405 return "";
6406 }
6407 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006408 if($OSgroup ne "hpux")
6409 {
6410 if($Header eq "sys/stream.h") {
6411 return "";
6412 }
6413 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006414 if($ObsoleteHeaders{$HName}) {
6415 return "";
6416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006417
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006418 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6419 { # search in default paths
6420 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 }
6423 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006424 if(not keys(%SystemHeaders))
6425 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006426 detectSystemHeaders();
6427 }
6428 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6429 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6430 {
6431 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006432 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006433 }
6434 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006435 # error
6436 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006437}
6438
6439sub getSystemHeaders($$)
6440{
6441 my ($Header, $LibVersion) = @_;
6442 my @Candidates = ();
6443 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6444 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006445 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006446 next;
6447 }
6448 push(@Candidates, $Candidate);
6449 }
6450 return @Candidates;
6451}
6452
6453sub cut_path_prefix($$)
6454{
6455 my ($Path, $Prefix) = @_;
6456 return $Path if(not $Prefix);
6457 $Prefix=~s/[\/\\]+\Z//;
6458 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6459 return $Path;
6460}
6461
6462sub is_default_include_dir($)
6463{
6464 my $Dir = $_[0];
6465 $Dir=~s/[\/\\]+\Z//;
6466 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6467}
6468
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006469sub identifyHeader($$)
6470{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006471 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006472 if(not $Header) {
6473 return "";
6474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006475 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006476 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6477 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006479 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006480}
6481
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006482sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006483{ # search for header by absolute path, relative path or name
6484 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006485 if(-f $Header)
6486 { # it's relative or absolute path
6487 return get_abs_path($Header);
6488 }
6489 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6490 and my $HeaderDir = find_in_defaults($Header))
6491 { # search for libc headers in the /usr/include
6492 # for non-libc target library before searching
6493 # in the library paths
6494 return joinPath($HeaderDir,$Header);
6495 }
6496 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6497 { # search in the target library paths
6498 return $Path;
6499 }
6500 elsif($DefaultGccHeader{$Header})
6501 { # search in the internal GCC include paths
6502 return $DefaultGccHeader{$Header};
6503 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006504 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006505 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006506 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006507 }
6508 elsif($DefaultCppHeader{$Header})
6509 { # search in the default G++ include paths
6510 return $DefaultCppHeader{$Header};
6511 }
6512 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6513 { # search everywhere in the system
6514 return $AnyPath;
6515 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006516 elsif($OSgroup eq "macos")
6517 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6518 if(my $Dir = get_dirname($Header))
6519 {
6520 my $RelPath = "Headers\/".get_filename($Header);
6521 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6522 return joinPath($HeaderDir, $RelPath);
6523 }
6524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 # cannot find anything
6527 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528}
6529
6530sub getLocation($)
6531{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006532 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6533 {
6534 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006535 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006537 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006538 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006539}
6540
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006541sub getNameByInfo($)
6542{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006543 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006544 {
6545 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6546 {
6547 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6548 {
6549 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6550 { # short unsigned int (may include spaces)
6551 return $1;
6552 }
6553 }
6554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006555 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006556 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006557}
6558
6559sub getTreeStr($)
6560{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006561 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006562 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006563 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6564 {
6565 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006566 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006567 and $Str=~/\Ac99_(.+)\Z/) {
6568 if($CppKeywords_A{$1}) {
6569 $Str=$1;
6570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006571 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006572 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006574 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006575 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006576}
6577
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006578sub getFuncShortName($)
6579{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006580 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006581 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 if($Info=~/ operator /)
6583 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006584 if($Info=~/ conversion /)
6585 {
6586 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6587 {
6588 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6589 return "operator ".$RName;
6590 }
6591 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006592 }
6593 else
6594 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006595 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6596 {
6597 if(my $Ind = $Operator_Indication{$1}) {
6598 return "operator".$Ind;
6599 }
6600 elsif(not $UnknownOperator{$1})
6601 {
6602 printMsg("WARNING", "unknown operator $1");
6603 $UnknownOperator{$1} = 1;
6604 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006605 }
6606 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006607 }
6608 else
6609 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006610 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6611 return getTreeStr($1);
6612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006613 }
6614 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006615 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616}
6617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618sub getFuncReturn($)
6619{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006620 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6621 {
6622 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6623 {
6624 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6625 return $1;
6626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006627 }
6628 }
6629 return "";
6630}
6631
6632sub getFuncOrig($)
6633{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006634 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6635 {
6636 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6637 return $1;
6638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006639 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006640 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006641}
6642
6643sub unmangleSymbol($)
6644{
6645 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006646 if(my @Unmngl = unmangleArray($Symbol)) {
6647 return $Unmngl[0];
6648 }
6649 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006650}
6651
6652sub unmangleArray(@)
6653{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006654 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006655 { # MSVC mangling
6656 my $UndNameCmd = get_CmdPath("undname");
6657 if(not $UndNameCmd) {
6658 exitStatus("Not_Found", "can't find \"undname\"");
6659 }
6660 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006661 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006662 }
6663 else
6664 { # GCC mangling
6665 my $CppFiltCmd = get_CmdPath("c++filt");
6666 if(not $CppFiltCmd) {
6667 exitStatus("Not_Found", "can't find c++filt in PATH");
6668 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006669 if(not defined $CPPFILT_SUPPORT_FILE)
6670 {
6671 my $Info = `$CppFiltCmd -h 2>&1`;
6672 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6673 }
6674 if($CPPFILT_SUPPORT_FILE)
6675 { # new versions of c++filt can take a file
6676 if($#_>$MAX_CPPFILT_FILE_SIZE)
6677 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6678 # this is fixed in the oncoming version of Binutils
6679 my @Half = splice(@_, 0, ($#_+1)/2);
6680 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006681 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006682 else
6683 {
6684 my $NoStrip = "";
6685 if($OSgroup eq "macos"
6686 or $OSgroup eq "windows") {
6687 $NoStrip = "-n";
6688 }
6689 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6690 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6691 if($?==139)
6692 { # segmentation fault
6693 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6694 }
6695 return split(/\n/, $Res);
6696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006697 }
6698 else
6699 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006700 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6701 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006702 my @Half = splice(@_, 0, ($#_+1)/2);
6703 return (unmangleArray(@Half), unmangleArray(@_))
6704 }
6705 else
6706 {
6707 my $NoStrip = "";
6708 if($OSgroup eq "macos"
6709 or $OSgroup eq "windows") {
6710 $NoStrip = "-n";
6711 }
6712 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006713 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6714 if($?==139)
6715 { # segmentation fault
6716 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6717 }
6718 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006719 }
6720 }
6721 }
6722}
6723
6724sub get_SignatureNoInfo($$)
6725{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006726 my ($Symbol, $LibVersion) = @_;
6727 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6728 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006729 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006730 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006731 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006732 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006733 { # C++
6734 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6735 $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;
6736 }
6737 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6738 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006739 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740 $Signature .= " [data]";
6741 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006742 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006743 $Signature .= " (...)";
6744 }
6745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006746 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006748 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006749 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6750 }
6751 if($SymbolVersion) {
6752 $Signature .= $VersionSpec.$SymbolVersion;
6753 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006754 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006755}
6756
6757sub get_ChargeLevel($$)
6758{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006759 my ($Symbol, $LibVersion) = @_;
6760 return "" if($Symbol!~/\A(_Z|\?)/);
6761 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6762 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006764 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006765 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006766 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006767 return "[in-charge]";
6768 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006769 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006770 return "[not-in-charge]";
6771 }
6772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006773 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006774 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006775 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 return "[in-charge]";
6777 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006778 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006779 return "[not-in-charge]";
6780 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006781 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006782 return "[in-charge-deleting]";
6783 }
6784 }
6785 }
6786 else
6787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006788 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006789 return "[in-charge]";
6790 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006791 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006792 return "[not-in-charge]";
6793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006794 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 return "[in-charge]";
6796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006797 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006798 return "[not-in-charge]";
6799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006800 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006801 return "[in-charge-deleting]";
6802 }
6803 }
6804 return "";
6805}
6806
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006807sub get_Signature_M($$)
6808{
6809 my ($Symbol, $LibVersion) = @_;
6810 my $Signature_M = $tr_name{$Symbol};
6811 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6812 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006813 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006814 }
6815 return $Signature_M;
6816}
6817
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006818sub get_Signature($$)
6819{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006820 my ($Symbol, $LibVersion) = @_;
6821 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6822 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6825 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006826 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006827 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006828 }
6829 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006830 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6831 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006833 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6834 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006837 $Func_Signature = $NameSpace."::".$ShortName;
6838 }
6839 else {
6840 $Func_Signature = $ShortName;
6841 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006842 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6843 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006844 }
6845 else {
6846 $Func_Signature = $MnglName;
6847 }
6848 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006849 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006850 {
6851 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006852 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006853 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006854 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006855 if(not $ParamTypeName) {
6856 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6857 }
6858 foreach my $Typedef (keys(%ChangedTypedef))
6859 {
6860 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006861 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006863 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6865 }
6866 else {
6867 push(@ParamArray, $ParamTypeName);
6868 }
6869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6871 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006872 $Func_Signature .= " [data]";
6873 }
6874 else
6875 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006877 { # add [in-charge]
6878 $Func_Signature .= " ".$ChargeLevel;
6879 }
6880 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006881 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6882 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 $Func_Signature .= " const";
6884 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006885 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6886 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006887 $Func_Signature .= " volatile";
6888 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006889 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6890 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006891 {# for static methods
6892 $Func_Signature .= " [static]";
6893 }
6894 }
6895 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006896 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6897 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006898 }
6899 if($SymbolVersion) {
6900 $Func_Signature .= $VersionSpec.$SymbolVersion;
6901 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006902 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006903}
6904
6905sub create_member_decl($$)
6906{
6907 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006908 if($TName=~/\([\*]+\)/)
6909 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6911 return $TName;
6912 }
6913 else
6914 {
6915 my @ArraySizes = ();
6916 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6917 push(@ArraySizes, $1);
6918 }
6919 return $TName." ".$Member.join("", @ArraySizes);
6920 }
6921}
6922
6923sub getFuncType($)
6924{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006925 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6926 {
6927 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6928 {
6929 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6930 {
6931 if($Type eq "method_type") {
6932 return "Method";
6933 }
6934 elsif($Type eq "function_type") {
6935 return "Function";
6936 }
6937 else {
6938 return "Other";
6939 }
6940 }
6941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006942 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006943 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006944}
6945
6946sub getFuncTypeId($)
6947{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006948 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6949 {
6950 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6951 return $1;
6952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006953 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006954 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006955}
6956
6957sub isNotAnon($) {
6958 return (not isAnon($_[0]));
6959}
6960
6961sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006962{ # "._N" or "$_N" in older GCC versions
6963 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006964}
6965
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006966sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006967{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006968 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
6969 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006970 }
6971
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006972 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006973
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006974 if($_[1] ne "S")
6975 {
6976 $N=~s/\A[ ]+//g;
6977 $N=~s/[ ]+\Z//g;
6978 $N=~s/[ ]{2,}/ /g;
6979 }
6980
6981 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006982
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006983 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006984
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006985 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6986 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006987
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006988 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006989
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006990 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006991
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006992 if($_[1] eq "S")
6993 {
6994 if(index($N, "operator")!=-1) {
6995 $N=~s/\b(operator[ ]*)> >/$1>>/;
6996 }
6997 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006998
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006999 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007000}
7001
7002sub get_HeaderDeps($$)
7003{
7004 my ($AbsPath, $LibVersion) = @_;
7005 return () if(not $AbsPath or not $LibVersion);
7006 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7007 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7008 }
7009 my %IncDir = ();
7010 detect_recursive_includes($AbsPath, $LibVersion);
7011 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7012 {
7013 next if(not $HeaderPath);
7014 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7015 my $Dir = get_dirname($HeaderPath);
7016 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7017 {
7018 my $Dep = $Dir;
7019 if($Prefix)
7020 {
7021 if($OSgroup eq "windows")
7022 { # case insensitive seach on windows
7023 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7024 next;
7025 }
7026 }
7027 elsif($OSgroup eq "macos")
7028 { # seach in frameworks
7029 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7030 {
7031 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7032 {# frameworks
7033 my ($HFramework, $HName) = ($1, $2);
7034 $Dep = $HFramework;
7035 }
7036 else
7037 {# mismatch
7038 next;
7039 }
7040 }
7041 }
7042 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7043 { # Linux, FreeBSD
7044 next;
7045 }
7046 }
7047 if(not $Dep)
7048 { # nothing to include
7049 next;
7050 }
7051 if(is_default_include_dir($Dep))
7052 { # included by the compiler
7053 next;
7054 }
7055 if(get_depth($Dep)==1)
7056 { # too short
7057 next;
7058 }
7059 if(isLibcDir($Dep))
7060 { # do NOT include /usr/include/{sys,bits}
7061 next;
7062 }
7063 $IncDir{$Dep}=1;
7064 }
7065 }
7066 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7067 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7068}
7069
7070sub sortIncPaths($$)
7071{
7072 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007073 if(not $ArrRef or $#{$ArrRef}<0) {
7074 return $ArrRef;
7075 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007076 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7077 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007078 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007079 return $ArrRef;
7080}
7081
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007082sub sortDeps($$$)
7083{
7084 if($Header_Dependency{$_[2]}{$_[0]}
7085 and not $Header_Dependency{$_[2]}{$_[1]}) {
7086 return 1;
7087 }
7088 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7089 and $Header_Dependency{$_[2]}{$_[1]}) {
7090 return -1;
7091 }
7092 return 0;
7093}
7094
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007095sub joinPath($$) {
7096 return join($SLASH, @_);
7097}
7098
7099sub get_namespace_additions($)
7100{
7101 my $NameSpaces = $_[0];
7102 my ($Additions, $AddNameSpaceId) = ("", 1);
7103 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7104 {
7105 next if($SkipNameSpaces{$Version}{$NS});
7106 next if(not $NS or $NameSpaces->{$NS}==-1);
7107 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7108 next if($NS=~/\A__/i);
7109 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007110 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007111 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7112 my @NS_Parts = split(/::/, $NS);
7113 next if($#NS_Parts==-1);
7114 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7115 foreach my $NS_Part (@NS_Parts)
7116 {
7117 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7118 $TypeDecl_Suffix .= "}";
7119 }
7120 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7121 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7122 $Additions.=" $TypeDecl\n $FuncDecl\n";
7123 $AddNameSpaceId+=1;
7124 }
7125 return $Additions;
7126}
7127
7128sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007129{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007130 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007131 if($Fmt eq "windows")
7132 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 $Path=~s/\//\\/g;
7134 $Path=lc($Path);
7135 }
7136 else {
7137 $Path=~s/\\/\//g;
7138 }
7139 return $Path;
7140}
7141
7142sub inc_opt($$)
7143{
7144 my ($Path, $Style) = @_;
7145 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007146 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007147 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007148 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007149 return "-I\"".path_format($Path, "unix")."\"";
7150 }
7151 elsif($OSgroup eq "macos"
7152 and $Path=~/\.framework\Z/)
7153 {# to Apple's GCC
7154 return "-F".esc(get_dirname($Path));
7155 }
7156 else {
7157 return "-I".esc($Path);
7158 }
7159 }
7160 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007161 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007162 }
7163 return "";
7164}
7165
7166sub platformSpecs($)
7167{
7168 my $LibVersion = $_[0];
7169 my $Arch = getArch($LibVersion);
7170 if($OStarget eq "symbian")
7171 { # options for GCCE compiler
7172 my %Symbian_Opts = map {$_=>1} (
7173 "-D__GCCE__",
7174 "-DUNICODE",
7175 "-fexceptions",
7176 "-D__SYMBIAN32__",
7177 "-D__MARM_INTERWORK__",
7178 "-D_UNICODE",
7179 "-D__S60_50__",
7180 "-D__S60_3X__",
7181 "-D__SERIES60_3X__",
7182 "-D__EPOC32__",
7183 "-D__MARM__",
7184 "-D__EABI__",
7185 "-D__MARM_ARMV5__",
7186 "-D__SUPPORT_CPP_EXCEPTIONS__",
7187 "-march=armv5t",
7188 "-mapcs",
7189 "-mthumb-interwork",
7190 "-DEKA2",
7191 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7192 );
7193 return join(" ", keys(%Symbian_Opts));
7194 }
7195 elsif($OSgroup eq "windows"
7196 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7197 { # add options to MinGW compiler
7198 # to simulate the MSVC compiler
7199 my %MinGW_Opts = map {$_=>1} (
7200 "-D_WIN32",
7201 "-D_STDCALL_SUPPORTED",
7202 "-D__int64=\"long long\"",
7203 "-D__int32=int",
7204 "-D__int16=short",
7205 "-D__int8=char",
7206 "-D__possibly_notnullterminated=\" \"",
7207 "-D__nullterminated=\" \"",
7208 "-D__nullnullterminated=\" \"",
7209 "-D__w64=\" \"",
7210 "-D__ptr32=\" \"",
7211 "-D__ptr64=\" \"",
7212 "-D__forceinline=inline",
7213 "-D__inline=inline",
7214 "-D__uuidof(x)=IID()",
7215 "-D__try=",
7216 "-D__except(x)=",
7217 "-D__declspec(x)=__attribute__((x))",
7218 "-D__pragma(x)=",
7219 "-D_inline=inline",
7220 "-D__forceinline=__inline",
7221 "-D__stdcall=__attribute__((__stdcall__))",
7222 "-D__cdecl=__attribute__((__cdecl__))",
7223 "-D__fastcall=__attribute__((__fastcall__))",
7224 "-D__thiscall=__attribute__((__thiscall__))",
7225 "-D_stdcall=__attribute__((__stdcall__))",
7226 "-D_cdecl=__attribute__((__cdecl__))",
7227 "-D_fastcall=__attribute__((__fastcall__))",
7228 "-D_thiscall=__attribute__((__thiscall__))",
7229 "-DSHSTDAPI_(x)=x",
7230 "-D_MSC_EXTENSIONS",
7231 "-DSECURITY_WIN32",
7232 "-D_MSC_VER=1500",
7233 "-D_USE_DECLSPECS_FOR_SAL",
7234 "-D__noop=\" \"",
7235 "-DDECLSPEC_DEPRECATED=\" \"",
7236 "-D__builtin_alignof(x)=__alignof__(x)",
7237 "-DSORTPP_PASS");
7238 if($Arch eq "x86") {
7239 $MinGW_Opts{"-D_M_IX86=300"}=1;
7240 }
7241 elsif($Arch eq "x86_64") {
7242 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7243 }
7244 elsif($Arch eq "ia64") {
7245 $MinGW_Opts{"-D_M_IA64=300"}=1;
7246 }
7247 return join(" ", keys(%MinGW_Opts));
7248 }
7249 return "";
7250}
7251
7252my %C_Structure = map {$_=>1} (
7253# FIXME: Can't separate union and struct data types before dumping,
7254# so it sometimes cause compilation errors for unknown reason
7255# when trying to declare TYPE* tmp_add_class_N
7256# This is a list of such structures + list of other C structures
7257 "sigval",
7258 "sigevent",
7259 "sigaction",
7260 "sigvec",
7261 "sigstack",
7262 "timeval",
7263 "timezone",
7264 "rusage",
7265 "rlimit",
7266 "wait",
7267 "flock",
7268 "stat",
7269 "_stat",
7270 "stat32",
7271 "_stat32",
7272 "stat64",
7273 "_stat64",
7274 "_stati64",
7275 "if_nameindex",
7276 "usb_device",
7277 "sigaltstack",
7278 "sysinfo",
7279 "timeLocale",
7280 "tcp_debug",
7281 "rpc_createerr",
7282# Other C structures appearing in every dump
7283 "timespec",
7284 "random_data",
7285 "drand48_data",
7286 "_IO_marker",
7287 "_IO_FILE",
7288 "lconv",
7289 "sched_param",
7290 "tm",
7291 "itimerspec",
7292 "_pthread_cleanup_buffer",
7293 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007294 "siginfo",
7295 "mallinfo"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007296);
7297
7298sub getCompileCmd($$$)
7299{
7300 my ($Path, $Opt, $Inc) = @_;
7301 my $GccCall = $GCC_PATH;
7302 if($Opt) {
7303 $GccCall .= " ".$Opt;
7304 }
7305 $GccCall .= " -x ";
7306 if($OSgroup eq "macos") {
7307 $GccCall .= "objective-";
7308 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007309 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007310 { # compile as "C++" header
7311 # to obtain complete dump using GCC 4.0
7312 $GccCall .= "c++-header";
7313 }
7314 else
7315 { # compile as "C++" source
7316 # GCC 3.3 cannot compile headers
7317 $GccCall .= "c++";
7318 }
7319 if(my $Opts = platformSpecs($Version))
7320 {# platform-specific options
7321 $GccCall .= " ".$Opts;
7322 }
7323 # allow extra qualifications
7324 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007325 $GccCall .= " -fpermissive";
7326 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007327 if($NoStdInc)
7328 {
7329 $GccCall .= " -nostdinc";
7330 $GccCall .= " -nostdinc++";
7331 }
7332 if($CompilerOptions{$Version})
7333 { # user-defined options
7334 $GccCall .= " ".$CompilerOptions{$Version};
7335 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007336 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007337 if($Inc)
7338 { # include paths
7339 $GccCall .= " ".$Inc;
7340 }
7341 return $GccCall;
7342}
7343
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007344sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007345{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007346 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007347 my %HeaderElems = (
7348 # Types
7349 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007350 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007351 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7352 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007353 "time.h" => ["time_t"],
7354 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007355 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7356 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007357 "stdbool.h" => ["_Bool"],
7358 "rpc/xdr.h" => ["bool_t"],
7359 "in_systm.h" => ["n_long", "n_short"],
7360 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007361 "arpa/inet.h" => ["fw_src", "ip_src"],
7362 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007363 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007364 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007365 );
7366 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007367 foreach (keys(%HeaderElems))
7368 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007369 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007370 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007371 }
7372 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007373 my %Types = ();
7374 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7375 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007376 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007377 }
7378 if(keys(%Types))
7379 {
7380 my %AddHeaders = ();
7381 foreach my $Type (keys(%Types))
7382 {
7383 if(my $Header = $AutoPreamble{$Type})
7384 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007385 if(my $Path = identifyHeader($Header, $LibVersion))
7386 {
7387 if(skipHeader($Path, $LibVersion)) {
7388 next;
7389 }
7390 $Path = path_format($Path, $OSgroup);
7391 $AddHeaders{$Path}{"Type"} = $Type;
7392 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007393 }
7394 }
7395 }
7396 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007397 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007398 }
7399 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007400 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007401}
7402
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007403sub checkCTags($)
7404{
7405 my $Path = $_[0];
7406 if(not $Path) {
7407 return;
7408 }
7409 my $CTags = get_CmdPath("ctags");
7410 if(not $CTags) {
7411 return;
7412 }
7413 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007414 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007415 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007416 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007417 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007418 open(CTAGS, "<", $Out);
7419 while(my $Line = <CTAGS>)
7420 {
7421 chomp($Line);
7422 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007423 if(defined $Intrinsic_Keywords{$Name})
7424 { # noise
7425 next;
7426 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007427 if($Type eq "n")
7428 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007429 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007430 next;
7431 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007432 if(index($Scpe, "struct:")==0) {
7433 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007434 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007435 if(index($Scpe, "namespace:")==0)
7436 {
7437 if($Scpe=~s/\Anamespace://) {
7438 $Name = $Scpe."::".$Name;
7439 }
7440 }
7441 $TUnit_NameSpaces{$Version}{$Name} = 1;
7442 }
7443 elsif($Type eq "p")
7444 {
7445 if(not $Scpe or index($Scpe, "namespace:")==0) {
7446 $TUnit_Funcs{$Version}{$Name} = 1;
7447 }
7448 }
7449 elsif($Type eq "x")
7450 {
7451 if(not $Scpe or index($Scpe, "namespace:")==0) {
7452 $TUnit_Vars{$Version}{$Name} = 1;
7453 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007454 }
7455 }
7456 close(CTAGS);
7457}
7458
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007459sub getDump()
7460{
7461 if(not $GCC_PATH) {
7462 exitStatus("Error", "internal error - GCC path is not set");
7463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007464 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007465 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007466 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007467 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7468 {
7469 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007470 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007471 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007472 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007473 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7474 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7475 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007476 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007477 }
7478 my @Headers = keys(%{$Registered_Headers{$Version}});
7479 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7480 foreach my $Header_Path (@Headers)
7481 {
7482 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007483 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007484 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007485 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007486 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007487
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007488 if($ExtraInfo)
7489 { # extra information for other tools
7490 writeFile($ExtraInfo."/include-string", $IncludeString);
7491 }
7492
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007493 if(not keys(%{$TargetHeaders{$Version}}))
7494 { # Target headers
7495 addTargetHeaders($Version);
7496 }
7497
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007498 if($Debug)
7499 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007500 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7501 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7502 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007503 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007504 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007505
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007506 # clean memory
7507 %RecursiveIncludes = ();
7508 %Header_Include_Prefix = ();
7509 %Header_Includes = ();
7510
7511 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007512 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007513 delete($Cache{"detect_header_includes"});
7514 delete($Cache{"selectSystemHeader"});
7515
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007516 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007517 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7518 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007519
7520 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007521 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007522
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007523 if($COMMON_LANGUAGE{$Version} eq "C++") {
7524 checkCTags($Pre);
7525 }
7526
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007527 my $MContent = "";
7528 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7529 if($OStarget eq "windows"
7530 and get_dumpmachine($GCC_PATH)=~/mingw/i
7531 and $MinGWMode{$Version}!=-1)
7532 { # modify headers to compile by MinGW
7533 if(not $MContent)
7534 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007535 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007536 }
7537 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7538 { # __asm { ... }
7539 $MinGWMode{$Version}=1;
7540 }
7541 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7542 { # comments after preprocessing
7543 $MinGWMode{$Version}=1;
7544 }
7545 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7546 { # 0xffui8
7547 $MinGWMode{$Version}=1;
7548 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007549 if($MinGWMode{$Version})
7550 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007551 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007552 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007553 }
7554 }
7555 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007556 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007557 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007558 if(not $MContent)
7559 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007560 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007561 }
7562 my $RegExp_C = join("|", keys(%CppKeywords_C));
7563 my $RegExp_F = join("|", keys(%CppKeywords_F));
7564 my $RegExp_O = join("|", keys(%CppKeywords_O));
7565 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7566 { # MATCH:
7567 # int foo(int new, int class, int (*new)(int));
7568 # unsigned private: 8;
7569 # DO NOT MATCH:
7570 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007571 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007572 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007573 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007574 { # MATCH:
7575 # int delete(...);
7576 # int explicit(...);
7577 # DO NOT MATCH:
7578 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007579 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007580 }
7581 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7582 { # MATCH:
7583 # int bool;
7584 # DO NOT MATCH:
7585 # bool X;
7586 # return *this;
7587 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007588 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007589 }
7590 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7591 { # MATCH:
7592 # int operator(...);
7593 # DO NOT MATCH:
7594 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007595 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007596 }
7597 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7598 { # MATCH:
7599 # int foo(int operator);
7600 # int foo(int operator, int other);
7601 # DO NOT MATCH:
7602 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007603 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007604 }
7605 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7606 { # MATCH:
7607 # int foo(gboolean *bool);
7608 # DO NOT MATCH:
7609 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007610 $CppMode{$Version} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007611 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007612 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007613 { # MATCH:
7614 # int foo(int* this);
7615 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007616 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007617 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007618 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007619 $CppMode{$Version} = 1;
7620 }
7621
7622 if($CppMode{$Version} == 1)
7623 {
7624 if($Debug) {
7625 printMsg("INFO", "Detected: $1$2$3$4");
7626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007627 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007628
7629 # remove typedef enum NAME NAME;
7630 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7631 my $N = 0;
7632 while($N<=$#FwdTypedefs-1)
7633 {
7634 my $S = $FwdTypedefs[$N];
7635 if($S eq $FwdTypedefs[$N+1])
7636 {
7637 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007638 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007639 }
7640 $N+=2;
7641 }
7642
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007643 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007644 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007645 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007646 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007647 }
7648 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007649 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007650 or $MinGWMode{$Version}==1)
7651 { # compile the corrected preprocessor output
7652 writeFile($MHeaderPath, $MContent);
7653 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007654
7655 # clean memory
7656 undef $MContent;
7657
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007658 if($COMMON_LANGUAGE{$Version} eq "C++")
7659 { # add classes and namespaces to the dump
7660 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007661 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007662 or $MinGWMode{$Version}==1) {
7663 $CHdump .= " -fpreprocessed";
7664 }
7665 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7666 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007667 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007668 chdir($ORIG_DIR);
7669 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7670 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007671 my $Content = readFile($ClassDump);
7672 foreach my $ClassInfo (split(/\n\n/, $Content))
7673 {
7674 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7675 {
7676 my $CName = $1;
7677 next if($CName=~/\A(__|_objc_|_opaque_)/);
7678 $TUnit_NameSpaces{$Version}{$CName} = -1;
7679 if($CName=~/\A[\w:]+\Z/)
7680 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007681 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007682 }
7683 if($CName=~/(\w[\w:]*)::/)
7684 { # namespaces
7685 my $NS = $1;
7686 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7687 $TUnit_NameSpaces{$Version}{$NS} = 1;
7688 }
7689 }
7690 }
7691 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7692 { # read v-tables (advanced approach)
7693 my ($CName, $VTable) = ($1, $2);
7694 $ClassVTable_Content{$Version}{$CName} = $VTable;
7695 }
7696 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007697 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7698 { # add user-defined namespaces
7699 $TUnit_NameSpaces{$Version}{$NS} = 1;
7700 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007701 if($Debug)
7702 { # debug mode
7703 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007704 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007705 }
7706 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007707 }
7708
7709 # add namespaces and classes
7710 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7711 { # GCC on all supported platforms does not include namespaces to the dump by default
7712 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7713 }
7714 # some GCC versions don't include class methods to the TU dump by default
7715 my ($AddClass, $ClassNum) = ("", 0);
7716 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7717 {
7718 next if($C_Structure{$CName});
7719 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7720 next if(($CName=~tr![:]!!)>2);
7721 next if($SkipTypes{$Version}{$CName});
7722 if($CName=~/\A(.+)::[^:]+\Z/)
7723 { # will be added by name space
7724 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007725 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007726 if(defined $TUnit_Funcs{$Version}{$CName})
7727 { # the same name for a function and type
7728 next;
7729 }
7730 if(defined $TUnit_Vars{$Version}{$CName})
7731 { # the same name for a variable and type
7732 next;
7733 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007734 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7735 }
7736 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007737 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7738 }
7739 }
7740 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7741 # create TU dump
7742 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007743 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007744 or $MinGWMode{$Version}==1) {
7745 $TUdump .= " -fpreprocessed";
7746 }
7747 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7748 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7749 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007750 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007751 if($?)
7752 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007753 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7754 { # try to recompile
7755 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007756 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007757 and $Errors=~/c99_/)
7758 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007759 $CppMode{$Version}=-1;
7760 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007761 resetLogging($Version);
7762 $TMP_DIR = tempdir(CLEANUP=>1);
7763 return getDump();
7764 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007765 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007766 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007767 { # add auto preamble headers and try again
7768 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007769 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007770 foreach my $Num (0 .. $#Headers)
7771 {
7772 my $Path = $Headers[$Num];
7773 if(defined $Include_Preamble{$Version}{$Path})
7774 { # already added
7775 next;
7776 }
7777 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007778 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007779 }
7780 resetLogging($Version);
7781 $TMP_DIR = tempdir(CLEANUP=>1);
7782 return getDump();
7783 }
7784 elsif($Cpp0xMode{$Version}!=-1
7785 and ($Errors=~/\Q-std=c++0x\E/
7786 or $Errors=~/is not a class or namespace/))
7787 { # c++0x: enum class
7788 $Cpp0xMode{$Version}=-1;
7789 printMsg("INFO", "Enabling c++0x mode");
7790 resetLogging($Version);
7791 $TMP_DIR = tempdir(CLEANUP=>1);
7792 $CompilerOptions{$Version} .= " -std=c++0x";
7793 return getDump();
7794 }
7795 elsif($MinGWMode{$Version}==1)
7796 { # disable MinGW mode and try again
7797 $MinGWMode{$Version}=-1;
7798 resetLogging($Version);
7799 $TMP_DIR = tempdir(CLEANUP=>1);
7800 return getDump();
7801 }
7802 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007803 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007804 else {
7805 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007806 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007807 printMsg("ERROR", "some errors occurred when compiling headers");
7808 printErrorLog($Version);
7809 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7810 writeLog($Version, "\n");# new line
7811 }
7812 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007813 unlink($TmpHeaderPath);
7814 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007815 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7816}
7817
7818sub cmd_file($)
7819{
7820 my $Path = $_[0];
7821 return "" if(not $Path or not -e $Path);
7822 if(my $CmdPath = get_CmdPath("file")) {
7823 return `$CmdPath -b \"$Path\"`;
7824 }
7825 return "";
7826}
7827
7828sub getIncString($$)
7829{
7830 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007831 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007832 my $String = "";
7833 foreach (@{$ArrRef}) {
7834 $String .= " ".inc_opt($_, $Style);
7835 }
7836 return $String;
7837}
7838
7839sub getIncPaths(@)
7840{
7841 my @HeaderPaths = @_;
7842 my @IncPaths = ();
7843 if($INC_PATH_AUTODETECT{$Version})
7844 { # auto-detecting dependencies
7845 my %Includes = ();
7846 foreach my $HPath (@HeaderPaths)
7847 {
7848 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7849 {
7850 if($Skip_Include_Paths{$Version}{$Dir}) {
7851 next;
7852 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007853 if($SystemRoot)
7854 {
7855 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7856 next;
7857 }
7858 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007859 $Includes{$Dir}=1;
7860 }
7861 }
7862 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7863 { # added by user
7864 next if($Includes{$Dir});
7865 push(@IncPaths, $Dir);
7866 }
7867 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7868 push(@IncPaths, $Dir);
7869 }
7870 }
7871 else
7872 { # user-defined paths
7873 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7874 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7875 push(@IncPaths, $Dir);
7876 }
7877 }
7878 return \@IncPaths;
7879}
7880
7881sub callPreprocessor($$$)
7882{
7883 my ($Path, $Inc, $LibVersion) = @_;
7884 return "" if(not $Path or not -f $Path);
7885 my $IncludeString=$Inc;
7886 if(not $Inc) {
7887 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7888 }
7889 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007890 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007891 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007892 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007893}
7894
7895sub cmd_find($$$$)
7896{ # native "find" is much faster than File::Find (~6x)
7897 # also the File::Find doesn't support --maxdepth N option
7898 # so using the cross-platform wrapper for the native one
7899 my ($Path, $Type, $Name, $MaxDepth) = @_;
7900 return () if(not $Path or not -e $Path);
7901 if($OSgroup eq "windows")
7902 {
7903 my $DirCmd = get_CmdPath("dir");
7904 if(not $DirCmd) {
7905 exitStatus("Not_Found", "can't find \"dir\" command");
7906 }
7907 $Path=~s/[\\]+\Z//;
7908 $Path = get_abs_path($Path);
7909 $Path = path_format($Path, $OSgroup);
7910 my $Cmd = $DirCmd." \"$Path\" /B /O";
7911 if($MaxDepth!=1) {
7912 $Cmd .= " /S";
7913 }
7914 if($Type eq "d") {
7915 $Cmd .= " /AD";
7916 }
7917 my @Files = ();
7918 if($Name)
7919 { # FIXME: how to search file names in MS shell?
7920 $Name=~s/\*/.*/g if($Name!~/\]/);
7921 foreach my $File (split(/\n/, `$Cmd`))
7922 {
7923 if($File=~/$Name\Z/i) {
7924 push(@Files, $File);
7925 }
7926 }
7927 }
7928 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007929 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007930 }
7931 my @AbsPaths = ();
7932 foreach my $File (@Files)
7933 {
7934 if(not is_abs($File)) {
7935 $File = joinPath($Path, $File);
7936 }
7937 if($Type eq "f" and not -f $File)
7938 { # skip dirs
7939 next;
7940 }
7941 push(@AbsPaths, path_format($File, $OSgroup));
7942 }
7943 if($Type eq "d") {
7944 push(@AbsPaths, $Path);
7945 }
7946 return @AbsPaths;
7947 }
7948 else
7949 {
7950 my $FindCmd = get_CmdPath("find");
7951 if(not $FindCmd) {
7952 exitStatus("Not_Found", "can't find a \"find\" command");
7953 }
7954 $Path = get_abs_path($Path);
7955 if(-d $Path and -l $Path
7956 and $Path!~/\/\Z/)
7957 { # for directories that are symlinks
7958 $Path.="/";
7959 }
7960 my $Cmd = $FindCmd." \"$Path\"";
7961 if($MaxDepth) {
7962 $Cmd .= " -maxdepth $MaxDepth";
7963 }
7964 if($Type) {
7965 $Cmd .= " -type $Type";
7966 }
7967 if($Name)
7968 { # file name
7969 if($Name=~/\]/) {
7970 $Cmd .= " -regex \"$Name\"";
7971 }
7972 else {
7973 $Cmd .= " -name \"$Name\"";
7974 }
7975 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007976 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
7977 if($?) {
7978 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
7979 }
7980 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007981 }
7982}
7983
7984sub unpackDump($)
7985{
7986 my $Path = $_[0];
7987 return "" if(not $Path or not -e $Path);
7988 $Path = get_abs_path($Path);
7989 $Path = path_format($Path, $OSgroup);
7990 my ($Dir, $FileName) = separate_path($Path);
7991 my $UnpackDir = $TMP_DIR."/unpack";
7992 rmtree($UnpackDir);
7993 mkpath($UnpackDir);
7994 if($FileName=~s/\Q.zip\E\Z//g)
7995 { # *.zip
7996 my $UnzipCmd = get_CmdPath("unzip");
7997 if(not $UnzipCmd) {
7998 exitStatus("Not_Found", "can't find \"unzip\" command");
7999 }
8000 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008001 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008002 if($?) {
8003 exitStatus("Error", "can't extract \'$Path\'");
8004 }
8005 chdir($ORIG_DIR);
8006 my @Contents = ();
8007 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8008 {
8009 if(/inflating:\s*([^\s]+)/) {
8010 push(@Contents, $1);
8011 }
8012 }
8013 if(not @Contents) {
8014 exitStatus("Error", "can't extract \'$Path\'");
8015 }
8016 return joinPath($UnpackDir, $Contents[0]);
8017 }
8018 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8019 { # *.tar.gz
8020 if($OSgroup eq "windows")
8021 { # -xvzf option is not implemented in tar.exe (2003)
8022 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8023 my $TarCmd = get_CmdPath("tar");
8024 if(not $TarCmd) {
8025 exitStatus("Not_Found", "can't find \"tar\" command");
8026 }
8027 my $GzipCmd = get_CmdPath("gzip");
8028 if(not $GzipCmd) {
8029 exitStatus("Not_Found", "can't find \"gzip\" command");
8030 }
8031 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008032 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008033 if($?) {
8034 exitStatus("Error", "can't extract \'$Path\'");
8035 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008036 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008037 if($?) {
8038 exitStatus("Error", "can't extract \'$Path\'");
8039 }
8040 chdir($ORIG_DIR);
8041 unlink($Dir."/".$FileName.".tar");
8042 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8043 if(not @Contents) {
8044 exitStatus("Error", "can't extract \'$Path\'");
8045 }
8046 return joinPath($UnpackDir, $Contents[0]);
8047 }
8048 else
8049 { # Unix
8050 my $TarCmd = get_CmdPath("tar");
8051 if(not $TarCmd) {
8052 exitStatus("Not_Found", "can't find \"tar\" command");
8053 }
8054 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008055 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008056 if($?) {
8057 exitStatus("Error", "can't extract \'$Path\'");
8058 }
8059 chdir($ORIG_DIR);
8060 # The content file name may be different
8061 # from the package file name
8062 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8063 if(not @Contents) {
8064 exitStatus("Error", "can't extract \'$Path\'");
8065 }
8066 return joinPath($UnpackDir, $Contents[0]);
8067 }
8068 }
8069}
8070
8071sub createArchive($$)
8072{
8073 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008074 if(not $To) {
8075 $To = ".";
8076 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008077 if(not $Path or not -e $Path
8078 or not -d $To) {
8079 return "";
8080 }
8081 my ($From, $Name) = separate_path($Path);
8082 if($OSgroup eq "windows")
8083 { # *.zip
8084 my $ZipCmd = get_CmdPath("zip");
8085 if(not $ZipCmd) {
8086 exitStatus("Not_Found", "can't find \"zip\"");
8087 }
8088 my $Pkg = $To."/".$Name.".zip";
8089 unlink($Pkg);
8090 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008091 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008092 if($?)
8093 { # cannot allocate memory (or other problems with "zip")
8094 unlink($Path);
8095 exitStatus("Error", "can't pack the ABI dump: ".$!);
8096 }
8097 chdir($ORIG_DIR);
8098 unlink($Path);
8099 return $Pkg;
8100 }
8101 else
8102 { # *.tar.gz
8103 my $TarCmd = get_CmdPath("tar");
8104 if(not $TarCmd) {
8105 exitStatus("Not_Found", "can't find \"tar\"");
8106 }
8107 my $GzipCmd = get_CmdPath("gzip");
8108 if(not $GzipCmd) {
8109 exitStatus("Not_Found", "can't find \"gzip\"");
8110 }
8111 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8112 unlink($Pkg);
8113 chdir($From);
8114 system($TarCmd, "-czf", $Pkg, $Name);
8115 if($?)
8116 { # cannot allocate memory (or other problems with "tar")
8117 unlink($Path);
8118 exitStatus("Error", "can't pack the ABI dump: ".$!);
8119 }
8120 chdir($ORIG_DIR);
8121 unlink($Path);
8122 return $To."/".$Name.".tar.gz";
8123 }
8124}
8125
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008126sub readBytes($)
8127{
8128 sysopen(FILE, $_[0], O_RDONLY);
8129 sysread(FILE, my $Header, 4);
8130 close(FILE);
8131 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8132 return join("", @Bytes);
8133}
8134
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008135sub is_header_file($)
8136{
8137 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8138 return $_[0];
8139 }
8140 return 0;
8141}
8142
8143sub is_not_header($)
8144{
8145 if($_[0]=~/\.\w+\Z/
8146 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8147 return 1;
8148 }
8149 return 0;
8150}
8151
8152sub is_header($$$)
8153{
8154 my ($Header, $UserDefined, $LibVersion) = @_;
8155 return 0 if(-d $Header);
8156 if(-f $Header) {
8157 $Header = get_abs_path($Header);
8158 }
8159 else
8160 {
8161 if(is_abs($Header))
8162 { # incorrect absolute path
8163 return 0;
8164 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008165 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008166 $Header = $HPath;
8167 }
8168 else
8169 { # can't find header
8170 return 0;
8171 }
8172 }
8173 if($Header=~/\.\w+\Z/)
8174 { # have an extension
8175 return is_header_file($Header);
8176 }
8177 else
8178 {
8179 if($UserDefined==2)
8180 { # specified on the command line
8181 if(cmd_file($Header)!~/HTML|XML/i) {
8182 return $Header;
8183 }
8184 }
8185 elsif($UserDefined)
8186 { # specified in the XML-descriptor
8187 # header file without an extension
8188 return $Header;
8189 }
8190 else
8191 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008192 if($Header=~/\/include\//
8193 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008194 { # !~/HTML|XML|shared|dynamic/i
8195 return $Header;
8196 }
8197 }
8198 }
8199 return 0;
8200}
8201
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008202sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008203{
8204 my $LibVersion = $_[0];
8205 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8206 {
8207 my $RegDir = get_dirname($RegHeader);
8208 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008209
8210 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8211 detect_recursive_includes($RegHeader, $LibVersion);
8212 }
8213
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008214 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8215 {
8216 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008217 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8218 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8219 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008220 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8221 }
8222 }
8223 }
8224}
8225
8226sub readHeaders($)
8227{
8228 $Version = $_[0];
8229 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8230 my $DumpPath = getDump();
8231 if(not $DumpPath) {
8232 exitStatus("Cannot_Compile", "can't compile header(s)");
8233 }
8234 if($Debug)
8235 { # debug mode
8236 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008237 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008238 }
8239 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008240}
8241
8242sub prepareTypes($)
8243{
8244 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008245 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008246 { # support for old ABI dumps
8247 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008248 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008249 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008250 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8251 if($TName=~/\A(\w+)::(\w+)/) {
8252 my ($P1, $P2) = ($1, $2);
8253 if($P1 eq $P2) {
8254 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008255 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008256 else {
8257 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8258 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008259 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008260 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008261 }
8262 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008263 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008264 { # support for old ABI dumps
8265 # V < 2.5: array size == "number of elements"
8266 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008267 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008268 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008269 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008270 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008271 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008272 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008273 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008274 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008275 $Size *= $Base{"Size"};
8276 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008277 }
8278 else
8279 { # array[] is a pointer
8280 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008281 }
8282 }
8283 }
8284 }
8285 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008286 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008287 { # support for old ABI dumps
8288 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008289 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008290 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008291 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008292 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008293 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008294 my %Type = get_Type($TypeId, $LibVersion);
8295 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8296 my %Type2 = get_Type($TypeId_2, $V2);
8297 if($Type{"Size"} ne $Type2{"Size"}) {
8298 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008299 }
8300 }
8301 }
8302 }
8303}
8304
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008305sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306{
8307 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008308
8309 if(not keys(%{$SymbolInfo{$LibVersion}}))
8310 { # check if input is valid
8311 if(not $ExtendedCheck and not $CheckObjectsOnly)
8312 {
8313 if($CheckHeadersOnly) {
8314 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8315 }
8316 else {
8317 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8318 }
8319 }
8320 }
8321
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008322 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008323 if(not checkDump(1, "2.10")
8324 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008325 { # different formats
8326 $Remangle = 1;
8327 }
8328 if($CheckHeadersOnly)
8329 { # different languages
8330 if($UserLang)
8331 { # --lang=LANG for both versions
8332 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8333 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8334 {
8335 if($UserLang eq "C++")
8336 { # remangle symbols
8337 $Remangle = 1;
8338 }
8339 elsif($UserLang eq "C")
8340 { # remove mangling
8341 $Remangle = -1;
8342 }
8343 }
8344 }
8345 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008346
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008347 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008348 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008349 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008350 { # support for old ABI dumps
8351 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8352 {
8353 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8354 {
8355 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8356 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008357 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008358 if(defined $DVal and $DVal ne "")
8359 {
8360 if($TName eq "char") {
8361 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8362 }
8363 elsif($TName eq "bool") {
8364 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8365 }
8366 }
8367 }
8368 }
8369 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008370 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008371 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008372 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8373 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008374 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008375 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8376 # + support for old ABI dumps
8377 next;
8378 }
8379 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008380 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008381 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008382 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008383 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008384
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008385 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008386 if(not checkDump(1, "2.12")
8387 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008388 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008389 if($ShortName eq "operator>>")
8390 {
8391 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8392 { # corrected mangling of operator>>
8393 $SRemangle = 1;
8394 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008395 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008396 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8397 {
8398 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8399 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8400 { # corrected mangling of const global data
8401 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8402 # and incorrectly mangled by old ACC versions
8403 $SRemangle = 1;
8404 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008405 }
8406 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008407 if(not $CheckHeadersOnly)
8408 { # support for old ABI dumps
8409 if(not checkDump(1, "2.17")
8410 or not checkDump(2, "2.17"))
8411 {
8412 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8413 {
8414 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8415 {
8416 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8417 {
8418 $MnglName = $ShortName;
8419 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8420 }
8421 }
8422 }
8423 }
8424 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008425 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008426 { # support for old ABI dumps: some symbols are not mangled in old dumps
8427 # mangle both sets of symbols (old and new)
8428 # NOTE: remangling all symbols by the same mangler
8429 if($MnglName=~/\A_ZN(V|)K/)
8430 { # mangling may be incorrect on old ABI dumps
8431 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008432 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008433 }
8434 if($MnglName=~/\A_ZN(K|)V/)
8435 { # mangling may be incorrect on old ABI dumps
8436 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008437 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008438 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008439 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8440 or (not $ClassID and $CheckHeadersOnly)
8441 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8442 { # support for old ABI dumps, GCC >= 4.0
8443 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008444 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008445 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008446 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008447 $MangledNames{$LibVersion}{$MnglName} = 1;
8448 }
8449 }
8450 }
8451 elsif($Remangle==-1)
8452 { # remove mangling
8453 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008454 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008455 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008456 if(not $MnglName) {
8457 next;
8458 }
8459 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8460 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008461 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8462
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008464 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008465 { # support for old dumps
8466 # add "Volatile" attribute
8467 if($MnglName=~/_Z(K|)V/) {
8468 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8469 }
8470 }
8471 # symbol and its symlink have same signatures
8472 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008473 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008474 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008475
8476 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008477 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008478 }
8479 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8480 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8481 }
8482 if($ExtendedCheck)
8483 { # --ext option
8484 addExtension($LibVersion);
8485 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008486
8487 # clean memory
8488 delete($SymbolInfo{$LibVersion});
8489
8490 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008491 { # detect allocable classes with public exported constructors
8492 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008493 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008494 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008495 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008496 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008497 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8498 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008499 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008500 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008501 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008502 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008503 $AllocableClass{$LibVersion}{$ClassName} = 1;
8504 }
8505 }
8506 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008507 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008508 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008509 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008510 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008511 if($CheckHeadersOnly)
8512 {
8513 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8514 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8515 { # all symbols except non-virtual inline
8516 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8517 }
8518 }
8519 else {
8520 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008521 }
8522 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008523 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008524 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008525 }
8526 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008527 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008528 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008529 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008530 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008531 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008532 if(defined $Base{"Type"}
8533 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008534 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008535 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008536 if($Name=~/<([^<>\s]+)>/)
8537 {
8538 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8539 $ReturnedClass{$LibVersion}{$Tid} = 1;
8540 }
8541 }
8542 else {
8543 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8544 }
8545 }
8546 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008547 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008548 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008549 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008550 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008551 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008552 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008553 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008554 if($Base{"Type"}=~/Struct|Class/)
8555 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008556 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008557 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8558 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008559 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008561 }
8562 }
8563 }
8564 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008565
8566 # mapping {short name => symbols}
8567 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008568 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008569 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008570 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008571 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008572 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008573 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008574 {
8575 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008576 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008577 }
8578 }
8579 }
8580 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008581
8582 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008583 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008584 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008585 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008586 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008587 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8588 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008589 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008590 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008591 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008592 $ClassNames{$LibVersion}{$TName} = 1;
8593 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008594 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008595 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8596 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008597 }
8598 }
8599 }
8600 }
8601 }
8602}
8603
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008604sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008605{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008606 my ($TypeId, $LibVersion) = @_;
8607 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008608 return 0;
8609 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008610 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008611 { # already registered
8612 return 1;
8613 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008614 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008615 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008616 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008617 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008618 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008619 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008620 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008621 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008622 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008623 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008624 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008625 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008626 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8627 {
8628 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8629 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008630 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008631 }
8632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008633 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008634 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008635 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008636 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008637 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008638 }
8639 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008640 if($TInfo{"Type"} eq "FuncPtr"
8641 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008642 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008643 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008644 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008645 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008646 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008647 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008648 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008649 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008650 }
8651 }
8652 }
8653 return 1;
8654 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008655 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008656 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008657 $UsedType{$LibVersion}{$TypeId} = 1;
8658 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008659 return 1;
8660 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008661 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008662 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008663 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008664 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008665 }
8666 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008667 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008668}
8669
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008670sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008671{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008672 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8673
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008674 if($Level eq "Dump")
8675 {
8676 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8677 { # TODO: check if this symbol is from
8678 # base classes of other target symbols
8679 return 1;
8680 }
8681 }
8682
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008683 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8684 { # stdc++ interfaces
8685 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008686 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008687
8688 my $Target = 0;
8689 if(my $Header = $SInfo->{"Header"}) {
8690 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8691 }
8692 if($CheckHeadersOnly)
8693 {
8694 if($Target)
8695 {
8696 if($Level eq "Dump")
8697 { # dumped
8698 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008699 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008700 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008701 return 1;
8702 }
8703 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008704 else {
8705 return 1;
8706 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008707 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008708 elsif($Level eq "Source")
8709 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008710 return 1;
8711 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008712 elsif($Level eq "Binary")
8713 { # checked
8714 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8715 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8716 return 1;
8717 }
8718 }
8719 }
8720 }
8721 else
8722 { # library is available
8723 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8724 { # exported symbols
8725 return 1;
8726 }
8727 if($Level eq "Dump")
8728 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008729 if($BinaryOnly)
8730 {
8731 if($SInfo->{"Data"})
8732 {
8733 if($Target) {
8734 return 1;
8735 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008736 }
8737 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008738 else
8739 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008740 if($Target) {
8741 return 1;
8742 }
8743 }
8744 }
8745 elsif($Level eq "Source")
8746 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008747 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8748 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008749 { # skip LOCAL symbols
8750 if($Target) {
8751 return 1;
8752 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008753 }
8754 }
8755 elsif($Level eq "Binary")
8756 { # checked
8757 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8758 {
8759 if($Target) {
8760 return 1;
8761 }
8762 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008763 }
8764 }
8765 return 0;
8766}
8767
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008768sub cleanDump($)
8769{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008770 my $LibVersion = $_[0];
8771 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8772 {
8773 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8774 if(not $MnglName) {
8775 delete($SymbolInfo{$LibVersion}{$InfoId});
8776 next;
8777 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008778 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008779 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008780 delete($SymbolInfo{$LibVersion}{$InfoId});
8781 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008782 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008783 if($MnglName eq $ShortName)
8784 { # remove duplicate data
8785 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008786 }
8787 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8788 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8789 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008790 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8791 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8792 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008794 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008795 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008796 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008797 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008798 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008799 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8800 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8801 }
8802 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008803 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8804 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8805 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008806 }
8807}
8808
8809sub selectType($$)
8810{
8811 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008812
8813 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8814 {
8815 if(defined $TypeInfo{$LibVersion}{$Dupl})
8816 {
8817 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8818 { # duplicate
8819 return 0;
8820 }
8821 }
8822 }
8823
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008824 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8825 {
8826 if(not isBuiltIn($THeader))
8827 {
8828 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008829 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008830 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8831 {
8832 if(is_target_header($THeader, $LibVersion))
8833 { # from target headers
8834 if(not selfTypedef($Tid, $LibVersion)) {
8835 return 1;
8836 }
8837 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008838 }
8839 }
8840 }
8841 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008842 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008843}
8844
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008845sub removeUnused($$)
8846{ # remove unused data types from the ABI dump
8847 my ($LibVersion, $Kind) = @_;
8848 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8849 {
8850 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8851 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008852 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008853 }
8854 if(my $FCid = $FuncInfo{"Class"})
8855 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008856 register_TypeUsage($FCid, $LibVersion);
8857 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008858 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008859 $UsedType{$LibVersion}{$ThisId} = 1;
8860 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8861 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008862 }
8863 }
8864 }
8865 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8866 {
8867 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008868 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008869 }
8870 }
8871 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8872 {
8873 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8874 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008875 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008876 }
8877 }
8878 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008879 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8880 {
8881 if($UsedType{$LibVersion}{$Tid})
8882 { # All & Derived
8883 next;
8884 }
8885
8886 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008887 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008888 if(selectType($Tid, $LibVersion)) {
8889 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008890 }
8891 }
8892 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008893 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8894 { # remove unused types
8895 if($UsedType{$LibVersion}{$Tid})
8896 { # All & Derived
8897 next;
8898 }
8899 # remove type
8900 delete($TypeInfo{$LibVersion}{$Tid});
8901 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008902
8903 # clean memory
8904 %UsedType = ();
8905}
8906
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008907sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008908{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008909 my ($TypeId, $LibVersion) = @_;
8910 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008911 if($Type{"Type"} eq "Typedef")
8912 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008913 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008914 if($Base{"Type"}=~/Class|Struct/)
8915 {
8916 if($Type{"Name"} eq $Base{"Name"}) {
8917 return 1;
8918 }
8919 elsif($Type{"Name"}=~/::(\w+)\Z/)
8920 {
8921 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8922 { # QPointer<QWidget>::QPointer
8923 return 1;
8924 }
8925 }
8926 }
8927 }
8928 return 0;
8929}
8930
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008931sub addExtension($)
8932{
8933 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008934 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008935 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008936 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008937 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008938 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8939
8940 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8941 "Header" => "extended.h",
8942 "ShortName" => $Symbol,
8943 "MnglName" => $Symbol,
8944 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8945 );
8946
8947 $ExtendedSymbols{$Symbol}=1;
8948 $CheckedSymbols{"Binary"}{$Symbol}=1;
8949 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008950 }
8951 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008952 $ExtendedSymbols{"external_func_0"}=1;
8953 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8954 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008955}
8956
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008957sub findMethod($$$)
8958{
8959 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008960 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008961 {
8962 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8963 return $VirtMethodInClass;
8964 }
8965 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8966 return $VirtMethodInBaseClasses;
8967 }
8968 }
8969 return "";
8970}
8971
8972sub findMethod_Class($$$)
8973{
8974 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008975 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008976 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8977 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8978 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8979 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8980 { # search for interface with the same parameters suffix (overridden)
8981 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8982 {
8983 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008984 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8985 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008986 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8987 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8988 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8989 return $Candidate;
8990 }
8991 }
8992 }
8993 else {
8994 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8995 return $Candidate;
8996 }
8997 }
8998 }
8999 }
9000 return "";
9001}
9002
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009003sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009004{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009005 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009006 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009007 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009008 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9009 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009010 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009011 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009012 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009013 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9014 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009015 { # pure virtual D2-destructors are marked as "virt" in the dump
9016 # virtual D2-destructors are NOT marked as "virt" in the dump
9017 # both destructors are not presented in the v-table
9018 next;
9019 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009020 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009021 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9022 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009023 }
9024}
9025
9026sub registerOverriding($)
9027{
9028 my $LibVersion = $_[0];
9029 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009030 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009031 foreach my $ClassName (@Classes)
9032 {
9033 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9034 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009035 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9036 { # pure virtuals
9037 next;
9038 }
9039 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9040 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009041 {
9042 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9043 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9044 { # both overridden virtual methods
9045 # and implemented pure virtual methods
9046 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9047 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9048 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9049 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009050 }
9051 }
9052 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9053 delete($VirtualTable{$LibVersion}{$ClassName});
9054 }
9055 }
9056}
9057
9058sub setVirtFuncPositions($)
9059{
9060 my $LibVersion = $_[0];
9061 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9062 {
9063 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9064 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9065 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9066 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009067 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9068
9069 # set relative positions
9070 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9071 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9072 { # relative position excluding added and removed virtual functions
9073 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9074 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009075 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9076 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009077 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009078 }
9079 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009080 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009081 {
9082 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009083 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9084 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009085 }
9086 }
9087}
9088
9089sub get_sub_classes($$$)
9090{
9091 my ($ClassId, $LibVersion, $Recursive) = @_;
9092 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9093 my @Subs = ();
9094 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9095 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009096 if($Recursive)
9097 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009098 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9099 push(@Subs, $SubSubId);
9100 }
9101 }
9102 push(@Subs, $SubId);
9103 }
9104 return @Subs;
9105}
9106
9107sub get_base_classes($$$)
9108{
9109 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009110 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009111 return () if(not defined $ClassType{"Base"});
9112 my @Bases = ();
9113 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9114 keys(%{$ClassType{"Base"}}))
9115 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009116 if($Recursive)
9117 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009118 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9119 push(@Bases, $SubBaseId);
9120 }
9121 }
9122 push(@Bases, $BaseId);
9123 }
9124 return @Bases;
9125}
9126
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009127sub getVTable_Model($$)
9128{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009129 my ($ClassId, $LibVersion) = @_;
9130 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9131 my @Elements = ();
9132 foreach my $BaseId (@Bases, $ClassId)
9133 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009134 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009135 {
9136 if(defined $VirtualTable{$LibVersion}{$BName})
9137 {
9138 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9139 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9140 foreach my $VFunc (@VFunctions) {
9141 push(@Elements, $VFunc);
9142 }
9143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009144 }
9145 }
9146 return @Elements;
9147}
9148
9149sub getVShift($$)
9150{
9151 my ($ClassId, $LibVersion) = @_;
9152 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9153 my $VShift = 0;
9154 foreach my $BaseId (@Bases)
9155 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009156 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009157 {
9158 if(defined $VirtualTable{$LibVersion}{$BName}) {
9159 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9160 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009161 }
9162 }
9163 return $VShift;
9164}
9165
9166sub getShift($$)
9167{
9168 my ($ClassId, $LibVersion) = @_;
9169 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9170 my $Shift = 0;
9171 foreach my $BaseId (@Bases)
9172 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009173 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009174 {
9175 if($Size!=1)
9176 { # not empty base class
9177 $Shift+=$Size;
9178 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009179 }
9180 }
9181 return $Shift;
9182}
9183
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009184sub getVTable_Size($$)
9185{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009186 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009187 my $Size = 0;
9188 # three approaches
9189 if(not $Size)
9190 { # real size
9191 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9192 $Size = keys(%VTable);
9193 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009194 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009195 if(not $Size)
9196 { # shared library symbol size
9197 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9198 $Size /= $WORD_SIZE{$LibVersion};
9199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009200 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009201 if(not $Size)
9202 { # model size
9203 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9204 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9205 }
9206 }
9207 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009208}
9209
9210sub isCopyingClass($$)
9211{
9212 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009213 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009214}
9215
9216sub isLeafClass($$)
9217{
9218 my ($ClassId, $LibVersion) = @_;
9219 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9220}
9221
9222sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009223{ # check structured type for public fields
9224 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009225}
9226
9227sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009228{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009229 my ($TypePtr, $Skip, $Start, $End) = @_;
9230 return 0 if(not $TypePtr);
9231 if($End==-1) {
9232 $End = keys(%{$TypePtr->{"Memb"}})-1;
9233 }
9234 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9235 {
9236 if($Skip and $Skip->{$MemPos})
9237 { # skip removed/added fields
9238 next;
9239 }
9240 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9241 {
9242 if(isPublic($TypePtr, $MemPos)) {
9243 return ($MemPos+1);
9244 }
9245 }
9246 }
9247 return 0;
9248}
9249
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009250sub isReserved($)
9251{ # reserved fields == private
9252 my $MName = $_[0];
9253 if($MName=~/reserved|padding|f_spare/i) {
9254 return 1;
9255 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009256 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009257 return 1;
9258 }
9259 if($MName=~/(pad\d+)/i) {
9260 return 1;
9261 }
9262 return 0;
9263}
9264
9265sub isPublic($$)
9266{
9267 my ($TypePtr, $FieldPos) = @_;
9268 return 0 if(not $TypePtr);
9269 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9270 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9271 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9272 { # by name in C language
9273 # FIXME: add other methods to detect private members
9274 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9275 if($MName=~/priv|abidata|parent_object/i)
9276 { # C-styled private data
9277 return 0;
9278 }
9279 if(lc($MName) eq "abi")
9280 { # ABI information/reserved field
9281 return 0;
9282 }
9283 if(isReserved($MName))
9284 { # reserved fields
9285 return 0;
9286 }
9287 return 1;
9288 }
9289 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9290 { # by access in C++ language
9291 return 1;
9292 }
9293 return 0;
9294}
9295
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009296sub getVTable_Real($$)
9297{
9298 my ($ClassName, $LibVersion) = @_;
9299 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9300 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009301 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009302 if(defined $Type{"VTable"}) {
9303 return %{$Type{"VTable"}};
9304 }
9305 }
9306 return ();
9307}
9308
9309sub cmpVTables($)
9310{
9311 my $ClassName = $_[0];
9312 my $Res = cmpVTables_Real($ClassName, 1);
9313 if($Res==-1) {
9314 $Res = cmpVTables_Model($ClassName);
9315 }
9316 return $Res;
9317}
9318
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009319sub cmpVTables_Model($)
9320{
9321 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009322 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009323 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009324 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009325 return 1;
9326 }
9327 }
9328 return 0;
9329}
9330
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009331sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009332{
9333 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009334 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9335 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009336 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009337 my %VTable_Old = getVTable_Real($ClassName, 1);
9338 my %VTable_New = getVTable_Real($ClassName, 2);
9339 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009340 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009341 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009342 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009343 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009344 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9345 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009346 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009347 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009348 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009349 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009350 my $Entry1 = $VTable_Old{$Offset};
9351 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009352 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009353 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009354 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009355 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009356 $Entry1 = simpleVEntry($Entry1);
9357 $Entry2 = simpleVEntry($Entry2);
9358 if($Entry1 ne $Entry2)
9359 { # register as changed
9360 if($Entry1=~/::([^:]+)\Z/)
9361 {
9362 my $M1 = $1;
9363 if($Entry2=~/::([^:]+)\Z/)
9364 {
9365 my $M2 = $1;
9366 if($M1 eq $M2)
9367 { # overridden
9368 next;
9369 }
9370 }
9371 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009372 if(differentDumps("G"))
9373 {
9374 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9375 {
9376 # GCC 4.6.1: -0x00000000000000010
9377 # GCC 4.7.0: -16
9378 next;
9379 }
9380 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009381 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009382 }
9383 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009384 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009385}
9386
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009387sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009388{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009389 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009390 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9391 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009392 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009393 { # already registered
9394 next;
9395 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009396 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009397 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009398 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009399 foreach my $Symbol (@Affected)
9400 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009401 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009402 "Type_Name"=>$ClassName,
9403 "Type_Type"=>"Class",
9404 "Target"=>$ClassName);
9405 }
9406 }
9407 }
9408}
9409
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009410sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009411{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009412 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009413 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009415 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009416 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009417 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009418 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009419 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009420 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009421 if($TName_Tid{1}{$ClassName}
9422 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009423 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009424 if(defined $CompleteSignature{1}{$Symbol}
9425 and $CompleteSignature{1}{$Symbol}{"Virt"})
9426 { # override some method in v.1
9427 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009428 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009429 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009430 }
9431 }
9432 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009433 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009434 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009435 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009436 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009437 if($TName_Tid{2}{$ClassName}
9438 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009439 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009440 if(defined $CompleteSignature{2}{$Symbol}
9441 and $CompleteSignature{2}{$Symbol}{"Virt"})
9442 { # override some method in v.2
9443 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009444 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009445 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009446 }
9447 }
9448 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009449 if($Level eq "Binary")
9450 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009451 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009452 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9453 { # check replacements, including pure virtual methods
9454 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9455 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009456 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009457 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9458 if($AddedPos==$RemovedPos)
9459 {
9460 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9461 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9462 last; # other methods will be reported as "added" or "removed"
9463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009464 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009465 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9466 {
9467 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9468 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009469 next;
9470 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009471 my $ProblemType = "Virtual_Replacement";
9472 my @Affected = ($RemovedVFunc);
9473 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9474 { # pure methods
9475 if(not isUsedClass($ClassId, 1, $Level))
9476 { # not a parameter of some exported method
9477 next;
9478 }
9479 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009480
9481 # affected all methods (both virtual and non-virtual ones)
9482 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9483 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009484 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009485 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009486 foreach my $AffectedInt (@Affected)
9487 {
9488 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9489 { # affected exported methods only
9490 next;
9491 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009492 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9493 next;
9494 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009495 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9496 "Type_Name"=>$Class_Type{"Name"},
9497 "Type_Type"=>"Class",
9498 "Target"=>get_Signature($AddedVFunc, 2),
9499 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9500 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009501 }
9502 }
9503 }
9504 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009505 if(not checkDump(1, "2.0")
9506 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009507 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009508 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009509 return;
9510 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009511 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009512 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009513 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009514 next if(not $ClassId_Old);
9515 if(not isCreatable($ClassId_Old, 1))
9516 { # skip classes without public constructors (including auto-generated)
9517 # example: class has only a private exported or private inline constructor
9518 next;
9519 }
9520 if($ClassName=~/>/)
9521 { # skip affected template instances
9522 next;
9523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009524 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009525 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009526 if(not $ClassId_New) {
9527 next;
9528 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009529 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009530 if($Class_New{"Type"}!~/Class|Struct/)
9531 { # became typedef
9532 if($Level eq "Binary") {
9533 next;
9534 }
9535 if($Level eq "Source")
9536 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009537 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009538 if($Class_New{"Type"}!~/Class|Struct/) {
9539 next;
9540 }
9541 $ClassId_New = $Class_New{"Tid"};
9542 }
9543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009544 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9545 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 +04009546
9547 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9548 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9549
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009550 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009551 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9552 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009553 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9554 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009555 my $Shift_Old = getShift($ClassId_Old, 1);
9556 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009557 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009558 my ($Added, $Removed) = (0, 0);
9559 my @StableBases_Old = ();
9560 foreach my $BaseId (@Bases_Old)
9561 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009562 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009563 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009564 push(@StableBases_Old, $BaseId);
9565 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009566 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009567 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009568 { # removed base
9569 # excluding namespace::SomeClass to SomeClass renaming
9570 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009571 if($Level eq "Binary")
9572 { # Binary-level
9573 if($Shift_Old ne $Shift_New)
9574 { # affected fields
9575 if(havePubFields(\%Class_Old)) {
9576 $ProblemKind .= "_And_Shift";
9577 }
9578 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9579 $ProblemKind .= "_And_Size";
9580 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009581 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009582 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9583 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009584 { # affected v-table
9585 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009586 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009587 }
9588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009589 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009590 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9591 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009592 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9593 {
9594 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9595 if($ProblemKind=~/VTable/) {
9596 $VTableChanged_M{$SubName}=1;
9597 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009598 }
9599 }
9600 foreach my $Interface (@Affected)
9601 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009602 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9603 next;
9604 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009605 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009606 "Type_Name"=>$ClassName,
9607 "Type_Type"=>"Class",
9608 "Target"=>$BaseName,
9609 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9610 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9611 "Shift"=>abs($Shift_New-$Shift_Old) );
9612 }
9613 $Removed+=1;
9614 }
9615 }
9616 my @StableBases_New = ();
9617 foreach my $BaseId (@Bases_New)
9618 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009619 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009620 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009621 push(@StableBases_New, $BaseId);
9622 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009623 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009624 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009625 { # added base
9626 # excluding namespace::SomeClass to SomeClass renaming
9627 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009628 if($Level eq "Binary")
9629 { # Binary-level
9630 if($Shift_Old ne $Shift_New)
9631 { # affected fields
9632 if(havePubFields(\%Class_Old)) {
9633 $ProblemKind .= "_And_Shift";
9634 }
9635 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9636 $ProblemKind .= "_And_Size";
9637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009638 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009639 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9640 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009641 { # affected v-table
9642 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009643 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009644 }
9645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009646 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009647 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9648 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009649 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9650 {
9651 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9652 if($ProblemKind=~/VTable/) {
9653 $VTableChanged_M{$SubName}=1;
9654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009655 }
9656 }
9657 foreach my $Interface (@Affected)
9658 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009659 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9660 next;
9661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009662 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009663 "Type_Name"=>$ClassName,
9664 "Type_Type"=>"Class",
9665 "Target"=>$BaseName,
9666 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9667 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9668 "Shift"=>abs($Shift_New-$Shift_Old) );
9669 }
9670 $Added+=1;
9671 }
9672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009673 if($Level eq "Binary")
9674 { # Binary-level
9675 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009676 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9677 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009678 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009679 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009680 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009681 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009682 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009683 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9684 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009685 if($NewPos!=$OldPos)
9686 { # changed position of the base class
9687 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009688 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009689 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9690 next;
9691 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009692 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9693 "Type_Name"=>$ClassName,
9694 "Type_Type"=>"Class",
9695 "Target"=>$BaseName,
9696 "Old_Value"=>$OldPos-1,
9697 "New_Value"=>$NewPos-1 );
9698 }
9699 }
9700 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9701 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9702 { # became non-virtual base
9703 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9704 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009705 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9706 next;
9707 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009708 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9709 "Type_Name"=>$ClassName,
9710 "Type_Type"=>"Class",
9711 "Target"=>$BaseName );
9712 }
9713 }
9714 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9715 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9716 { # became virtual base
9717 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9718 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009719 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9720 next;
9721 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009722 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9723 "Type_Name"=>$ClassName,
9724 "Type_Type"=>"Class",
9725 "Target"=>$BaseName );
9726 }
9727 }
9728 }
9729 }
9730 # detect size changes in base classes
9731 if($Shift_Old!=$Shift_New)
9732 { # size of allocable class
9733 foreach my $BaseId (@StableBases_Old)
9734 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009735 my %BaseType = get_Type($BaseId, 1);
9736 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009737 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009738 if($Size_Old ne $Size_New
9739 and $Size_Old and $Size_New)
9740 {
9741 my $ProblemType = "";
9742 if(isCopyingClass($BaseId, 1)) {
9743 $ProblemType = "Size_Of_Copying_Class";
9744 }
9745 elsif($AllocableClass{1}{$BaseType{"Name"}})
9746 {
9747 if($Size_New>$Size_Old)
9748 { # increased size
9749 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009750 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009751 else
9752 { # decreased size
9753 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9754 if(not havePubFields(\%Class_Old))
9755 { # affected class has no public members
9756 next;
9757 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009758 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009759 }
9760 next if(not $ProblemType);
9761 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9762 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009763 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9764 next;
9765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009766 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9767 "Type_Name"=>$BaseType{"Name"},
9768 "Type_Type"=>"Class",
9769 "Target"=>$BaseType{"Name"},
9770 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9771 "New_Size"=>$Size_New*$BYTE_SIZE );
9772 }
9773 }
9774 }
9775 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009776 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009777 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009778 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009779 { # compare virtual tables size in base classes
9780 my $VShift_Old = getVShift($ClassId_Old, 1);
9781 my $VShift_New = getVShift($ClassId_New, 2);
9782 if($VShift_Old ne $VShift_New)
9783 { # changes in the base class or changes in the list of base classes
9784 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9785 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9786 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009787 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009788 foreach my $BaseId (@AllBases_Old)
9789 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009790 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009791 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009792 { # lost base
9793 next;
9794 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009795 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9796 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009797 if($VSize_Old!=$VSize_New)
9798 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009799 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009800 { # TODO: affected non-virtual methods?
9801 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009802 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9803 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009804 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009805 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009806 { # skip interfaces that have not changed the absolute virtual position
9807 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009808 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009809 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9810 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009811 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009812 $VTableChanged_M{$BaseType{"Name"}} = 1;
9813 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009814 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9815 { # the reason of the layout change: added virtual functions
9816 next if($VirtualReplacement{$VirtFunc});
9817 my $ProblemType = "Added_Virtual_Method";
9818 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9819 $ProblemType = "Added_Pure_Virtual_Method";
9820 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009821 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009822 "Type_Name"=>$BaseType{"Name"},
9823 "Type_Type"=>"Class",
9824 "Target"=>get_Signature($VirtFunc, 2) );
9825 }
9826 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9827 { # the reason of the layout change: removed virtual functions
9828 next if($VirtualReplacement{$VirtFunc});
9829 my $ProblemType = "Removed_Virtual_Method";
9830 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9831 $ProblemType = "Removed_Pure_Virtual_Method";
9832 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009833 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009834 "Type_Name"=>$BaseType{"Name"},
9835 "Type_Type"=>"Class",
9836 "Target"=>get_Signature($VirtFunc, 1) );
9837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009838 }
9839 }
9840 }
9841 }
9842 }
9843 }
9844 }
9845}
9846
9847sub isCreatable($$)
9848{
9849 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009850 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009851 or isCopyingClass($ClassId, $LibVersion)) {
9852 return 1;
9853 }
9854 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9855 { # Fix for incomplete data: if this class has
9856 # a base class then it should also has a constructor
9857 return 1;
9858 }
9859 if($ReturnedClass{$LibVersion}{$ClassId})
9860 { # returned by some method of this class
9861 # or any other class
9862 return 1;
9863 }
9864 return 0;
9865}
9866
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009867sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009868{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009869 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009870 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9871 { # parameter of some exported method
9872 return 1;
9873 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009874 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9875 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009876 { # method from target class
9877 return 1;
9878 }
9879 return 0;
9880}
9881
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009882sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009883{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009884 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009885 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009886 # - virtual
9887 # - pure-virtual
9888 # - non-virtual
9889 if($CompleteSignature{1}{$Interface}{"Data"})
9890 { # global data is not affected
9891 return;
9892 }
9893 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009894 if(not $Class_Id) {
9895 return;
9896 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009897 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009898 if(cmpVTables_Real($CName, 1)==0)
9899 { # no changes
9900 return;
9901 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009902 $CheckedTypes{$Level}{$CName} = 1;
9903 if($Level eq "Binary")
9904 { # Binary-level
9905 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9906 and not isUsedClass($Class_Id, 1, $Level))
9907 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009908 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009909 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009910 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009911 }
9912 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9913 {
9914 if(defined $VirtualTable{2}{$CName}{$Func}
9915 and defined $CompleteSignature{2}{$Func})
9916 {
9917 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9918 and $CompleteSignature{2}{$Func}{"PureVirt"})
9919 { # became pure virtual
9920 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9921 "Type_Name"=>$CName,
9922 "Type_Type"=>"Class",
9923 "Target"=>get_Signature_M($Func, 1) );
9924 $VTableChanged_M{$CName} = 1;
9925 }
9926 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9927 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9928 { # became non-pure virtual
9929 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9930 "Type_Name"=>$CName,
9931 "Type_Type"=>"Class",
9932 "Target"=>get_Signature_M($Func, 1) );
9933 $VTableChanged_M{$CName} = 1;
9934 }
9935 }
9936 }
9937 if($Level eq "Binary")
9938 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009939 # check virtual table structure
9940 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9941 {
9942 next if($Interface eq $AddedVFunc);
9943 next if($VirtualReplacement{$AddedVFunc});
9944 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9945 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9946 { # pure virtual methods affect all others (virtual and non-virtual)
9947 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009948 "Type_Name"=>$CName,
9949 "Type_Type"=>"Class",
9950 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009951 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009952 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009953 elsif(not defined $VirtualTable{1}{$CName}
9954 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009955 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009956 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009957 { # became polymorphous class, added v-table pointer
9958 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009959 "Type_Name"=>$CName,
9960 "Type_Type"=>"Class",
9961 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009962 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009963 }
9964 else
9965 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009966 my $VSize_Old = getVTable_Size($CName, 1);
9967 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009968 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009969 if(isCopyingClass($Class_Id, 1))
9970 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9971 my $ProblemType = "Added_Virtual_Method";
9972 if(isLeafClass($Class_Id, 1)) {
9973 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9974 }
9975 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9976 "Type_Name"=>$CName,
9977 "Type_Type"=>"Class",
9978 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009979 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009980 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009981 else
9982 {
9983 my $ProblemType = "Added_Virtual_Method";
9984 if(isLeafClass($Class_Id, 1)) {
9985 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9986 }
9987 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9988 "Type_Name"=>$CName,
9989 "Type_Type"=>"Class",
9990 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009991 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009993 }
9994 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009995 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9996 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009997 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009998 if(defined $VirtualTable{1}{$CName}
9999 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010000 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010001 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10002 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10003 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010004 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010005 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10006 foreach my $ASymbol (@Affected)
10007 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010008 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10009 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010010 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010011 next;
10012 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010013 }
10014 $CheckedSymbols{$Level}{$ASymbol} = 1;
10015 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10016 "Type_Name"=>$CName,
10017 "Type_Type"=>"Class",
10018 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010019 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010020 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010022 }
10023 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010024 else {
10025 # safe
10026 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010027 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010028 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10029 {
10030 next if($VirtualReplacement{$RemovedVFunc});
10031 if($RemovedVFunc eq $Interface
10032 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10033 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010034 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010035 next;
10036 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010037 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010038 { # became non-polymorphous class, removed v-table pointer
10039 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10040 "Type_Name"=>$CName,
10041 "Type_Type"=>"Class",
10042 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010043 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010044 }
10045 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10046 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10047 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010048 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010049 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010050 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10051 next;
10052 }
10053 my $VPos_New = -1;
10054 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010055 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010056 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10057 }
10058 else
10059 {
10060 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010061 next;
10062 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010063 }
10064 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10065 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10066 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10067 {
10068 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10069 foreach my $ASymbol (@Affected)
10070 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010071 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10072 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010073 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010074 next;
10075 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010076 }
10077 my $ProblemType = "Removed_Virtual_Method";
10078 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10079 $ProblemType = "Removed_Pure_Virtual_Method";
10080 }
10081 $CheckedSymbols{$Level}{$ASymbol} = 1;
10082 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10083 "Type_Name"=>$CName,
10084 "Type_Type"=>"Class",
10085 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010086 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010088 }
10089 }
10090 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010091 }
10092 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010093 else
10094 { # Source-level
10095 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010096 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010097 next if($Interface eq $AddedVFunc);
10098 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010099 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010100 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10101 "Type_Name"=>$CName,
10102 "Type_Type"=>"Class",
10103 "Target"=>get_Signature($AddedVFunc, 2) );
10104 }
10105 }
10106 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10107 {
10108 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10109 {
10110 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10111 "Type_Name"=>$CName,
10112 "Type_Type"=>"Class",
10113 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010114 }
10115 }
10116 }
10117}
10118
10119sub find_MemberPair_Pos_byName($$)
10120{
10121 my ($Member_Name, $Pair_Type) = @_;
10122 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10123 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10124 {
10125 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10126 {
10127 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10128 $Name=~s/\A[_]+|[_]+\Z//g;
10129 if($Name eq $Member_Name) {
10130 return $MemberPair_Pos;
10131 }
10132 }
10133 }
10134 return "lost";
10135}
10136
10137sub find_MemberPair_Pos_byVal($$)
10138{
10139 my ($Member_Value, $Pair_Type) = @_;
10140 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10141 {
10142 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10143 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10144 return $MemberPair_Pos;
10145 }
10146 }
10147 return "lost";
10148}
10149
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010150my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010151 "High"=>3,
10152 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010153 "Low"=>1,
10154 "Safe"=>-1
10155);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010156
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010157sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010158{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010159 my ($S1, $S2) = @_;
10160 if(cmpSeverities($S1, $S2)) {
10161 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010162 }
10163 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010164 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010165 }
10166}
10167
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010168sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010169{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010170 my ($S1, $S2) = @_;
10171 if(not $S1) {
10172 return 0;
10173 }
10174 elsif(not $S2) {
10175 return 1;
10176 }
10177 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010178}
10179
10180sub getProblemSeverity($$)
10181{
10182 my ($Level, $Kind) = @_;
10183 return $CompatRules{$Level}{$Kind}{"Severity"};
10184}
10185
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010186sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010187{
10188 foreach (@RecurTypes)
10189 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010190 if( $_->{"T1"} eq $_[0]
10191 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010192 {
10193 return 1;
10194 }
10195 }
10196 return 0;
10197}
10198
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010199sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010200{
10201 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010202 "T1" => $_[0], #Tid1
10203 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010204 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010205 push(@RecurTypes, \%TypeIDs);
10206}
10207
10208sub isRenamed($$$$$)
10209{
10210 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10211 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10212 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010213 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010214 if(not defined $Type2->{"Memb"}{$MemPos}) {
10215 return "";
10216 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010217 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010218 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010219
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010220 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10221 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010222 if($MemberPair_Pos_Rev eq "lost")
10223 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010224 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10225 { # base type match
10226 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010227 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010228 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10229 { # exact type match
10230 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010231 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010232 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10233 { # size match
10234 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010235 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010236 if(isReserved($Pair_Name))
10237 { # reserved fields
10238 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010239 }
10240 }
10241 return "";
10242}
10243
10244sub isLastElem($$)
10245{
10246 my ($Pos, $TypeRef) = @_;
10247 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10248 if($Name=~/last|count|max|total/i)
10249 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10250 return 1;
10251 }
10252 elsif($Name=~/END|NLIMITS\Z/)
10253 { # __RLIMIT_NLIMITS
10254 return 1;
10255 }
10256 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10257 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10258 { # NImageFormats, NColorRoles
10259 return 1;
10260 }
10261 return 0;
10262}
10263
10264sub nonComparable($$)
10265{
10266 my ($T1, $T2) = @_;
10267 if($T1->{"Name"} ne $T2->{"Name"}
10268 and not isAnon($T1->{"Name"})
10269 and not isAnon($T2->{"Name"}))
10270 { # different names
10271 if($T1->{"Type"} ne "Pointer"
10272 or $T2->{"Type"} ne "Pointer")
10273 { # compare base types
10274 return 1;
10275 }
10276 if($T1->{"Name"}!~/\Avoid\s*\*/
10277 and $T2->{"Name"}=~/\Avoid\s*\*/)
10278 {
10279 return 1;
10280 }
10281 }
10282 elsif($T1->{"Type"} ne $T2->{"Type"})
10283 { # different types
10284 if($T1->{"Type"} eq "Class"
10285 and $T2->{"Type"} eq "Struct")
10286 { # "class" to "struct"
10287 return 0;
10288 }
10289 elsif($T2->{"Type"} eq "Class"
10290 and $T1->{"Type"} eq "Struct")
10291 { # "struct" to "class"
10292 return 0;
10293 }
10294 else
10295 { # "class" to "enum"
10296 # "union" to "class"
10297 # ...
10298 return 1;
10299 }
10300 }
10301 return 0;
10302}
10303
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010304sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010305{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010306 my ($Type1_Id, $Type2_Id, $Level) = @_;
10307 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010308 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010309 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010310 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010311 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010312 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010313 my %Type1 = get_Type($Type1_Id, 1);
10314 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010315 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10316 return ();
10317 }
10318 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010319 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10320 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010321 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010322 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10323 { # including a case when "class Class { ... };" changed to "class Class;"
10324 return ();
10325 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010326 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010327 { # skip recursive declarations
10328 return ();
10329 }
10330 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10331 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10332 return () if($SkipTypes{1}{$Type1{"Name"}});
10333
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010334 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10335 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010336 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10337 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10338 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010339 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010340 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10341 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010342 if($Base_1{"Name"} ne $Base_2{"Name"})
10343 {
10344 if(differentDumps("G")
10345 or differentDumps("V"))
10346 { # different GCC versions or different dumps
10347 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10348 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10349 # std::__va_list and __va_list
10350 $Base_1{"Name"}=~s/\A(\w+::)+//;
10351 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010352 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10353 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010355 }
10356 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10357 and $Base_1{"Name"} ne $Base_2{"Name"})
10358 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010359 if($Level eq "Binary"
10360 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010361 {
10362 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10363 "Target"=>$Typedef_1{"Name"},
10364 "Type_Name"=>$Typedef_1{"Name"},
10365 "Type_Type"=>"Typedef",
10366 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10367 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10368 }
10369 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10370 "Target"=>$Typedef_1{"Name"},
10371 "Type_Name"=>$Typedef_1{"Name"},
10372 "Type_Type"=>"Typedef",
10373 "Old_Value"=>$Base_1{"Name"},
10374 "New_Value"=>$Base_2{"Name"} );
10375 }
10376 }
10377 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10378 { # different types (reported in detectTypeChange(...))
10379 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10380 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10381 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10382 { # different type of the type
10383 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10384 "Target"=>$Type1_Pure{"Name"},
10385 "Type_Name"=>$Type1_Pure{"Name"},
10386 "Type_Type"=>$Type1_Pure{"Type"},
10387 "Old_Value"=>lc($Type1_Pure{"Type"}),
10388 "New_Value"=>lc($Type2_Pure{"Type"}) );
10389 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010390 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010391 return %SubProblems;
10392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010393 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010394 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10395 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10396 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10397 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010398 if($Level eq "Binary"
10399 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010400 {
10401 my $ProblemKind = "DataType_Size";
10402 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010403 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010404 {
10405 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10406 $ProblemKind = "Size_Of_Copying_Class";
10407 }
10408 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10409 {
10410 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10411 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10412 }
10413 else {
10414 # descreased size of allocable class
10415 # it has no special effects
10416 }
10417 }
10418 }
10419 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10420 "Target"=>$Type1_Pure{"Name"},
10421 "Type_Name"=>$Type1_Pure{"Name"},
10422 "Type_Type"=>$Type1_Pure{"Type"},
10423 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10424 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10425 "InitialType_Type"=>$Type1_Pure{"Type"} );
10426 }
10427 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010428 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10429 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10430 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010431 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010432 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10433 {
10434 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10435 {
10436 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10437 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10438 }
10439 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10440 }
10441 }
10442 }
10443 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10444 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10445 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10446 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10447 { # detect removed and renamed fields
10448 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10449 next if(not $Member_Name);
10450 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);
10451 if($MemberPair_Pos eq "lost")
10452 {
10453 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10454 {
10455 if(isUnnamed($Member_Name))
10456 { # support for old-version dumps
10457 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010458 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010459 next;
10460 }
10461 }
10462 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10463 { # renamed
10464 $RenamedField{$Member_Pos}=$RenamedTo;
10465 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10466 }
10467 else
10468 { # removed
10469 $RemovedField{$Member_Pos}=1;
10470 }
10471 }
10472 elsif($Type1_Pure{"Type"} eq "Enum")
10473 {
10474 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10475 next if($Member_Value1 eq "");
10476 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10477 if($MemberPair_Pos ne "lost")
10478 { # renamed
10479 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10480 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10481 if($MemberPair_Pos_Rev eq "lost")
10482 {
10483 $RenamedField{$Member_Pos}=$RenamedTo;
10484 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10485 }
10486 else {
10487 $RemovedField{$Member_Pos}=1;
10488 }
10489 }
10490 else
10491 { # removed
10492 $RemovedField{$Member_Pos}=1;
10493 }
10494 }
10495 }
10496 else
10497 { # related
10498 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10499 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10500 }
10501 }
10502 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10503 { # detect added fields
10504 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10505 next if(not $Member_Name);
10506 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);
10507 if($MemberPair_Pos eq "lost")
10508 {
10509 if(isUnnamed($Member_Name))
10510 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010511 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010512 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010513 next;
10514 }
10515 }
10516 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10517 {
10518 if(not $RenamedField_Rev{$Member_Pos})
10519 { # added
10520 $AddedField{$Member_Pos}=1;
10521 }
10522 }
10523 }
10524 }
10525 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10526 { # detect moved fields
10527 my (%RelPos, %RelPosName, %AbsPos) = ();
10528 my $Pos = 0;
10529 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10530 { # relative positions in 1st version
10531 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10532 next if(not $Member_Name);
10533 if(not $RemovedField{$Member_Pos})
10534 { # old type without removed fields
10535 $RelPos{1}{$Member_Name}=$Pos;
10536 $RelPosName{1}{$Pos} = $Member_Name;
10537 $AbsPos{1}{$Pos++} = $Member_Pos;
10538 }
10539 }
10540 $Pos = 0;
10541 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10542 { # relative positions in 2nd version
10543 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10544 next if(not $Member_Name);
10545 if(not $AddedField{$Member_Pos})
10546 { # new type without added fields
10547 $RelPos{2}{$Member_Name}=$Pos;
10548 $RelPosName{2}{$Pos} = $Member_Name;
10549 $AbsPos{2}{$Pos++} = $Member_Pos;
10550 }
10551 }
10552 foreach my $Member_Name (keys(%{$RelPos{1}}))
10553 {
10554 my $RPos1 = $RelPos{1}{$Member_Name};
10555 my $AbsPos1 = $NameToPosA{$Member_Name};
10556 my $Member_Name2 = $Member_Name;
10557 if(my $RenamedTo = $RenamedField{$AbsPos1})
10558 { # renamed
10559 $Member_Name2 = $RenamedTo;
10560 }
10561 my $RPos2 = $RelPos{2}{$Member_Name2};
10562 if($RPos2 ne "" and $RPos1 ne $RPos2)
10563 { # different relative positions
10564 my $AbsPos2 = $NameToPosB{$Member_Name2};
10565 if($AbsPos1 ne $AbsPos2)
10566 { # different absolute positions
10567 my $ProblemType = "Moved_Field";
10568 if(not isPublic(\%Type1_Pure, $AbsPos1))
10569 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010570 if($Level eq "Source") {
10571 next;
10572 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010573 $ProblemType = "Moved_Private_Field";
10574 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010575 if($Level eq "Binary"
10576 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010577 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010578 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010579 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010580 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010581 if($MemSize1 ne $MemSize2) {
10582 $ProblemType .= "_And_Size";
10583 }
10584 }
10585 if($ProblemType eq "Moved_Private_Field") {
10586 next;
10587 }
10588 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10589 "Target"=>$Member_Name,
10590 "Type_Name"=>$Type1_Pure{"Name"},
10591 "Type_Type"=>$Type1_Pure{"Type"},
10592 "Old_Value"=>$RPos1,
10593 "New_Value"=>$RPos2 );
10594 }
10595 }
10596 }
10597 }
10598 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010599 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010600 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10601 next if(not $Member_Name);
10602 if(my $RenamedTo = $RenamedField{$Member_Pos})
10603 { # renamed
10604 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10605 {
10606 if(isPublic(\%Type1_Pure, $Member_Pos))
10607 {
10608 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10609 "Target"=>$Member_Name,
10610 "Type_Name"=>$Type1_Pure{"Name"},
10611 "Type_Type"=>$Type1_Pure{"Type"},
10612 "Old_Value"=>$Member_Name,
10613 "New_Value"=>$RenamedTo );
10614 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010615 elsif(isReserved($Member_Name))
10616 {
10617 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10618 "Target"=>$Member_Name,
10619 "Type_Name"=>$Type1_Pure{"Name"},
10620 "Type_Type"=>$Type1_Pure{"Type"},
10621 "Old_Value"=>$Member_Name,
10622 "New_Value"=>$RenamedTo );
10623 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010624 }
10625 elsif($Type1_Pure{"Type"} eq "Enum")
10626 {
10627 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10628 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10629 "Type_Name"=>$Type1_Pure{"Name"},
10630 "Type_Type"=>$Type1_Pure{"Type"},
10631 "Old_Value"=>$Member_Name,
10632 "New_Value"=>$RenamedTo );
10633 }
10634 }
10635 elsif($RemovedField{$Member_Pos})
10636 { # removed
10637 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10638 {
10639 my $ProblemType = "Removed_Field";
10640 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010641 or isUnnamed($Member_Name))
10642 {
10643 if($Level eq "Source") {
10644 next;
10645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010646 $ProblemType = "Removed_Private_Field";
10647 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010648 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010649 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010650 {
10651 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10652 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010653 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 +040010654 { # changed offset
10655 $ProblemType .= "_And_Layout";
10656 }
10657 }
10658 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10659 { # affected size
10660 $ProblemType .= "_And_Size";
10661 }
10662 }
10663 if($ProblemType eq "Removed_Private_Field") {
10664 next;
10665 }
10666 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10667 "Target"=>$Member_Name,
10668 "Type_Name"=>$Type1_Pure{"Name"},
10669 "Type_Type"=>$Type1_Pure{"Type"} );
10670 }
10671 elsif($Type2_Pure{"Type"} eq "Union")
10672 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010673 if($Level eq "Binary"
10674 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010675 {
10676 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10677 "Target"=>$Member_Name,
10678 "Type_Name"=>$Type1_Pure{"Name"},
10679 "Type_Type"=>$Type1_Pure{"Type"} );
10680 }
10681 else
10682 {
10683 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10684 "Target"=>$Member_Name,
10685 "Type_Name"=>$Type1_Pure{"Name"},
10686 "Type_Type"=>$Type1_Pure{"Type"} );
10687 }
10688 }
10689 elsif($Type1_Pure{"Type"} eq "Enum")
10690 {
10691 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10692 "Target"=>$Member_Name,
10693 "Type_Name"=>$Type1_Pure{"Name"},
10694 "Type_Type"=>$Type1_Pure{"Type"},
10695 "Old_Value"=>$Member_Name );
10696 }
10697 }
10698 else
10699 { # changed
10700 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10701 if($Type1_Pure{"Type"} eq "Enum")
10702 {
10703 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10704 next if($Member_Value1 eq "");
10705 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10706 next if($Member_Value2 eq "");
10707 if($Member_Value1 ne $Member_Value2)
10708 {
10709 my $ProblemType = "Enum_Member_Value";
10710 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10711 $ProblemType = "Enum_Last_Member_Value";
10712 }
10713 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10714 "Target"=>$Member_Name,
10715 "Type_Name"=>$Type1_Pure{"Name"},
10716 "Type_Type"=>$Type1_Pure{"Type"},
10717 "Old_Value"=>$Member_Value1,
10718 "New_Value"=>$Member_Value2 );
10719 }
10720 }
10721 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10722 {
10723 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10724 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010725 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010726 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10727 $SizeV1 = $BSize1;
10728 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010729 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010730 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10731 $SizeV2 = $BSize2;
10732 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010733 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10734 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010735 if($Level eq "Binary"
10736 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010737 {
10738 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10739 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10740 { # field size change (including anon-structures and unions)
10741 # - same types
10742 # - unnamed types
10743 # - bitfields
10744 my $ProblemType = "Field_Size";
10745 if(not isPublic(\%Type1_Pure, $Member_Pos)
10746 or isUnnamed($Member_Name))
10747 { # should not be accessed by applications, goes to "Low Severity"
10748 # example: "abidata" members in GStreamer types
10749 $ProblemType = "Private_".$ProblemType;
10750 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010751 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 +040010752 { # check an effect
10753 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10754 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010755 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 +040010756 { # changed offset
10757 $ProblemType .= "_And_Layout";
10758 }
10759 }
10760 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10761 $ProblemType .= "_And_Type_Size";
10762 }
10763 }
10764 if($ProblemType eq "Private_Field_Size")
10765 { # private field size with no effect
10766 $ProblemType = "";
10767 }
10768 if($ProblemType)
10769 { # register a problem
10770 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10771 "Target"=>$Member_Name,
10772 "Type_Name"=>$Type1_Pure{"Name"},
10773 "Type_Type"=>$Type1_Pure{"Type"},
10774 "Old_Size"=>$SizeV1,
10775 "New_Size"=>$SizeV2);
10776 }
10777 }
10778 }
10779 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10780 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10781 { # do NOT check bitfield type changes
10782 next;
10783 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010784 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010785 {
10786 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10787 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10788 {
10789 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10790 "Target"=>$Member_Name,
10791 "Type_Name"=>$Type1_Pure{"Name"},
10792 "Type_Type"=>$Type1_Pure{"Type"});
10793 }
10794 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10795 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10796 {
10797 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10798 "Target"=>$Member_Name,
10799 "Type_Name"=>$Type1_Pure{"Name"},
10800 "Type_Type"=>$Type1_Pure{"Type"});
10801 }
10802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010803 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010804 foreach my $ProblemType (keys(%Sub_SubProblems))
10805 {
10806 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10807 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10808 if($ProblemType eq "Field_Type"
10809 or $ProblemType eq "Field_Type_And_Size")
10810 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010811 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010812 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010813 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010814 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010815 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10816 if($Level eq "Source"
10817 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10818 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010819 }
10820 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010821 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10822 {
10823 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10824 if($Level eq "Source"
10825 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010826 delete($Sub_SubProblems{$ProblemType});
10827 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010828 }
10829 }
10830 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10831 {
10832 if($RA==2) {
10833 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10834 }
10835 else {
10836 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10837 }
10838 if($Level eq "Source"
10839 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10840 delete($Sub_SubProblems{$ProblemType});
10841 }
10842 }
10843 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10844 {
10845 if($RR==2) {
10846 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10847 }
10848 else {
10849 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10850 }
10851 if($Level eq "Source"
10852 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10853 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010854 }
10855 }
10856 }
10857 }
10858 foreach my $ProblemType (keys(%Sub_SubProblems))
10859 {
10860 my $ProblemType_Init = $ProblemType;
10861 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010862 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010863 if(not isPublic(\%Type1_Pure, $Member_Pos)
10864 or isUnnamed($Member_Name)) {
10865 $ProblemType = "Private_".$ProblemType;
10866 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010867 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 +040010868 { # check an effect
10869 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10870 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010871 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 +040010872 { # changed offset
10873 $ProblemType .= "_And_Layout";
10874 }
10875 }
10876 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10877 $ProblemType .= "_And_Type_Size";
10878 }
10879 }
10880 }
10881 else
10882 {
10883 if(not isPublic(\%Type1_Pure, $Member_Pos)
10884 or isUnnamed($Member_Name)) {
10885 next;
10886 }
10887 }
10888 if($ProblemType eq "Private_Field_Type_And_Size")
10889 { # private field change with no effect
10890 next;
10891 }
10892 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10893 "Target"=>$Member_Name,
10894 "Type_Name"=>$Type1_Pure{"Name"},
10895 "Type_Type"=>$Type1_Pure{"Type"} );
10896 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10897 { # other properties
10898 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10899 }
10900 }
10901 if(not isPublic(\%Type1_Pure, $Member_Pos))
10902 { # do NOT check internal type changes
10903 next;
10904 }
10905 if($MemberType1_Id and $MemberType2_Id)
10906 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010907 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010908 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10909 {
10910 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10911 {
10912 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10913 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10914 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10915 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10916 }
10917 if($Sub_SubLocation!~/\-\>/) {
10918 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10919 }
10920 }
10921 }
10922 }
10923 }
10924 }
10925 }
10926 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10927 { # checking added members, public and private
10928 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10929 next if(not $Member_Name);
10930 if($AddedField{$Member_Pos})
10931 { # added
10932 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10933 {
10934 my $ProblemType = "Added_Field";
10935 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010936 or isUnnamed($Member_Name))
10937 {
10938 if($Level eq "Source") {
10939 next;
10940 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010941 $ProblemType = "Added_Private_Field";
10942 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010943 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010944 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010945 {
10946 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10947 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010948 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 +040010949 { # changed offset
10950 $ProblemType .= "_And_Layout";
10951 }
10952 }
10953 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10954 $ProblemType .= "_And_Size";
10955 }
10956 }
10957 if($ProblemType eq "Added_Private_Field")
10958 { # skip added private fields
10959 next;
10960 }
10961 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10962 "Target"=>$Member_Name,
10963 "Type_Name"=>$Type1_Pure{"Name"},
10964 "Type_Type"=>$Type1_Pure{"Type"} );
10965 }
10966 elsif($Type2_Pure{"Type"} eq "Union")
10967 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010968 if($Level eq "Binary"
10969 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010970 {
10971 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10972 "Target"=>$Member_Name,
10973 "Type_Name"=>$Type1_Pure{"Name"},
10974 "Type_Type"=>$Type1_Pure{"Type"} );
10975 }
10976 else
10977 {
10978 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10979 "Target"=>$Member_Name,
10980 "Type_Name"=>$Type1_Pure{"Name"},
10981 "Type_Type"=>$Type1_Pure{"Type"} );
10982 }
10983 }
10984 elsif($Type2_Pure{"Type"} eq "Enum")
10985 {
10986 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10987 next if($Member_Value eq "");
10988 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10989 "Target"=>$Member_Name,
10990 "Type_Name"=>$Type2_Pure{"Name"},
10991 "Type_Type"=>$Type2_Pure{"Type"},
10992 "New_Value"=>$Member_Value );
10993 }
10994 }
10995 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010996 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010997 pop(@RecurTypes);
10998 return %SubProblems;
10999}
11000
11001sub isUnnamed($) {
11002 return $_[0]=~/\Aunnamed\d+\Z/;
11003}
11004
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011005sub get_ShortType($$)
11006{
11007 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011008 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011009 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011010 $TypeName=~s/\A$NameSpace\:\://g;
11011 }
11012 return $TypeName;
11013}
11014
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011015sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011016{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011017 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011018 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011019 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11020 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011021 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011022 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11023 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011024 return () if(not $Type{"Type"});
11025 if($Type{"Type"} ne $Type_Type)
11026 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011027 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011028 return () if(not $Type{"BaseType"}{"Tid"});
11029 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011030 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011031 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011032 return %Type;
11033}
11034
11035my %TypeSpecAttributes = (
11036 "Const" => 1,
11037 "Volatile" => 1,
11038 "ConstVolatile" => 1,
11039 "Restrict" => 1,
11040 "Typedef" => 1
11041);
11042
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011043sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011044{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011045 my ($TypeId, $Info) = @_;
11046 if(not $TypeId or not $Info
11047 or not $Info->{$TypeId}) {
11048 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011049 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011050 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11051 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11052 }
11053 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011054 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011055 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011056 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011057 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011058 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011059 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011060 return %Type;
11061}
11062
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011063sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011064{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011065 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011066 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011067 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11068 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011069 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011070 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11071 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011072 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011073 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011074 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011075 my $PointerLevel = 0;
11076 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11077 $PointerLevel += 1;
11078 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011079 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11080 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011081 return $PointerLevel;
11082}
11083
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011084sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011085{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011086 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011087 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011088 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11089 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011091 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11092 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011093 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011094 return %Type if(not $Type{"BaseType"}{"Tid"});
11095 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11096 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011097 return %Type;
11098}
11099
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011100sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011101{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011102 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011103 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011104 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11105 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011106 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011107 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011108 my $Qual = "";
11109 if($Type{"Type"} eq "Pointer") {
11110 $Qual .= "*";
11111 }
11112 elsif($Type{"Type"} eq "Ref") {
11113 $Qual .= "&";
11114 }
11115 elsif($Type{"Type"} eq "ConstVolatile") {
11116 $Qual .= "const volatile";
11117 }
11118 elsif($Type{"Type"} eq "Const"
11119 or $Type{"Type"} eq "Volatile"
11120 or $Type{"Type"} eq "Restrict") {
11121 $Qual .= lc($Type{"Type"});
11122 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011123 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011124 return $BQual.$Qual;
11125}
11126
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011127sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011128{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011129 my ($TypeId, $Info) = @_;
11130 if(not $TypeId or not $Info
11131 or not $Info->{$TypeId}) {
11132 return ();
11133 }
11134 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011135 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011136 if(my $BTid = $Type{"BaseType"}{"Tid"})
11137 {
11138 if($Info->{$BTid}) {
11139 return %{$Info->{$BTid}};
11140 }
11141 else { # something is going wrong
11142 return ();
11143 }
11144 }
11145 else {
11146 return %Type;
11147 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011148}
11149
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011150sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011151{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011152 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011153 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011154 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11155 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011156}
11157
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011158sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011159{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011160 my $Symbol = $_[0];
11161 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11162}
11163
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011164sub isInLineInst($$$) {
11165 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11166}
11167
11168sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011170 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011171 if($CheckObjectsOnly)
11172 {
11173 if($Symbol!~/\A(_Z|\?)/) {
11174 return 0;
11175 }
11176 if(my $Signature = $tr_name{$Symbol})
11177 {
11178 if(index($Signature,">")==-1) {
11179 return 0;
11180 }
11181 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11182 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011183 if(index($ShortName,"<")!=-1
11184 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011185 return 1;
11186 }
11187 }
11188 }
11189 }
11190 else
11191 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011192 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011193 {
11194 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11195 {
11196 if(index($ClassName,"<")!=-1) {
11197 return 1;
11198 }
11199 }
11200 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011201 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011202 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011203 if(index($ShortName,"<")!=-1
11204 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011205 return 1;
11206 }
11207 }
11208 }
11209 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011210}
11211
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011212sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011214 my ($Symbol, $SInfo, $LibVersion) = @_;
11215 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011216 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011217 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011218 { # class specialization
11219 return 1;
11220 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011221 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011222 { # method specialization
11223 return 1;
11224 }
11225 }
11226 return 0;
11227}
11228
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011229sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011230{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011231 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011232 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011233 { # non-public global data
11234 return 0;
11235 }
11236 if($CheckObjectsOnly) {
11237 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011239 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011240 { # support for old ABI dumps in --headers-only mode
11241 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11242 {
11243 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11244 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011245 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011246 if(not $PType or $PType eq "Unknown") {
11247 return 0;
11248 }
11249 }
11250 }
11251 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011252 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011253 {
11254 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011255 if($SkipSymbols{$LibVersion}{$Symbol})
11256 { # user defined symbols to ignore
11257 return 0;
11258 }
11259 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11260 if(not $NameSpace and $ClassId)
11261 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011262 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011263 }
11264 if($NameSpace)
11265 { # user defined namespaces to ignore
11266 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11267 return 0;
11268 }
11269 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11270 { # nested namespaces
11271 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11272 return 0;
11273 }
11274 }
11275 }
11276 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11277 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011278 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011279 { # --skip-headers or <skip_headers> (not <skip_including>)
11280 if($Skip==1) {
11281 return 0;
11282 }
11283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011284 }
11285 if($SymbolsListPath and not $SymbolsList{$Symbol})
11286 { # user defined symbols
11287 return 0;
11288 }
11289 if($AppPath and not $SymbolsList_App{$Symbol})
11290 { # user defined symbols (in application)
11291 return 0;
11292 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011293 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11294 { # non-target symbols
11295 return 0;
11296 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011297 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011298 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011299 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011300 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011301 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011302 return 0;
11303 }
11304 }
11305 else
11306 {
11307 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011308 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011309 {
11310 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11311 { # inline virtual methods
11312 if($Type=~/InlineVirt/) {
11313 return 1;
11314 }
11315 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11316 if(not $Allocable)
11317 { # check bases
11318 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11319 {
11320 if(not isCopyingClass($DCId, $LibVersion))
11321 { # exists a derived class without default c-tor
11322 $Allocable=1;
11323 last;
11324 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011325 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011326 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011327 if(not $Allocable) {
11328 return 0;
11329 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011330 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011331 else
11332 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011333 return 0;
11334 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011335 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011336 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011337 }
11338 }
11339 return 1;
11340}
11341
11342sub mergeImpl()
11343{
11344 my $DiffCmd = get_CmdPath("diff");
11345 if(not $DiffCmd) {
11346 exitStatus("Not_Found", "can't find \"diff\"");
11347 }
11348 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11349 { # implementation changes
11350 next if($CompleteSignature{1}{$Interface}{"Private"});
11351 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11352 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011353 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11354 next;
11355 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011356 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011357 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011358 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011359 next if(not $Impl2);
11360 if($Impl1 ne $Impl2)
11361 {
11362 writeFile("$TMP_DIR/impl1", $Impl1);
11363 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011364 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011365 $Diff=~s/(---|\+\+\+).+\n//g;
11366 $Diff=~s/[ ]{3,}/ /g;
11367 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011368 unlink("$TMP_DIR/impl1");
11369 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011370 %{$ImplProblems{$Interface}}=(
11371 "Diff" => get_CodeView($Diff) );
11372 }
11373 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011374
11375 # clean memory
11376 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011377}
11378
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011379sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011380{
11381 my $FuncBody= $_[0];
11382 return "" if(not $FuncBody);
11383 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11384 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11385 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11386 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11387 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11388 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11389 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11390 $FuncBody=~s/\.L\d+/.L/g;
11391 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11392 $FuncBody=~s/[\n]{2,}/\n/g;
11393 return $FuncBody;
11394}
11395
11396sub get_CodeView($)
11397{
11398 my $Code = $_[0];
11399 my $View = "";
11400 foreach my $Line (split(/\n/, $Code))
11401 {
11402 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011403 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011404 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11405 }
11406 else {
11407 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11408 }
11409 }
11410 return "<table class='code_view'>$View</table>\n";
11411}
11412
11413sub getImplementations($$)
11414{
11415 my ($LibVersion, $Path) = @_;
11416 return if(not $LibVersion or not -e $Path);
11417 if($OSgroup eq "macos")
11418 {
11419 my $OtoolCmd = get_CmdPath("otool");
11420 if(not $OtoolCmd) {
11421 exitStatus("Not_Found", "can't find \"otool\"");
11422 }
11423 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011424 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011425 {
11426 if($Line=~/\A\s*_(\w+)\s*:/i) {
11427 $CurInterface = $1;
11428 }
11429 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011430 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011431 }
11432 }
11433 }
11434 else
11435 {
11436 my $ObjdumpCmd = get_CmdPath("objdump");
11437 if(not $ObjdumpCmd) {
11438 exitStatus("Not_Found", "can't find \"objdump\"");
11439 }
11440 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011441 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011442 {
11443 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11444 $CurInterface = $1;
11445 }
11446 else
11447 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11448 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11449 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 +040011450 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011451 }
11452 }
11453 }
11454 }
11455}
11456
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011457sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011458{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011459 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011460 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11461 {
11462 if(link_symbol($Symbol, 1, "+Deps"))
11463 { # linker can find a new symbol
11464 # in the old-version library
11465 # So, it's not a new symbol
11466 next;
11467 }
11468 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011469 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011470 next;
11471 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011472 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011473 }
11474}
11475
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011476sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011477{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011478 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011479 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11480 {
11481 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011482 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011483 }
11484 if(link_symbol($Symbol, 2, "+Deps"))
11485 { # linker can find an old symbol
11486 # in the new-version library
11487 next;
11488 }
11489 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011490 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011491 next;
11492 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011493 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011494 }
11495}
11496
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011497sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011498{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011499 my $Level = $_[0];
11500 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011501 { # checking added symbols
11502 next if($CompleteSignature{2}{$Symbol}{"Private"});
11503 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011504 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011505 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011506 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011507 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011508 { # checking removed symbols
11509 next if($CompleteSignature{1}{$Symbol}{"Private"});
11510 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011511 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011512 { # skip v-tables for templates, that should not be imported by applications
11513 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011514 if(my $CName = $VTableClass{$Symbol})
11515 {
11516 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11517 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011518 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011519 next;
11520 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521 }
11522 }
11523 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011524 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011525 }
11526 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11527 { # symbols for pure virtual methods cannot be called by clients
11528 next;
11529 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011530 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011531 }
11532}
11533
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011534sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011535{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011536 my ($LibVersion, $V) = @_;
11537 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11538 return $Cache{"checkDump"}{$LibVersion}{$V};
11539 }
11540 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011541}
11542
11543sub detectAdded_H($)
11544{
11545 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011546 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11547 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011548 if($Level eq "Source")
11549 { # remove symbol version
11550 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11551 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011552
11553 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11554 { # skip artificial constructors
11555 next;
11556 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011557 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011558 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11559 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011560 next;
11561 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011562 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011563 next;
11564 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011565 if(not defined $CompleteSignature{1}{$Symbol}
11566 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11567 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011568 if($UsedDump{2}{"SrcBin"})
11569 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011570 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011571 { # support for old and different (!) ABI dumps
11572 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11573 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011574 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011575 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011576 {
11577 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11578 {
11579 if($Lang eq "C")
11580 { # support for old ABI dumps: missed extern "C" functions
11581 next;
11582 }
11583 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011584 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011585 else
11586 {
11587 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011588 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011589 next;
11590 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011591 }
11592 }
11593 }
11594 }
11595 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011596 }
11597 }
11598}
11599
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011600sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011601{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011602 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011603 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11604 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011605 if($Level eq "Source")
11606 { # remove symbol version
11607 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11608 $Symbol=$SN;
11609 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011610 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11611 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011612 next;
11613 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011614 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011615 next;
11616 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011617 if(not defined $CompleteSignature{2}{$Symbol}
11618 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011619 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011620 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011621 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011622 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011623 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011624 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11625 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011626 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011627 if($CheckHeadersOnly)
11628 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011629 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11630 {
11631 if($Lang eq "C")
11632 { # support for old ABI dumps: missed extern "C" functions
11633 next;
11634 }
11635 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011637 else
11638 {
11639 if(not link_symbol($Symbol, 1, "-Deps"))
11640 { # skip removed inline symbols
11641 next;
11642 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011643 }
11644 }
11645 }
11646 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011647 if(not checkDump(1, "2.15"))
11648 {
11649 if($Symbol=~/_IT_E\Z/)
11650 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11651 next;
11652 }
11653 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011654 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11655 {
11656 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11657 {
11658 if(defined $Constants{2}{$Short})
11659 {
11660 my $Val = $Constants{2}{$Short}{"Value"};
11661 if(defined $Func_ShortName{2}{$Val})
11662 { # old name defined to new
11663 next;
11664 }
11665 }
11666 }
11667
11668 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011669 $RemovedInt{$Level}{$Symbol} = 1;
11670 if($Level eq "Source")
11671 { # search for a source-compatible equivalent
11672 setAlternative($Symbol, $Level);
11673 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011674 }
11675 }
11676}
11677
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011678sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011679{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011680 my $Level = $_[0];
11681 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011682 { # checking added symbols
11683 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011684 next if($CompleteSignature{2}{$Symbol}{"Private"});
11685 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011686 if($Level eq "Binary")
11687 {
11688 if($CompleteSignature{2}{$Symbol}{"InLine"})
11689 {
11690 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11691 { # skip inline non-virtual functions
11692 next;
11693 }
11694 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011695 }
11696 else
11697 { # Source
11698 if($SourceAlternative_B{$Symbol}) {
11699 next;
11700 }
11701 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011702 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011703 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011704 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011705 { # checking removed symbols
11706 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011707 next if($CompleteSignature{1}{$Symbol}{"Private"});
11708 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011709 if($Level eq "Binary")
11710 {
11711 if($CompleteSignature{1}{$Symbol}{"InLine"})
11712 {
11713 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11714 { # skip inline non-virtual functions
11715 next;
11716 }
11717 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011718 }
11719 else
11720 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011721 if(my $Alt = $SourceAlternative{$Symbol})
11722 {
11723 if(defined $CompleteSignature{1}{$Alt}
11724 and $CompleteSignature{1}{$Symbol}{"Const"})
11725 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011726 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011727 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011728 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011729 "Type_Type"=>"Class",
11730 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011731 }
11732 else
11733 { # do NOT show removed symbol
11734 next;
11735 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011736 }
11737 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011738 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011739 }
11740}
11741
11742sub addParamNames($)
11743{
11744 my $LibraryVersion = $_[0];
11745 return if(not keys(%AddIntParams));
11746 my $SecondVersion = $LibraryVersion==1?2:1;
11747 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11748 {
11749 next if(not keys(%{$AddIntParams{$Interface}}));
11750 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011751 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011752 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11753 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011754 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011755 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11756 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11757 {
11758 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11759 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11760 }
11761 }
11762 else {
11763 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11764 }
11765 }
11766 }
11767 }
11768}
11769
11770sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011771{ # detect changed typedefs to show
11772 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011773 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11774 {
11775 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011776 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11777 if(not $BName1 or isAnon($BName1)) {
11778 next;
11779 }
11780 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11781 if(not $BName2 or isAnon($BName2)) {
11782 next;
11783 }
11784 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011785 $ChangedTypedef{$Typedef} = 1;
11786 }
11787 }
11788}
11789
11790sub get_symbol_suffix($$)
11791{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011792 my ($Symbol, $Full) = @_;
11793 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11794 $Symbol=$SN;# remove version
11795 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011796 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011797 if(not $Full) {
11798 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11799 }
11800 return $Suffix;
11801}
11802
11803sub get_symbol_prefix($$)
11804{
11805 my ($Symbol, $LibVersion) = @_;
11806 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11807 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11808 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011809 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011810 }
11811 return $ShortName;
11812}
11813
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011814sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011815{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011816 my $Symbol = $_[0];
11817 my $PSymbol = $Symbol;
11818 if(not defined $CompleteSignature{2}{$PSymbol}
11819 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11820 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11821 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011822 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011823 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011824 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011825 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011826 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11827 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011828 {
11829 if(defined $CompleteSignature{2}{$PSymbol}
11830 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11831 {
11832 $SourceAlternative{$Symbol} = $PSymbol;
11833 $SourceAlternative_B{$PSymbol} = $Symbol;
11834 if(not defined $CompleteSignature{1}{$PSymbol}
11835 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11836 $SourceReplacement{$Symbol} = $PSymbol;
11837 }
11838 }
11839 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011840 }
11841 else
11842 {
11843 foreach my $Sp ("KV", "VK", "K", "V")
11844 {
11845 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11846 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11847 {
11848 if(defined $CompleteSignature{2}{$PSymbol}
11849 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11850 {
11851 $SourceAlternative{$Symbol} = $PSymbol;
11852 $SourceAlternative_B{$PSymbol} = $Symbol;
11853 if(not defined $CompleteSignature{1}{$PSymbol}
11854 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11855 $SourceReplacement{$Symbol} = $PSymbol;
11856 }
11857 }
11858 }
11859 $PSymbol = $Symbol;
11860 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011861 }
11862 }
11863 }
11864 return "";
11865}
11866
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011867sub getSymKind($$)
11868{
11869 my ($Symbol, $LibVersion) = @_;
11870 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11871 {
11872 return "Global_Data";
11873 }
11874 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11875 {
11876 return "Method";
11877 }
11878 return "Function";
11879}
11880
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011881sub mergeSignatures($)
11882{
11883 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011884 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011885
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011886 mergeBases($Level);
11887
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011888 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011889 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011890 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011891 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011892 next;
11893 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011894 if(defined $CompleteSignature{1}{$Symbol}
11895 and $CompleteSignature{1}{$Symbol}{"Header"})
11896 { # double-check added symbol
11897 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011898 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011899 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011900 next;
11901 }
11902 if($Symbol=~/\A(_Z|\?)/)
11903 { # C++
11904 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11905 }
11906 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11907 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011908 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11909 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011910 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011911 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011912 {
11913 if($TName_Tid{1}{$AffectedClass_Name})
11914 { # class should exist in previous version
11915 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11916 { # old v-table is NOT copied by old applications
11917 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11918 "Type_Name"=>$AffectedClass_Name,
11919 "Type_Type"=>"Class",
11920 "Target"=>get_Signature($Symbol, 2),
11921 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11922 "New_Value"=>get_Signature($Symbol, 2) );
11923 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011924 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011925 }
11926 }
11927 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011928 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11929 { # check all removed exported symbols
11930 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011931 next;
11932 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011933 if(defined $CompleteSignature{2}{$Symbol}
11934 and $CompleteSignature{2}{$Symbol}{"Header"})
11935 { # double-check removed symbol
11936 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011937 }
11938 if($CompleteSignature{1}{$Symbol}{"Private"})
11939 { # skip private methods
11940 next;
11941 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011942 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011943 next;
11944 }
11945 $CheckedSymbols{$Level}{$Symbol} = 1;
11946 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11947 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011948 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11949 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011950 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011951 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11952 {
11953 if($TName_Tid{2}{$AffectedClass_Name})
11954 { # class should exist in newer version
11955 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11956 { # old v-table is NOT copied by old applications
11957 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11958 "Type_Name"=>$AffectedClass_Name,
11959 "Type_Type"=>"Class",
11960 "Target"=>get_Signature($OverriddenMethod, 1),
11961 "Old_Value"=>get_Signature($Symbol, 1),
11962 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11963 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011964 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011965 }
11966 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011967 if($Level eq "Binary"
11968 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011969 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011970 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011971 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011972 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011973 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011974 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011975 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011976 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011977 {
11978 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11979 "Target"=>$tr_name{$Symbol},
11980 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011981 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011982 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011983 else
11984 {
11985 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11986 "Target"=>$tr_name{$Symbol},
11987 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011988 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011989 }
11990 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011991 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011992 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011993 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011994 {
11995 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11996 "Target"=>$tr_name{$Symbol},
11997 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011998 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011999 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012000 else
12001 {
12002 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12003 "Target"=>$tr_name{$Symbol},
12004 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012005 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012006 }
12007 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012008 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12009 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12010 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12011 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12012 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012013 {
12014 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012015 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012016 $ProblemType = "Global_Data_Symbol_Changed_Type";
12017 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012018 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12019 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012020 "Old_Type"=>$RTName1,
12021 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012022 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012023 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012024 }
12025 }
12026 }
12027 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012028 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012029 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012030 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012031 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012032 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012033 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012034 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012035 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12036 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012037 if($Symbol=~/(C1E|C2E)/)
12038 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012039 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012040 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012041 }
12042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012043 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12044 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012045 if($Symbol=~/(D0E|D1E|D2E)/)
12046 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012047 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012048 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012049 }
12050 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012051 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012052 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012053 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012054 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012055 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012056 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012057 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012058 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012059 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012060 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012061 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012062 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012063 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012064 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012065 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012066 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012067 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012068 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012069 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012070 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012071 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012072 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012073 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012074 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012075 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012076 { # "volatile" to non-"volatile"
12077
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012078 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012079 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012080 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012081 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012082 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012083 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012084 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012085 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012086 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012087 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012088 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012089 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012090 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012091 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012092 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012093 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012094 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012095 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12096 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012097 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012098 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012099 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012100 }
12101 }
12102 }
12103 }
12104 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012105 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12106 { # checking symbols
12107 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12108 if($Level eq "Source")
12109 { # remove symbol version
12110 $Symbol=$SN;
12111 }
12112 else
12113 { # Binary
12114 if(not $SV)
12115 { # symbol without version
12116 if(my $VSym = $SymVer{1}{$Symbol})
12117 { # the symbol is linked with versioned symbol
12118 if($CompleteSignature{2}{$VSym}{"MnglName"})
12119 { # show report for symbol@ver only
12120 next;
12121 }
12122 elsif(not link_symbol($VSym, 2, "-Deps"))
12123 { # changed version: sym@v1 to sym@v2
12124 # do NOT show report for symbol
12125 next;
12126 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 }
12128 }
12129 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012130 my $PSymbol = $Symbol;
12131 if($Level eq "Source"
12132 and my $S = $SourceReplacement{$Symbol})
12133 { # take a source-compatible replacement function
12134 $PSymbol = $S;
12135 }
12136 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012137 { # private symbols
12138 next;
12139 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012140 if(not defined $CompleteSignature{1}{$Symbol}
12141 or not defined $CompleteSignature{2}{$PSymbol})
12142 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012143 next;
12144 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012145 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12146 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12147 { # no mangled name
12148 next;
12149 }
12150 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12151 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012152 { # without a header
12153 next;
12154 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012155
12156 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12157 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12158 { # became pure
12159 next;
12160 }
12161 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12162 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12163 { # became non-pure
12164 next;
12165 }
12166
12167 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12168 { # exported, target, inline virtual and pure virtual
12169 next;
12170 }
12171 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12172 { # exported, target, inline virtual and pure virtual
12173 next;
12174 }
12175
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012176 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012177 {
12178 if($CompleteSignature{1}{$Symbol}{"Data"}
12179 and $CompleteSignature{2}{$PSymbol}{"Data"})
12180 {
12181 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12182 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12183 if(defined $Value1)
12184 {
12185 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12186 if(defined $Value2)
12187 {
12188 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12189 if($Value1 ne $Value2)
12190 {
12191 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12192 "Old_Value"=>$Value1,
12193 "New_Value"=>$Value2,
12194 "Target"=>get_Signature($Symbol, 1) );
12195 }
12196 }
12197 }
12198 }
12199 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012200
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012201 if($CompleteSignature{2}{$PSymbol}{"Private"})
12202 {
12203 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12204 "Target"=>get_Signature_M($PSymbol, 2) );
12205 }
12206 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12207 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12208 {
12209 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12210 "Target"=>get_Signature_M($PSymbol, 2) );
12211 }
12212 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12213 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12214 {
12215 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12216 "Target"=>get_Signature_M($PSymbol, 2) );
12217 }
12218
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012219 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012220 mergeVirtualTables($Symbol, $Level);
12221
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012222 if($COMPILE_ERRORS)
12223 { # if some errors occurred at the compiling stage
12224 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012225 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012226 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012227 { # missed information about parameters in newer version
12228 next;
12229 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012230 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012231 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012232 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012233 next;
12234 }
12235 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012236 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012237 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012238 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012239 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12240 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012241 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12242 "Target"=>get_Signature($Symbol, 1)
12243 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012244 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012245 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012246 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12247 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012248 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12249 "Target"=>get_Signature($Symbol, 1)
12250 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012252 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12253 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012254 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012255 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012256 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012257 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12258 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12259 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012260 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012261 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012262 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12263 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012264 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012265 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012266 my $ProblemType = "Virtual_Method_Position";
12267 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12268 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012269 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012270 if(isUsedClass($Class_Id, 1, $Level))
12271 {
12272 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012273 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012274 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012275 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12276 next;
12277 }
12278 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012279 "Type_Name"=>$Class_Type{"Name"},
12280 "Type_Type"=>"Class",
12281 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12282 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12283 "Target"=>get_Signature($Symbol, 1) );
12284 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012285 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012286 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012287 }
12288 }
12289 }
12290 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012291 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12292 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012293 { # do NOT check type changes in pure virtuals
12294 next;
12295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012296 $CheckedSymbols{$Level}{$Symbol}=1;
12297 if($Symbol=~/\A(_Z|\?)/
12298 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012299 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012300 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012301 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012302 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012303 }
12304 }
12305 else
12306 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012307 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012308 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012309 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012310 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12311 last if($PType2_Name eq "...");
12312 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12313 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012314 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012315 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012316 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012317 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12318 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012319 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12320 $ParamPos_Prev = "lost";
12321 }
12322 }
12323 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012324 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012325 }
12326 if($ParamPos_Prev eq "lost")
12327 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012328 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012329 {
12330 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012331 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012332 $ProblemType = "Added_Unnamed_Parameter";
12333 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012334 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012335 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012336 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012337 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012338 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012339 }
12340 else
12341 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012342 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012343 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012344 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012345 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12346 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012347 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012348 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012349 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012350 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012351 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012352 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012353 "Param_Type"=>$PType2_Name,
12354 "Old_Value"=>$PName_Old,
12355 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012356 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012357 }
12358 }
12359 else
12360 {
12361 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012362 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012363 $ProblemType = "Added_Middle_Unnamed_Parameter";
12364 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012365 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012366 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012367 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012368 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012369 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012370 }
12371 }
12372 }
12373 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012374 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012375 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012376 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012377 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012378 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012379 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012380 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012381 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012382 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012383 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12384 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012385 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012386 }
12387 }
12388 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012389 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012390 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012391 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012392 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12393 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012394 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12395 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012396 my $ParamPos_New = "-1";
12397 if($Parameter_Name=~/\Ap\d+\Z/i)
12398 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012399 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12400 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012401 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12402 $ParamPos_New = "lost";
12403 }
12404 }
12405 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012406 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012407 }
12408 if($ParamPos_New eq "lost")
12409 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012410 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012411 {
12412 my $ProblemType = "Removed_Parameter";
12413 if($Parameter_Name=~/\Ap\d+\Z/) {
12414 $ProblemType = "Removed_Unnamed_Parameter";
12415 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012416 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012417 "Target"=>$Parameter_Name,
12418 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012419 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012420 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012421 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012422 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012423 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012424 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012425 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012426 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012427 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012428 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012429 {
12430 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12431 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012432 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 "Target"=>$Parameter_Name,
12434 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012435 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012436 "Old_Value"=>$Parameter_Name,
12437 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012438 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012439 }
12440 }
12441 else
12442 {
12443 my $ProblemType = "Removed_Middle_Parameter";
12444 if($Parameter_Name=~/\Ap\d+\Z/) {
12445 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12446 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012447 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012448 "Target"=>$Parameter_Name,
12449 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012450 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012451 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012452 }
12453 }
12454 }
12455 }
12456 }
12457 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012458 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12459 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12460 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012461 foreach my $SubProblemType (keys(%SubProblems))
12462 {
12463 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12464 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12465 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012466 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012467
12468 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012469 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012470 $NewProblemType = "Global_Data_Type_And_Size";
12471 }
12472 elsif($SubProblemType eq "Return_Type")
12473 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012474 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012475 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012476 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012477 { # const -> non-const global data
12478 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012479 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012480 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012481 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012482 { # non-const -> const global data
12483 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012484 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012485 }
12486 else {
12487 $NewProblemType = "Global_Data_Type";
12488 }
12489 }
12490 else
12491 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012492 if(addedQual($Old_Value, $New_Value, "const"))
12493 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012494 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012495 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012496 }
12497 }
12498 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012499 elsif($SubProblemType eq "Return_Type_Format")
12500 {
12501 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12502 $NewProblemType = "Global_Data_Type_Format";
12503 }
12504 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012505 if($Level eq "Binary"
12506 and not $CompleteSignature{1}{$Symbol}{"Data"})
12507 {
12508 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12509 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12510 { # if one of the architectures is unknown
12511 # then set other arhitecture to unknown too
12512 ($Arch1, $Arch2) = ("unknown", "unknown");
12513 }
12514 my (%Conv1, %Conv2) = ();
12515 if($UseConv_Real{1} and $UseConv_Real{1})
12516 {
12517 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12518 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12519 }
12520 else
12521 {
12522 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12523 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12524 }
12525
12526 if($SubProblemType eq "Return_Type_Became_Void")
12527 {
12528 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12529 { # parameters stack has been affected
12530 if($Conv1{"Method"} eq "stack") {
12531 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12532 }
12533 elsif($Conv1{"Hidden"}) {
12534 $NewProblemType = "Return_Type_Became_Void_And_Register";
12535 }
12536 }
12537 }
12538 elsif($SubProblemType eq "Return_Type_From_Void")
12539 {
12540 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12541 { # parameters stack has been affected
12542 if($Conv2{"Method"} eq "stack") {
12543 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12544 }
12545 elsif($Conv2{"Hidden"}) {
12546 $NewProblemType = "Return_Type_From_Void_And_Register";
12547 }
12548 }
12549 }
12550 elsif($SubProblemType eq "Return_Type"
12551 or $SubProblemType eq "Return_Type_And_Size"
12552 or $SubProblemType eq "Return_Type_Format")
12553 {
12554 if($Conv1{"Method"} ne $Conv2{"Method"})
12555 {
12556 if($Conv1{"Method"} eq "stack")
12557 { # returns in a register instead of a hidden first parameter
12558 $NewProblemType = "Return_Type_From_Stack_To_Register";
12559 }
12560 else {
12561 $NewProblemType = "Return_Type_From_Register_To_Stack";
12562 }
12563 }
12564 else
12565 {
12566 if($Conv1{"Method"} eq "reg")
12567 {
12568 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12569 {
12570 if($Conv1{"Hidden"}) {
12571 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12572 }
12573 elsif($Conv2{"Hidden"}) {
12574 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12575 }
12576 else {
12577 $NewProblemType = "Return_Type_And_Register";
12578 }
12579 }
12580 }
12581 }
12582 }
12583 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012584 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012585 if(defined $AddProblemType) {
12586 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12587 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012588 }
12589 if($ReturnType1_Id and $ReturnType2_Id)
12590 {
12591 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012592 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012593 foreach my $SubProblemType (keys(%SubProblems))
12594 { # add "Global_Data_Size" problem
12595 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12596 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12597 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012598 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012599 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012600 { # add a new problem
12601 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12602 }
12603 }
12604 foreach my $SubProblemType (keys(%SubProblems))
12605 {
12606 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12607 {
12608 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012609 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012610 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012611 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012612 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012613 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012614 }
12615 }
12616 }
12617 }
12618
12619 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012620 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12621 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12622 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012623 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012624 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012625 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12626 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012627 if($ThisPtr1_Id and $ThisPtr2_Id)
12628 {
12629 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012630 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012631 foreach my $SubProblemType (keys(%SubProblems))
12632 {
12633 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12634 {
12635 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012636 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012637 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012638 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012639 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012640 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012641 }
12642 }
12643 }
12644 }
12645 }
12646 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012647 if($Level eq "Binary") {
12648 mergeVTables($Level);
12649 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012650 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12651 $CheckedSymbols{$Level}{$Symbol} = 1;
12652 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012653}
12654
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012655sub rmQuals($$)
12656{
12657 my ($Value, $Qual) = @_;
12658 if(not $Qual) {
12659 return $Value;
12660 }
12661 if($Qual eq "all")
12662 { # all quals
12663 $Qual = "const|volatile|restrict";
12664 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012665 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012666 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012667 }
12668 return $Value;
12669}
12670
12671sub cmpBTypes($$$$)
12672{
12673 my ($T1, $T2, $V1, $V2) = @_;
12674 $T1 = uncover_typedefs($T1, $V1);
12675 $T2 = uncover_typedefs($T2, $V2);
12676 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12677}
12678
12679sub addedQual($$$)
12680{
12681 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012682 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012683}
12684
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012685sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012686{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012687 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012688 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012689}
12690
12691sub removedQual_($$$$$)
12692{
12693 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12694 $Old_Value = uncover_typedefs($Old_Value, $V1);
12695 $New_Value = uncover_typedefs($New_Value, $V2);
12696 if($Old_Value eq $New_Value)
12697 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012698 return 0;
12699 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012700 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012701 { # without a qual
12702 return 0;
12703 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012704 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012705 { # became non-qual
12706 return 1;
12707 }
12708 else
12709 {
12710 my @BQ1 = getQualModel($Old_Value, $Qual);
12711 my @BQ2 = getQualModel($New_Value, $Qual);
12712 foreach (0 .. $#BQ1)
12713 { # removed qual
12714 if($BQ1[$_]==1
12715 and $BQ2[$_]!=1)
12716 {
12717 return 2;
12718 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012719 }
12720 }
12721 return 0;
12722}
12723
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012724sub getQualModel($$)
12725{
12726 my ($Value, $Qual) = @_;
12727 if(not $Qual) {
12728 return $Value;
12729 }
12730
12731 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012732 while($Value=~/(\w+)/ and $1 ne $Qual) {
12733 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012734 }
12735 $Value=~s/[^\*\&\w]+//g;
12736
12737 # modeling
12738 # int*const*const == 011
12739 # int**const == 001
12740 my @Model = ();
12741 my @Elems = split(/[\*\&]/, $Value);
12742 if(not @Elems) {
12743 return (0);
12744 }
12745 foreach (@Elems)
12746 {
12747 if($_ eq $Qual) {
12748 push(@Model, 1);
12749 }
12750 else {
12751 push(@Model, 0);
12752 }
12753 }
12754
12755 return @Model;
12756}
12757
12758sub showVal($$$)
12759{
12760 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012761 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012762 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012763 if(substr($Value, 0, 2) eq "_Z")
12764 {
12765 if(my $Unmangled = $tr_name{$Value}) {
12766 return $Unmangled;
12767 }
12768 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012769 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012770 { # strings
12771 return "\"$Value\"";
12772 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012773 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012774 { # characters
12775 return "\'$Value\'";
12776 }
12777 return $Value;
12778}
12779
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012780sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012781{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012782 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012783 if(not $Symbol) {
12784 return;
12785 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012786 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12787 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12788 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12789 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012790 if(not $PType1_Id
12791 or not $PType2_Id) {
12792 return;
12793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012794 my %Type1 = get_Type($PType1_Id, 1);
12795 my %Type2 = get_Type($PType2_Id, 2);
12796 my %BaseType1 = get_BaseType($PType1_Id, 1);
12797 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012798 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012799 if($Level eq "Binary")
12800 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012801 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012802 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12803 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12804 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12805 {
12806 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012807 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012808 "Param_Pos"=>$ParamPos1 );
12809 }
12810 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12811 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12812 {
12813 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012814 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012815 "Param_Pos"=>$ParamPos1 );
12816 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012817 }
12818 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012819 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012820 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012821 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12822 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012823 if(not checkDump(1, "2.13")
12824 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012825 { # support for old ABI dumps
12826 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012827 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012828 if($Type1{"Name"} eq "bool"
12829 and $Value_Old eq "false" and $Value_New eq "0")
12830 { # int class::method ( bool p = 0 );
12831 # old ABI dumps: "false"
12832 # new ABI dumps: "0"
12833 $Value_Old = "0";
12834 }
12835 }
12836 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012837 if(not checkDump(1, "2.18")
12838 and checkDump(2, "2.18"))
12839 { # support for old ABI dumps
12840 if(not defined $Value_Old
12841 and substr($Value_New, 0, 2) eq "_Z") {
12842 $Value_Old = $Value_New;
12843 }
12844 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012845 if(defined $Value_Old)
12846 {
12847 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12848 if(defined $Value_New)
12849 {
12850 $Value_New = showVal($Value_New, $PType2_Id, 2);
12851 if($Value_Old ne $Value_New)
12852 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012853 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012854 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012855 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012856 "Old_Value"=>$Value_Old,
12857 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012858 }
12859 }
12860 else
12861 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012862 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012863 "Target"=>$PName1,
12864 "Param_Pos"=>$ParamPos1,
12865 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012866 }
12867 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012868 elsif(defined $Value_New)
12869 {
12870 $Value_New = showVal($Value_New, $PType2_Id, 2);
12871 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12872 "Target"=>$PName1,
12873 "Param_Pos"=>$ParamPos1,
12874 "New_Value"=>$Value_New );
12875 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012876 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012877 if($PName1 and $PName2 and $PName1 ne $PName2
12878 and $PType1_Id!=-1 and $PType2_Id!=-1
12879 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012880 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012881 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012882 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012883 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012884 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012885 "Old_Value"=>$PName1,
12886 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012887 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012888 }
12889 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012890 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012891 foreach my $SubProblemType (keys(%SubProblems))
12892 { # add new problems, remove false alarms
12893 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12894 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12895 if($SubProblemType eq "Parameter_Type")
12896 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012897 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012898 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012899 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012900 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012901 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12902 if($Level eq "Source"
12903 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012904 delete($SubProblems{$SubProblemType});
12905 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012906 }
12907 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12908 {
12909 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12910 if($Level eq "Source"
12911 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012912 delete($SubProblems{$SubProblemType});
12913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012914 }
12915 }
12916 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12917 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12918 { # int to "int const"
12919 delete($SubProblems{$SubProblemType});
12920 }
12921 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12922 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12923 { # "int const" to int
12924 delete($SubProblems{$SubProblemType});
12925 }
12926 }
12927 }
12928 foreach my $SubProblemType (keys(%SubProblems))
12929 { # modify/register problems
12930 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12931 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012932 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
12933 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012934 my $NewProblemType = $SubProblemType;
12935 if($Old_Value eq "..." and $New_Value ne "...")
12936 { # change from "..." to "int"
12937 if($ParamPos1==0)
12938 { # ISO C requires a named argument before "..."
12939 next;
12940 }
12941 $NewProblemType = "Parameter_Became_NonVaList";
12942 }
12943 elsif($New_Value eq "..." and $Old_Value ne "...")
12944 { # change from "int" to "..."
12945 if($ParamPos2==0)
12946 { # ISO C requires a named argument before "..."
12947 next;
12948 }
12949 $NewProblemType = "Parameter_Became_VaList";
12950 }
12951 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012952 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012953 { # parameter: "const" to non-"const"
12954 $NewProblemType = "Parameter_Became_Non_Const";
12955 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012956 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012957 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012958 {
12959 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012960 if($Arch1 eq "unknown"
12961 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012962 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012963 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012964 ($Arch1, $Arch2) = ("unknown", "unknown");
12965 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012966 my (%Conv1, %Conv2) = ();
12967 if($UseConv_Real{1} and $UseConv_Real{1})
12968 { # real
12969 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
12970 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
12971 }
12972 else
12973 { # model
12974 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12975 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12976 }
12977 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012978 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012979 if($Conv1{"Method"} eq "stack")
12980 {
12981 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
12982 $NewProblemType = "Parameter_Type_And_Stack";
12983 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012984 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012985 elsif($Conv1{"Method"} eq "reg")
12986 {
12987 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
12988 $NewProblemType = "Parameter_Type_And_Register";
12989 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012990 }
12991 }
12992 else
12993 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012994 if($Conv1{"Method"} eq "stack") {
12995 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012996 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012997 elsif($Conv1{"Method"} eq "register") {
12998 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012999 }
13000 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013001 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13002 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013004 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013005 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013007 "New_Signature"=>get_Signature($Symbol, 2) );
13008 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013009 }
13010 @RecurTypes = ();
13011 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013012 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013013 foreach my $SubProblemType (keys(%SubProblems_Merge))
13014 {
13015 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13016 {
13017 my $NewProblemType = $SubProblemType;
13018 if($SubProblemType eq "DataType_Size")
13019 {
13020 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13021 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13022 { # stack has been affected
13023 $NewProblemType = "DataType_Size_And_Stack";
13024 }
13025 }
13026 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013027 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013028 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013029 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013030 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013031 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013032 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013033 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013034 }
13035 }
13036 }
13037}
13038
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013039sub find_ParamPair_Pos_byName($$$)
13040{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013041 my ($Name, $Symbol, $LibVersion) = @_;
13042 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013043 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013044 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13045 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013046 {
13047 return $ParamPos;
13048 }
13049 }
13050 return "lost";
13051}
13052
13053sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13054{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013055 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013056 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013057 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013058 {
13059 next if($Order eq "backward" and $ParamPos>$MediumPos);
13060 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013061 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13062 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013063 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013064 push(@Positions, $ParamPos);
13065 }
13066 }
13067 return @Positions;
13068}
13069
13070sub getTypeIdByName($$)
13071{
13072 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013073 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013074}
13075
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013076sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013077{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013078 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013079 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13080 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013081 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13082 { # equal types
13083 return 0;
13084 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013085 if($Type1_Pure{"Name"} eq "void")
13086 { # from void* to something
13087 return 0;
13088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013089 if($Type1_Pure{"Name"}=~/\*/
13090 or $Type2_Pure{"Name"}=~/\*/)
13091 { # compared in detectTypeChange()
13092 return 0;
13093 }
13094 my %FloatType = map {$_=>1} (
13095 "float",
13096 "double",
13097 "long double"
13098 );
13099 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13100 { # different types
13101 if($Type1_Pure{"Type"} eq "Intrinsic"
13102 and $Type2_Pure{"Type"} eq "Enum")
13103 { # "int" to "enum"
13104 return 0;
13105 }
13106 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13107 and $Type1_Pure{"Type"} eq "Enum")
13108 { # "enum" to "int"
13109 return 0;
13110 }
13111 else
13112 { # "union" to "struct"
13113 # ...
13114 return 1;
13115 }
13116 }
13117 else
13118 {
13119 if($Type1_Pure{"Type"} eq "Intrinsic")
13120 {
13121 if($FloatType{$Type1_Pure{"Name"}}
13122 or $FloatType{$Type2_Pure{"Name"}})
13123 { # "float" to "double"
13124 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013125 if($Level eq "Source")
13126 { # Safe
13127 return 0;
13128 }
13129 else {
13130 return 1;
13131 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013132 }
13133 }
13134 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13135 {
13136 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13137 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13138 if($#Membs1!=$#Membs2)
13139 { # different number of elements
13140 return 1;
13141 }
13142 if($Type1_Pure{"Type"} eq "Enum")
13143 {
13144 foreach my $Pos (@Membs1)
13145 { # compare elements by name and value
13146 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13147 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13148 { # different names
13149 return 1;
13150 }
13151 }
13152 }
13153 else
13154 {
13155 foreach my $Pos (@Membs1)
13156 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013157 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13158 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013159 if($MT1 ne $MT2)
13160 { # different types
13161 return 1;
13162 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013163 if($Level eq "Source")
13164 {
13165 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13166 { # different names
13167 return 1;
13168 }
13169 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013170 }
13171 }
13172 }
13173 }
13174 return 0;
13175}
13176
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013177sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013178{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013179 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013180 if(not $Type1_Id or not $Type2_Id) {
13181 return ();
13182 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013183 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013184 my %Type1 = get_Type($Type1_Id, 1);
13185 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013186 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13187 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13188 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13189 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 +040013190 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13191 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013192 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13193 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13194 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13195 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13196 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13197 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13198 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013199 if($Type1{"Name"} eq $Type2{"Name"})
13200 {
13201 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13202 { # will be reported in mergeTypes() as typedef problem
13203 return ();
13204 }
13205 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13206 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13207 if(%Typedef_1 and %Typedef_2)
13208 {
13209 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13210 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13211 { # const Typedef
13212 return ();
13213 }
13214 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013215 }
13216 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13217 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013218 if($Level eq "Binary"
13219 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013220 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13221 {
13222 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13223 "Old_Value"=>$Type1_Base{"Name"},
13224 "New_Value"=>$Type2_Base{"Name"},
13225 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13226 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13227 "InitialType_Type"=>$Type1_Pure{"Type"});
13228 }
13229 else
13230 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013231 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013232 { # format change
13233 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13234 "Old_Value"=>$Type1_Base{"Name"},
13235 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013236 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13237 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013238 "InitialType_Type"=>$Type1_Pure{"Type"});
13239 }
13240 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13241 {
13242 %{$LocalProblems{$Prefix."_BaseType"}}=(
13243 "Old_Value"=>$Type1_Base{"Name"},
13244 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013245 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13246 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013247 "InitialType_Type"=>$Type1_Pure{"Type"});
13248 }
13249 }
13250 }
13251 }
13252 elsif($Type1{"Name"} ne $Type2{"Name"})
13253 { # type change
13254 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13255 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013256 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013257 and $Type1_Pure{"Name"} eq "void")
13258 {
13259 %{$LocalProblems{"Return_Type_From_Void"}}=(
13260 "New_Value"=>$Type2{"Name"},
13261 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13262 "InitialType_Type"=>$Type1_Pure{"Type"});
13263 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013264 elsif($Prefix eq "Return"
13265 and $Type2_Pure{"Name"} eq "void")
13266 {
13267 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13268 "Old_Value"=>$Type1{"Name"},
13269 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13270 "InitialType_Type"=>$Type1_Pure{"Type"});
13271 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013272 else
13273 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013274 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013275 and $Type1{"Size"} and $Type2{"Size"}
13276 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013277 {
13278 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13279 "Old_Value"=>$Type1{"Name"},
13280 "New_Value"=>$Type2{"Name"},
13281 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13282 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13283 "InitialType_Type"=>$Type1_Pure{"Type"});
13284 }
13285 else
13286 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013287 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013288 { # format change
13289 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13290 "Old_Value"=>$Type1{"Name"},
13291 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013292 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13293 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013294 "InitialType_Type"=>$Type1_Pure{"Type"});
13295 }
13296 elsif(tNameLock($Type1_Id, $Type2_Id))
13297 { # FIXME: correct this condition
13298 %{$LocalProblems{$Prefix."_Type"}}=(
13299 "Old_Value"=>$Type1{"Name"},
13300 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013301 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13302 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013303 "InitialType_Type"=>$Type1_Pure{"Type"});
13304 }
13305 }
13306 }
13307 }
13308 }
13309 if($Type1_PLevel!=$Type2_PLevel)
13310 {
13311 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13312 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13313 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013314 if($Level eq "Source")
13315 {
13316 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013317 "Old_Value"=>$Type1_PLevel,
13318 "New_Value"=>$Type2_PLevel);
13319 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013320 else
13321 {
13322 if($Type2_PLevel>$Type1_PLevel) {
13323 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13324 "Old_Value"=>$Type1_PLevel,
13325 "New_Value"=>$Type2_PLevel);
13326 }
13327 else {
13328 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13329 "Old_Value"=>$Type1_PLevel,
13330 "New_Value"=>$Type2_PLevel);
13331 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013332 }
13333 }
13334 }
13335 if($Type1_Pure{"Type"} eq "Array")
13336 { # base_type[N] -> base_type[N]
13337 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013338 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013339 foreach my $SubProblemType (keys(%SubProblems))
13340 {
13341 $SubProblemType=~s/_Type/_BaseType/g;
13342 next if(defined $LocalProblems{$SubProblemType});
13343 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13344 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13345 }
13346 }
13347 }
13348 return %LocalProblems;
13349}
13350
13351sub tNameLock($$)
13352{
13353 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013354 my $Changed = 0;
13355 if(differentDumps("G"))
13356 { # different GCC versions
13357 $Changed = 1;
13358 }
13359 elsif(differentDumps("V"))
13360 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013361 if(not checkDump(1, "2.13")
13362 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013363 { # latest names update
13364 # 2.6: added restrict qualifier
13365 # 2.13: added missed typedefs to qualified types
13366 $Changed = 1;
13367 }
13368 }
13369 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013370 { # different formats
13371 if($UseOldDumps)
13372 { # old dumps
13373 return 0;
13374 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013375 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13376 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013377
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013378 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13379 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013380
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013381 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013382 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013383 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013384 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013385 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013386 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013387 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013389 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13390 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13391 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013392 { # equal base types
13393 return 0;
13394 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013395
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013396 if(not checkDump(1, "2.13")
13397 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013398 { # broken array names in ABI dumps < 2.13
13399 if($TT1 eq "Array"
13400 and $TT2 eq "Array")
13401 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013402 return 0;
13403 }
13404 }
13405
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013406 if(not checkDump(1, "2.6")
13407 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013408 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013409 if($TN1!~/\brestrict\b/
13410 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013411 {
13412 return 0;
13413 }
13414 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013415 }
13416 return 1;
13417}
13418
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013419sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013420{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013421 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013422 if(defined $Cache{"differentDumps"}{$Check}) {
13423 return $Cache{"differentDumps"}{$Check};
13424 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013425 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013426 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013427 if($Check eq "G")
13428 {
13429 if(getGccVersion(1) ne getGccVersion(2))
13430 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013431 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013432 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013433 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013434 if($Check eq "V")
13435 {
13436 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13437 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13438 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013439 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013440 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013441 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013442 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013443 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013444}
13445
13446sub formatVersion($$)
13447{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013448 my ($V, $Digits) = @_;
13449 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013450 return join(".", splice(@Elems, 0, $Digits));
13451}
13452
13453sub htmlSpecChars($)
13454{
13455 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013456 if(not $Str) {
13457 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013459 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13460 $Str=~s/</&lt;/g;
13461 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13462 $Str=~s/>/&gt;/g;
13463 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13464 $Str=~s/ /&#160;/g; # &nbsp;
13465 $Str=~s/\@ALONE_SP\@/ /g;
13466 $Str=~s/\n/<br\/>/g;
13467 $Str=~s/\"/&quot;/g;
13468 $Str=~s/\'/&#39;/g;
13469 return $Str;
13470}
13471
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013472sub xmlSpecChars($)
13473{
13474 my $Str = $_[0];
13475 if(not $Str) {
13476 return $Str;
13477 }
13478
13479 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13480 $Str=~s/</&lt;/g;
13481 $Str=~s/>/&gt;/g;
13482
13483 $Str=~s/\"/&quot;/g;
13484 $Str=~s/\'/&#39;/g;
13485
13486 return $Str;
13487}
13488
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013489sub xmlSpecChars_R($)
13490{
13491 my $Str = $_[0];
13492 if(not $Str) {
13493 return $Str;
13494 }
13495
13496 $Str=~s/&amp;/&/g;
13497 $Str=~s/&lt;/</g;
13498 $Str=~s/&gt;/>/g;
13499
13500 $Str=~s/&quot;/"/g;
13501 $Str=~s/&#39;/'/g;
13502
13503 return $Str;
13504}
13505
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013506sub black_name($)
13507{
13508 my $Name = $_[0];
13509 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13510}
13511
13512sub highLight_Signature($)
13513{
13514 my $Signature = $_[0];
13515 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13516}
13517
13518sub highLight_Signature_Italic_Color($)
13519{
13520 my $Signature = $_[0];
13521 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13522}
13523
13524sub separate_symbol($)
13525{
13526 my $Symbol = $_[0];
13527 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13528 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13529 ($Name, $Spec, $Ver) = ($1, $2, $3);
13530 }
13531 return ($Name, $Spec, $Ver);
13532}
13533
13534sub cut_f_attrs($)
13535{
13536 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13537 return $2;
13538 }
13539 return "";
13540}
13541
13542sub highLight_Signature_PPos_Italic($$$$$)
13543{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013544 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13545 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013546 if($CheckObjectsOnly) {
13547 $ItalicParams=$ColorParams=0;
13548 }
13549 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13550 my $Return = "";
13551 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13552 $Return = $2;
13553 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013554 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013555 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013556 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013557 $Signature = htmlSpecChars($Signature);
13558 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013559 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013560 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013561 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013562 }
13563 return $Signature;
13564 }
13565 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13566 $Begin.=" " if($Begin!~/ \Z/);
13567 $End = cut_f_attrs($Signature);
13568 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013569 my ($Short, $Params) = split_Signature($Signature);
13570 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013571 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013572 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013573 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013574 $Part=~s/\A\s+|\s+\Z//g;
13575 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13576 if($Part=~/\([\*]+(\w+)\)/i) {
13577 $ParamName = $1;#func-ptr
13578 }
13579 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13580 $ParamName = $1;
13581 }
13582 if(not $ParamName) {
13583 push(@Parts, $Part_Styled);
13584 next;
13585 }
13586 if($ItalicParams and not $TName_Tid{1}{$Part}
13587 and not $TName_Tid{2}{$Part})
13588 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013589 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013590 if($Param_Pos ne ""
13591 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013592 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013593 }
13594 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013595 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013596 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013597 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013598 }
13599 $Part_Styled=~s/,(\w)/, $1/g;
13600 push(@Parts, $Part_Styled);
13601 }
13602 if(@Parts)
13603 {
13604 foreach my $Num (0 .. $#Parts)
13605 {
13606 if($Num==$#Parts)
13607 { # add ")" to the last parameter
13608 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13609 }
13610 elsif(length($Parts[$Num])<=45) {
13611 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13612 }
13613 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013614 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013615 }
13616 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013617 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013618 }
13619 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013620 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013621 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013622 $Signature=~s!\[\]![&#160;]!g;
13623 $Signature=~s!operator=!operator&#160;=!g;
13624 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13625 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013626}
13627
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013628sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013629{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013630 my $Signature = $_[0];
13631 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13632 {
13633 $Signature=~s/\A\Q$ShortName\E\(//g;
13634 cut_f_attrs($Signature);
13635 $Signature=~s/\)\Z//;
13636 return ($ShortName, $Signature);
13637 }
13638
13639 # error
13640 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013641}
13642
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013643sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013644{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013645 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013646 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013647 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13648 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013649 foreach my $Pos (0 .. length($Params) - 1)
13650 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013651 my $S = substr($Params, $Pos, 1);
13652 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013653 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013654 }
13655 if($S eq "," and
13656 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013657 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013658 if($Comma)
13659 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013660 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013661 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013662 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013663 }
13664 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013665 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013666 }
13667 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013668 if(not $Sp)
13669 { # remove spaces
13670 foreach (@Parts)
13671 {
13672 s/\A //g;
13673 s/ \Z//g;
13674 }
13675 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013676 return @Parts;
13677}
13678
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013679sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013680{
13681 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013682 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013683 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013684 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13685 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013686 $Center+=length($1);
13687 }
13688 foreach my $Pos (0 .. length($Sign)-1)
13689 {
13690 my $S = substr($Sign, $Pos, 1);
13691 if($S eq $Target)
13692 {
13693 if($B{"("}==$B{")"}
13694 and $B{"<"}==$B{">"}) {
13695 return $Center;
13696 }
13697 }
13698 if(defined $B{$S}) {
13699 $B{$S}+=1;
13700 }
13701 $Center+=1;
13702 }
13703 return 0;
13704}
13705
13706sub appendFile($$)
13707{
13708 my ($Path, $Content) = @_;
13709 return if(not $Path);
13710 if(my $Dir = get_dirname($Path)) {
13711 mkpath($Dir);
13712 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013713 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013714 print FILE $Content;
13715 close(FILE);
13716}
13717
13718sub writeFile($$)
13719{
13720 my ($Path, $Content) = @_;
13721 return if(not $Path);
13722 if(my $Dir = get_dirname($Path)) {
13723 mkpath($Dir);
13724 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013725 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013726 print FILE $Content;
13727 close(FILE);
13728}
13729
13730sub readFile($)
13731{
13732 my $Path = $_[0];
13733 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013734 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013735 local $/ = undef;
13736 my $Content = <FILE>;
13737 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013738 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013739 $Content=~s/\r/\n/g;
13740 }
13741 return $Content;
13742}
13743
13744sub get_filename($)
13745{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013746 if(defined $Cache{"get_filename"}{$_[0]}) {
13747 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013748 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013749 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13750 return ($Cache{"get_filename"}{$_[0]}=$1);
13751 }
13752 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013753}
13754
13755sub get_dirname($)
13756{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013757 if(defined $Cache{"get_dirname"}{$_[0]}) {
13758 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013759 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013760 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13761 return ($Cache{"get_dirname"}{$_[0]}=$1);
13762 }
13763 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013764}
13765
13766sub separate_path($) {
13767 return (get_dirname($_[0]), get_filename($_[0]));
13768}
13769
13770sub esc($)
13771{
13772 my $Str = $_[0];
13773 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13774 return $Str;
13775}
13776
13777sub readLineNum($$)
13778{
13779 my ($Path, $Num) = @_;
13780 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013781 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013782 foreach (1 ... $Num) {
13783 <FILE>;
13784 }
13785 my $Line = <FILE>;
13786 close(FILE);
13787 return $Line;
13788}
13789
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013790sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013791{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013792 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013793 return () if(not $Path or not -f $Path);
13794 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013795 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13796 {
13797 foreach my $AttrVal (split(/;/, $1))
13798 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013799 if($AttrVal=~/(.+):(.+)/)
13800 {
13801 my ($Name, $Value) = ($1, $2);
13802 $Attributes{$Name} = $Value;
13803 }
13804 }
13805 }
13806 return \%Attributes;
13807}
13808
13809sub is_abs($) {
13810 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13811}
13812
13813sub get_abs_path($)
13814{ # abs_path() should NOT be called for absolute inputs
13815 # because it can change them
13816 my $Path = $_[0];
13817 if(not is_abs($Path)) {
13818 $Path = abs_path($Path);
13819 }
13820 return $Path;
13821}
13822
13823sub get_OSgroup()
13824{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013825 my $N = $Config{"osname"};
13826 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013827 return "macos";
13828 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013829 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013830 return "bsd";
13831 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013832 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013833 return "beos";
13834 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013835 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013836 return "symbian";
13837 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013838 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013839 return "windows";
13840 }
13841 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013842 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013843 }
13844}
13845
13846sub getGccVersion($)
13847{
13848 my $LibVersion = $_[0];
13849 if($GCC_VERSION{$LibVersion})
13850 { # dump version
13851 return $GCC_VERSION{$LibVersion};
13852 }
13853 elsif($UsedDump{$LibVersion}{"V"})
13854 { # old-version dumps
13855 return "unknown";
13856 }
13857 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13858 if(not $GccVersion) {
13859 return "unknown";
13860 }
13861 return $GccVersion;
13862}
13863
13864sub showArch($)
13865{
13866 my $Arch = $_[0];
13867 if($Arch eq "arm"
13868 or $Arch eq "mips") {
13869 return uc($Arch);
13870 }
13871 return $Arch;
13872}
13873
13874sub getArch($)
13875{
13876 my $LibVersion = $_[0];
13877 if($CPU_ARCH{$LibVersion})
13878 { # dump version
13879 return $CPU_ARCH{$LibVersion};
13880 }
13881 elsif($UsedDump{$LibVersion}{"V"})
13882 { # old-version dumps
13883 return "unknown";
13884 }
13885 if(defined $Cache{"getArch"}{$LibVersion}) {
13886 return $Cache{"getArch"}{$LibVersion};
13887 }
13888 my $Arch = get_dumpmachine($GCC_PATH); # host version
13889 if(not $Arch) {
13890 return "unknown";
13891 }
13892 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13893 $Arch = $1;
13894 }
13895 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13896 if($OSgroup eq "windows") {
13897 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13898 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13899 }
13900 $Cache{"getArch"}{$LibVersion} = $Arch;
13901 return $Arch;
13902}
13903
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013904sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013905{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013906 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013907 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013908 if(getArch(1) ne getArch(2)
13909 or getArch(1) eq "unknown"
13910 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013911 { # don't show architecture in the header
13912 $ArchInfo="";
13913 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013914 my $Report_Header = "<h1><span class='nowrap'>";
13915 if($Level eq "Source") {
13916 $Report_Header .= "Source compatibility";
13917 }
13918 elsif($Level eq "Binary") {
13919 $Report_Header .= "Binary compatibility";
13920 }
13921 else {
13922 $Report_Header .= "API compatibility";
13923 }
13924 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013925 $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>";
13926 if($AppPath) {
13927 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13928 }
13929 $Report_Header .= "</h1>\n";
13930 return $Report_Header;
13931}
13932
13933sub get_SourceInfo()
13934{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013935 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13936 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013937 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013938 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13939 $CheckedHeaders .= "<div class='h_list'>\n";
13940 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13941 {
13942 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13943 my $Header_Name = get_filename($Identity);
13944 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13945 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13946 }
13947 $CheckedHeaders .= "</div>\n";
13948 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013949 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013950 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013951 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013952 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13953 $CheckedLibs .= "<div class='lib_list'>\n";
13954 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13955 {
13956 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13957 $CheckedLibs .= $Library."<br/>\n";
13958 }
13959 $CheckedLibs .= "</div>\n";
13960 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013961 }
13962 return $CheckedHeaders.$CheckedLibs;
13963}
13964
13965sub get_TypeProblems_Count($$$)
13966{
13967 my ($TypeChanges, $TargetPriority, $Level) = @_;
13968 my $Type_Problems_Count = 0;
13969 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13970 {
13971 my %Kinds_Target = ();
13972 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13973 {
13974 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13975 {
13976 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13977 my $Priority = getProblemSeverity($Level, $Kind);
13978 next if($Priority ne $TargetPriority);
13979 if($Kinds_Target{$Kind}{$Target}) {
13980 next;
13981 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013982 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013983 { # select a problem with the highest priority
13984 next;
13985 }
13986 $Kinds_Target{$Kind}{$Target} = 1;
13987 $Type_Problems_Count += 1;
13988 }
13989 }
13990 }
13991 return $Type_Problems_Count;
13992}
13993
13994sub get_Summary($)
13995{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013996 my $Level = $_[0];
13997 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13998 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13999 %{$RESULT{$Level}} = (
14000 "Problems"=>0,
14001 "Warnings"=>0,
14002 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014003 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014004 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014005 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014006 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014007 {
14008 if(not defined $CompatRules{$Level}{$Kind})
14009 { # unknown rule
14010 if(not $UnknownRules{$Level}{$Kind})
14011 { # only one warning
14012 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14013 $UnknownRules{$Level}{$Kind}=1;
14014 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014015 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014016 }
14017 }
14018 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014019 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014020 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014021 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014022 {
14023 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14024 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014025 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014026 {
14027 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014028 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014029 $Added += 1;
14030 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014031 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014032 {
14033 $Removed += 1;
14034 $TotalAffected{$Level}{$Interface} = $Priority;
14035 }
14036 else
14037 {
14038 if($Priority eq "Safe") {
14039 $I_Other += 1;
14040 }
14041 elsif($Priority eq "High") {
14042 $I_Problems_High += 1;
14043 }
14044 elsif($Priority eq "Medium") {
14045 $I_Problems_Medium += 1;
14046 }
14047 elsif($Priority eq "Low") {
14048 $I_Problems_Low += 1;
14049 }
14050 if(($Priority ne "Low" or $StrictCompat)
14051 and $Priority ne "Safe") {
14052 $TotalAffected{$Level}{$Interface} = $Priority;
14053 }
14054 }
14055 }
14056 }
14057 }
14058 }
14059 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014060 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014061 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014062 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014063 {
14064 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14065 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014066 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014068 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14069 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014070 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014071 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014072 { # select a problem with the highest priority
14073 next;
14074 }
14075 if(($Priority ne "Low" or $StrictCompat)
14076 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014077 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014078 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014079 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014080 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014081 }
14082 }
14083 }
14084 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014085
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014086 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14087 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14088 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14089 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014090
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014091 if($CheckObjectsOnly)
14092 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014093 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014094 }
14095 else
14096 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014097 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014098 if($ExtendedCheck)
14099 { # don't count external_func_0 for constants
14100 $SCount-=1;
14101 }
14102 if($SCount)
14103 {
14104 my %Weight = (
14105 "High" => 100,
14106 "Medium" => 50,
14107 "Low" => 25
14108 );
14109 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014110 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014111 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014112 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014113 }
14114 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014115 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014116 }
14117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014118 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14119 if($RESULT{$Level}{"Affected"}>=100) {
14120 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014121 }
14122
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014123 $RESULT{$Level}{"Problems"} += $Removed;
14124 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014125 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014126 if($StrictCompat) {
14127 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14128 }
14129 else {
14130 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14131 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014132
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014133 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14134 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014135 if(defined $CompatRules{$Level}{"Changed_Constant"})
14136 {
14137 if($StrictCompat) {
14138 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14139 }
14140 else {
14141 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14142 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014143 }
14144 else
14145 {
14146 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14147 $C_Problems_Low = 0;
14148 }
14149 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014150 if($CheckImpl and $Level eq "Binary")
14151 {
14152 if($StrictCompat) {
14153 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14154 }
14155 else {
14156 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14157 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014158 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014159 if($RESULT{$Level}{"Problems"}
14160 and $RESULT{$Level}{"Affected"}) {
14161 $RESULT{$Level}{"Verdict"} = "incompatible";
14162 }
14163 else {
14164 $RESULT{$Level}{"Verdict"} = "compatible";
14165 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014166
14167 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14168 if(not $TotalTypes)
14169 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014170 $TotalTypes = keys(%{$TName_Tid{1}});
14171 }
14172
14173 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14174 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14175
14176 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14177
14178 if($ReportFormat eq "xml")
14179 { # XML
14180 # test info
14181 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14182 $TestInfo .= " <version1>\n";
14183 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14184 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14185 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14186 $TestInfo .= " </version1>\n";
14187
14188 $TestInfo .= " <version2>\n";
14189 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14190 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14191 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14192 $TestInfo .= " </version2>\n";
14193 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14194
14195 # test results
14196 $TestResults .= " <headers>\n";
14197 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14198 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014199 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014200 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14201 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14202 }
14203 $TestResults .= " </headers>\n";
14204
14205 $TestResults .= " <libs>\n";
14206 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14207 {
14208 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14209 $TestResults .= " <name>$Library</name>\n";
14210 }
14211 $TestResults .= " </libs>\n";
14212
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014213 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014214 $TestResults .= " <types>".$TotalTypes."</types>\n";
14215
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014216 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14217 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014218 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14219
14220 # problem summary
14221 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14222 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14223
14224 $Problem_Summary .= " <problems_with_types>\n";
14225 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14226 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14227 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14228 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14229 $Problem_Summary .= " </problems_with_types>\n";
14230
14231 $Problem_Summary .= " <problems_with_symbols>\n";
14232 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14233 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14234 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014235 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014236 $Problem_Summary .= " </problems_with_symbols>\n";
14237
14238 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014239 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014240 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014241 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014242 {
14243 $Problem_Summary .= " <impl>\n";
14244 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14245 $Problem_Summary .= " </impl>\n";
14246 }
14247 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14248
14249 return ($TestInfo.$TestResults.$Problem_Summary, "");
14250 }
14251 else
14252 { # HTML
14253 # test info
14254 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014255 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014256 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14257
14258 my (@VInf1, @VInf2, $AddTestInfo) = ();
14259 if($Arch1 ne "unknown"
14260 and $Arch2 ne "unknown")
14261 { # CPU arch
14262 if($Arch1 eq $Arch2)
14263 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014264 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014265 }
14266 else
14267 { # go to the version number
14268 push(@VInf1, showArch($Arch1));
14269 push(@VInf2, showArch($Arch2));
14270 }
14271 }
14272 if($GccV1 ne "unknown"
14273 and $GccV2 ne "unknown"
14274 and $OStarget ne "windows")
14275 { # GCC version
14276 if($GccV1 eq $GccV2)
14277 { # go to the separate section
14278 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14279 }
14280 else
14281 { # go to the version number
14282 push(@VInf1, "gcc ".$GccV1);
14283 push(@VInf2, "gcc ".$GccV2);
14284 }
14285 }
14286 # show long version names with GCC version and CPU architecture name (if different)
14287 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14288 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14289 $TestInfo .= $AddTestInfo;
14290 #if($COMMON_LANGUAGE{1}) {
14291 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14292 #}
14293 if($ExtendedCheck) {
14294 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014296 if($JoinReport)
14297 {
14298 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014299 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014300 }
14301 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014302 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014303 }
14304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014305 $TestInfo .= "</table>\n";
14306
14307 # test results
14308 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014309 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014310
14311 my $Headers_Link = "0";
14312 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14313 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14314
14315 if(not $ExtendedCheck)
14316 {
14317 my $Libs_Link = "0";
14318 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14319 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14320 }
14321
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014322 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014323
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014324 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014325 if($JoinReport) {
14326 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14327 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014328 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014329 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014330 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14331 }
14332 else {
14333 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14334 }
14335 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014336 $TestResults .= "</table>\n";
14337
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014338 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014339 # problem summary
14340 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014341 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014342 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14343
14344 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014345 if($Added>0)
14346 {
14347 if($JoinReport) {
14348 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14349 }
14350 else {
14351 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14352 }
14353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014354 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014355 $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 +040014356
14357 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014358 if($Removed>0)
14359 {
14360 if($JoinReport) {
14361 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14362 }
14363 else {
14364 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14365 }
14366 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014367 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014368 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14369 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014370
14371 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014372 $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 +040014373 $TH_Link = "n/a" if($CheckObjectsOnly);
14374 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014375 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14376 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014377
14378 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014379 $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 +040014380 $TM_Link = "n/a" if($CheckObjectsOnly);
14381 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014382 $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 +040014383
14384 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014385 $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 +040014386 $TL_Link = "n/a" if($CheckObjectsOnly);
14387 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014388 $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 +040014389
14390 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014391 $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 +040014392 $IH_Link = "n/a" if($CheckObjectsOnly);
14393 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014394 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14395 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014396
14397 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014398 $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 +040014399 $IM_Link = "n/a" if($CheckObjectsOnly);
14400 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014401 $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 +040014402
14403 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014404 $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 +040014405 $IL_Link = "n/a" if($CheckObjectsOnly);
14406 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014407 $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 +040014408
14409 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014410 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14411 {
14412 if($JoinReport) {
14413 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14414 }
14415 else {
14416 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014418 }
14419 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014420 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014421 $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 +040014422
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014423 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014424 {
14425 my $ChangedImpl_Link = "0";
14426 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14427 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14428 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014429 $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 +040014430 }
14431 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014432 if($T_Other and not $CheckObjectsOnly)
14433 {
14434 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014435 $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 +040014436 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014437
14438 if($I_Other and not $CheckObjectsOnly)
14439 {
14440 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014441 $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 +040014442 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014443
14444 $META_DATA .= "tool_version:$TOOL_VERSION";
14445 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014446 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014447 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14448 }
14449}
14450
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014451sub getStyle($$$)
14452{
14453 my ($Subj, $Act, $Num) = @_;
14454 my %Style = (
14455 "A"=>"new",
14456 "R"=>"failed",
14457 "S"=>"passed",
14458 "L"=>"warning",
14459 "M"=>"failed",
14460 "H"=>"failed"
14461 );
14462 if($Num>0) {
14463 return " class='".$Style{$Act}."'";
14464 }
14465 return "";
14466}
14467
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014468sub show_number($)
14469{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014470 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014471 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014472 my $Num = cut_off_number($_[0], 2, 0);
14473 if($Num eq "0")
14474 {
14475 foreach my $P (3 .. 7)
14476 {
14477 $Num = cut_off_number($_[0], $P, 1);
14478 if($Num ne "0") {
14479 last;
14480 }
14481 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014482 }
14483 if($Num eq "0") {
14484 $Num = $_[0];
14485 }
14486 return $Num;
14487 }
14488 return $_[0];
14489}
14490
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014491sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014492{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014493 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014494 if($num!~/\./)
14495 {
14496 $num .= ".";
14497 foreach (1 .. $digs_to_cut-1) {
14498 $num .= "0";
14499 }
14500 }
14501 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14502 {
14503 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14504 $num .= "0";
14505 }
14506 }
14507 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14508 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14509 }
14510 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014511 if($z) {
14512 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14513 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014514 return $num;
14515}
14516
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014517sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014518{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014519 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014520 my $CHANGED_CONSTANTS = "";
14521 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014522 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014523 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014524 }
14525 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014526 if(not defined $CompatRules{$Level}{$Kind}) {
14527 return "";
14528 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014529 if($ReportFormat eq "xml")
14530 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014531 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014532 {
14533 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014534 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014535 {
14536 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014537 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14538 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14539 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014540 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014541 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14542 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14543 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014544 $CHANGED_CONSTANTS .= " </problem>\n";
14545 $CHANGED_CONSTANTS .= " </constant>\n";
14546 }
14547 $CHANGED_CONSTANTS .= " </header>\n";
14548 }
14549 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14550 }
14551 else
14552 { # HTML
14553 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014554 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014555 {
14556 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014557 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014558 {
14559 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014560 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14561 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014562 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 +040014563 $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 +040014564 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14565 $CHANGED_CONSTANTS .= insertIDs($Report);
14566 }
14567 $CHANGED_CONSTANTS .= "<br/>\n";
14568 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014569 if($CHANGED_CONSTANTS)
14570 {
14571 my $Anchor = "<a name='Changed_Constants'></a>";
14572 if($JoinReport) {
14573 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14574 }
14575 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576 }
14577 }
14578 return $CHANGED_CONSTANTS;
14579}
14580
14581sub get_Report_Impl()
14582{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014583 my $CHANGED_IMPLEMENTATION = "";
14584 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014585 foreach my $Interface (sort keys(%ImplProblems))
14586 {
14587 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14588 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014589 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014590 }
14591 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014592 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014593 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014594 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014595 {
14596 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14597 if($HeaderName) {
14598 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14599 }
14600 else {
14601 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14602 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014603 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014604 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014605 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014607 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014608 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014609 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014610 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014611 foreach my $Interface (@SortedInterfaces)
14612 {
14613 $Changed_Number += 1;
14614 my $Signature = get_Signature($Interface, 1);
14615 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014616 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014618 $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 +040014619 }
14620 }
14621 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14622 }
14623 }
14624 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014625 $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 +040014626 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014627
14628 # clean memory
14629 %ImplProblems = ();
14630
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014631 return $CHANGED_IMPLEMENTATION;
14632}
14633
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014634sub getTitle($$$)
14635{
14636 my ($Header, $Library, $NameSpace) = @_;
14637 my $Title = "";
14638 if($Library and $Library!~/\.\w+\Z/) {
14639 $Library .= " (.$LIB_EXT)";
14640 }
14641 if($Header and $Library)
14642 {
14643 $Title .= "<span class='h_name'>$Header</span>";
14644 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14645 }
14646 elsif($Library) {
14647 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14648 }
14649 elsif($Header) {
14650 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14651 }
14652 if($NameSpace) {
14653 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14654 }
14655 return $Title;
14656}
14657
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014658sub get_Report_Added($)
14659{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014660 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014661 my $ADDED_INTERFACES = "";
14662 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014663 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014664 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014665 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014666 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014667 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014668 {
14669 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14670 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014671 if($Level eq "Source" and $ReportFormat eq "html")
14672 { # do not show library name in HTML report
14673 $DyLib = "";
14674 }
14675 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014676 }
14677 }
14678 }
14679 if($ReportFormat eq "xml")
14680 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014681 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014682 {
14683 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014684 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014685 {
14686 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014687 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014688 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14689 }
14690 $ADDED_INTERFACES .= " </library>\n";
14691 }
14692 $ADDED_INTERFACES .= " </header>\n";
14693 }
14694 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14695 }
14696 else
14697 { # HTML
14698 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014699 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014700 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014701 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014703 my %NameSpaceSymbols = ();
14704 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14705 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014707 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014708 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014709 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14710 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014711 foreach my $Interface (@SortedInterfaces)
14712 {
14713 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014714 my $Signature = get_Signature($Interface, 2);
14715 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014716 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014717 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014718 if($Interface=~/\A(_Z|\?)/)
14719 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014720 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014721 $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 +040014722 }
14723 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014724 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014725 }
14726 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014727 else
14728 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014729 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014730 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014731 }
14732 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014733 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014734 }
14735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014736 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014737 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014739 }
14740 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741 if($ADDED_INTERFACES)
14742 {
14743 my $Anchor = "<a name='Added'></a>";
14744 if($JoinReport) {
14745 $Anchor = "<a name='".$Level."_Added'></a>";
14746 }
14747 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014748 }
14749 }
14750 return $ADDED_INTERFACES;
14751}
14752
14753sub get_Report_Removed($)
14754{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014755 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014756 my $REMOVED_INTERFACES = "";
14757 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014758 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014759 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014760 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014761 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014762 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014763 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014764 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14765 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014766 if($Level eq "Source" and $ReportFormat eq "html")
14767 { # do not show library name in HTML report
14768 $DyLib = "";
14769 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014770 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014771 }
14772 }
14773 }
14774 if($ReportFormat eq "xml")
14775 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014776 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014777 {
14778 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014779 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014780 {
14781 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014782 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14783 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014784 }
14785 $REMOVED_INTERFACES .= " </library>\n";
14786 }
14787 $REMOVED_INTERFACES .= " </header>\n";
14788 }
14789 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14790 }
14791 else
14792 { # HTML
14793 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014794 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014795 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014796 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014797 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014798 my %NameSpaceSymbols = ();
14799 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14800 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014801 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014802 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014803 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014804 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14805 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014806 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014807 {
14808 $Removed_Number += 1;
14809 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014810 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014811 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014812 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014813 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014814 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014815 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014816 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014817 $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 +040014818 }
14819 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014820 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014821 }
14822 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014823 else
14824 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014825 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014826 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014827 }
14828 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014829 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014830 }
14831 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014832 }
14833 }
14834 $REMOVED_INTERFACES .= "<br/>\n";
14835 }
14836 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014837 if($REMOVED_INTERFACES)
14838 {
14839 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14840 if($JoinReport) {
14841 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14842 }
14843 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014844 }
14845 }
14846 return $REMOVED_INTERFACES;
14847}
14848
14849sub getXmlParams($$)
14850{
14851 my ($Content, $Problem) = @_;
14852 return "" if(not $Content or not $Problem);
14853 my %XMLparams = ();
14854 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14855 {
14856 my $Macro = "\@".lc($Attr);
14857 if($Content=~/\Q$Macro\E/) {
14858 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14859 }
14860 }
14861 my @PString = ();
14862 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014863 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014864 }
14865 if(@PString) {
14866 return " ".join(" ", @PString);
14867 }
14868 else {
14869 return "";
14870 }
14871}
14872
14873sub addMarkup($)
14874{
14875 my $Content = $_[0];
14876 # auto-markup
14877 $Content=~s/\n[ ]*//; # spaces
14878 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14879 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014880 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014881 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14882 if($Content=~/\ANOTE:/)
14883 { # notes
14884 $Content=~s!(NOTE):!<b>$1</b>:!g;
14885 }
14886 else {
14887 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14888 }
14889 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14890 my @Keywords = (
14891 "void",
14892 "const",
14893 "static",
14894 "restrict",
14895 "volatile",
14896 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014897 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014898 );
14899 my $MKeys = join("|", @Keywords);
14900 foreach (@Keywords) {
14901 $MKeys .= "|non-".$_;
14902 }
14903 $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 +040014904
14905 # Markdown
14906 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14907 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014908 return $Content;
14909}
14910
14911sub applyMacroses($$$$)
14912{
14913 my ($Level, $Kind, $Content, $Problem) = @_;
14914 return "" if(not $Content or not $Problem);
14915 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14916 $Content = addMarkup($Content);
14917 # macros
14918 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14919 {
14920 my $Macro = "\@".lc($Attr);
14921 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014922 if(not defined $Value
14923 or $Value eq "") {
14924 next;
14925 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014926 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014927 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014928 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14929 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014930 $Value = black_name($Value);
14931 }
14932 elsif($Value=~/\s/) {
14933 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14934 }
14935 elsif($Value=~/\A\d+\Z/
14936 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14937 { # bits to bytes
14938 if($Value % $BYTE_SIZE)
14939 { # bits
14940 if($Value==1) {
14941 $Value = "<b>".$Value."</b> bit";
14942 }
14943 else {
14944 $Value = "<b>".$Value."</b> bits";
14945 }
14946 }
14947 else
14948 { # bytes
14949 $Value /= $BYTE_SIZE;
14950 if($Value==1) {
14951 $Value = "<b>".$Value."</b> byte";
14952 }
14953 else {
14954 $Value = "<b>".$Value."</b> bytes";
14955 }
14956 }
14957 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014958 else
14959 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014960 $Value = "<b>".htmlSpecChars($Value)."</b>";
14961 }
14962 $Content=~s/\Q$Macro\E/$Value/g;
14963 }
14964
14965 if($Content=~/(\A|[^\@\w])\@\w/)
14966 {
14967 if(not $IncompleteRules{$Level}{$Kind})
14968 { # only one warning
14969 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14970 $IncompleteRules{$Level}{$Kind} = 1;
14971 }
14972 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014973 return $Content;
14974}
14975
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014976sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014977{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014978 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014979 my $INTERFACE_PROBLEMS = "";
14980 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014981 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014982 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014983 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14984 if($SV and defined $CompatProblems{$Level}{$SN}) {
14985 next;
14986 }
14987 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014988 {
14989 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014990 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014991 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014992 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14993 my $DyLib = $Symbol_Library{1}{$Symbol};
14994 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014995 { # Symbol with Version
14996 $DyLib = $Symbol_Library{1}{$VSym};
14997 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014998 if(not $DyLib)
14999 { # const global data
15000 $DyLib = "";
15001 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015002 if($Level eq "Source" and $ReportFormat eq "html")
15003 { # do not show library name in HTML report
15004 $DyLib = "";
15005 }
15006 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15007 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015008 {
15009 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015010 if($Priority ne $TargetSeverity) {
15011 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015012 }
15013 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015014 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15015 {
15016 delete($SymbolChanges{$Symbol}{$Kind});
15017 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015019 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015020 }
15021 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015022 if(not keys(%{$SymbolChanges{$Symbol}})) {
15023 delete($SymbolChanges{$Symbol});
15024 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015025 }
15026 if($ReportFormat eq "xml")
15027 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015028 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015029 {
15030 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015031 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015032 {
15033 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15034 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15035 {
15036 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15037 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15038 {
15039 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15040 {
15041 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015042 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015043 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15044 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15045 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15046 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15047 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15048 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15049 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15050 $INTERFACE_PROBLEMS .= " </problem>\n";
15051 }
15052 }
15053 $INTERFACE_PROBLEMS .= " </symbol>\n";
15054 }
15055 $INTERFACE_PROBLEMS .= " </library>\n";
15056 }
15057 $INTERFACE_PROBLEMS .= " </header>\n";
15058 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015059 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015060 }
15061 else
15062 { # HTML
15063 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015064 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015065 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015066 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015068 my (%NameSpaceSymbols, %NewSignature) = ();
15069 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15070 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015072 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015073 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015074 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15075 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15076 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015077 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015078 my $Signature = get_Signature($Symbol, 1);
15079 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015080 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015081 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015082 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015083 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015084 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015085 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015086 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015087 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015088 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015089 }
15090 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15091 {
15092 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015093 $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 +040015094 $ProblemNum += 1;
15095 $ProblemsNum += 1;
15096 }
15097 }
15098 }
15099 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015100 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015101 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015102 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015103 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015104 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015105 }
15106 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015107 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015109 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15110 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15111 if($NewSignature{$Symbol})
15112 { # argument list changed to
15113 $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 +040015114 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015115 if($Symbol=~/\A(_Z|\?)/) {
15116 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15117 }
15118 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15119 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015120 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015121 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015122 }
15123 }
15124 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015125 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015126 }
15127 }
15128 }
15129 if($INTERFACE_PROBLEMS)
15130 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015131 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15132 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15133 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015134 { # Safe Changes
15135 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015136 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015137 $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 +040015138 }
15139 }
15140 return $INTERFACE_PROBLEMS;
15141}
15142
15143sub get_Report_TypeProblems($$)
15144{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015145 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015146 my $TYPE_PROBLEMS = "";
15147 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015148 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015149 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015150 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015151 {
15152 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15153 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015154 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015156 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15157 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15158 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15159 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15160 my $Severity = getProblemSeverity($Level, $Kind);
15161 if($Severity eq "Safe"
15162 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015163 next;
15164 }
15165 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015166 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015167 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015168 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015169 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015170
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015171 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015172 { # select a problem with the highest priority
15173 next;
15174 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015175 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015176 }
15177 }
15178 }
15179 }
15180 my %Kinds_Locations = ();
15181 foreach my $TypeName (keys(%TypeChanges))
15182 {
15183 my %Kinds_Target = ();
15184 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15185 {
15186 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15187 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015188 my $Severity = getProblemSeverity($Level, $Kind);
15189 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015190 { # other priority
15191 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15192 next;
15193 }
15194 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15195 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15196 if($Kinds_Target{$Kind}{$Target})
15197 { # duplicate target
15198 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15199 next;
15200 }
15201 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015202 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015203 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015204 }
15205 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15206 delete($TypeChanges{$TypeName}{$Kind});
15207 }
15208 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015209 if(not keys(%{$TypeChanges{$TypeName}})) {
15210 delete($TypeChanges{$TypeName});
15211 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015212 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015213 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 +040015214 if($ReportFormat eq "xml")
15215 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015216 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015217 {
15218 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015219 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015220 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015221 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015222 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15223 {
15224 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15225 {
15226 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15227 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15228 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15229 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15230 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15231 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15232 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15233 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15234 $TYPE_PROBLEMS .= " </problem>\n";
15235 }
15236 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015237 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015238 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015239 $TYPE_PROBLEMS .= showVTables($TypeName);
15240 }
15241 $TYPE_PROBLEMS .= " </type>\n";
15242 }
15243 $TYPE_PROBLEMS .= " </header>\n";
15244 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015245 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015246 }
15247 else
15248 { # HTML
15249 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015250 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015251 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015252 my (%NameSpace_Type) = ();
15253 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015254 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15255 }
15256 foreach my $NameSpace (sort keys(%NameSpace_Type))
15257 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015258 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15259 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015260 foreach my $TypeName (@SortedTypes)
15261 {
15262 my $ProblemNum = 1;
15263 my $TYPE_REPORT = "";
15264 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15265 {
15266 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15267 {
15268 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15269 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15270 {
15271 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15272 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15273 $ProblemNum += 1;
15274 $ProblemsNum += 1;
15275 }
15276 }
15277 }
15278 $ProblemNum -= 1;
15279 if($TYPE_REPORT)
15280 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015281 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015282 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015283 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 $ShowVTables = showVTables($TypeName);
15285 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015286 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15287 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15288 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15289 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15290 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015291 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015292 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015293 }
15294 }
15295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015296 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015297 }
15298 }
15299 if($TYPE_PROBLEMS)
15300 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015301 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15302 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015303 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015304 { # Safe Changes
15305 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015307 $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 +040015308 }
15309 }
15310 return $TYPE_PROBLEMS;
15311}
15312
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015313sub get_Anchor($$$)
15314{
15315 my ($Kind, $Level, $Severity) = @_;
15316 if($JoinReport)
15317 {
15318 if($Severity eq "Safe") {
15319 return "Other_".$Level."_Changes_In_".$Kind."s";
15320 }
15321 else {
15322 return $Kind."_".$Level."_Problems_".$Severity;
15323 }
15324 }
15325 else
15326 {
15327 if($Severity eq "Safe") {
15328 return "Other_Changes_In_".$Kind."s";
15329 }
15330 else {
15331 return $Kind."_Problems_".$Severity;
15332 }
15333 }
15334}
15335
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015336sub showVTables($)
15337{
15338 my $TypeName = $_[0];
15339 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015340 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 if(defined $Type1{"VTable"}
15342 and keys(%{$Type1{"VTable"}}))
15343 {
15344 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015345 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015346 if(defined $Type2{"VTable"}
15347 and keys(%{$Type2{"VTable"}}))
15348 {
15349 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15350 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015351 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015352 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015353 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15354 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015355 }
15356 my $VTABLES = "";
15357 if($ReportFormat eq "xml")
15358 { # XML
15359 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015360 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015361 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015362 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015363 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15364 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015365 $VTABLES .= " </entry>\n";
15366 }
15367 $VTABLES .= " </vtable>\n\n";
15368 }
15369 else
15370 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015371 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015372 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15373 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15374 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015375 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015376 {
15377 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015378 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015379 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015380 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015381 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015382 $Color1 = " class='failed'";
15383 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015384 }
15385 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015386 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387 }
15388 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015389 $VTABLES .= "<tr><th>".$Index."</th>\n";
15390 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15391 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015392 }
15393 $VTABLES .= "</table><br/>\n";
15394 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015395 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 }
15397 return $VTABLES;
15398 }
15399 }
15400 return "";
15401}
15402
15403sub simpleVEntry($)
15404{
15405 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015406 if(not defined $VEntry
15407 or $VEntry eq "") {
15408 return "";
15409 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015410 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15411 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15412 if($VEntry=~/\A_ZThn.+\Z/) {
15413 $VEntry = "non-virtual thunk";
15414 }
15415 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15416 # support for old GCC versions
15417 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15418 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15419 $VEntry=~s/\A&_Z\Z/& _Z/;
15420 # templates
15421 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15422 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15423 # become std::basic_streambuf<char, ...>::imbue
15424 my ($Pname, $Pval) = ($1, $2);
15425 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15426 { # stdc++ typedefs
15427 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15428 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15429 # The typedef info should be added to ABI dumps
15430 }
15431 else
15432 {
15433 $VEntry=~s/<$Pname>/<$Pval>/g;
15434 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15435 }
15436 }
15437 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15438 return $VEntry;
15439}
15440
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015441sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015442{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015443 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015444 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015445 if($#{$Syms}>=10000)
15446 { # reduce size of the report
15447 $LIMIT = 10;
15448 }
15449 my %SProblems = ();
15450 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015451 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015452 if(keys(%SProblems)>$LIMIT) {
15453 last;
15454 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015455 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015456 { # duplicated problems for C2 constructors, D2 and D0 destructors
15457 next;
15458 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015459 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15460 if($Level eq "Source")
15461 { # remove symbol version
15462 $Symbol=$SN;
15463 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015464 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15465 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015466 my $Signature = get_Signature($Symbol, 1);
15467 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015468 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015469 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015470 {
15471 if(not defined $Kinds_Locations->{$Kind}
15472 or not $Kinds_Locations->{$Kind}{$Location}) {
15473 next;
15474 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015475 if($SV and defined $CompatProblems{$Level}{$SN}
15476 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015477 { # duplicated problems for versioned symbols
15478 next;
15479 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015480 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015481 next if($Type_Name ne $Target_TypeName);
15482
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15484 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015485 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015486 my $Path_Length = 0;
15487 my $ProblemLocation = $Location;
15488 if($Type_Name) {
15489 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15490 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015491 while($ProblemLocation=~/\-\>/g) {
15492 $Path_Length += 1;
15493 }
15494 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15495 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015496 {
15497 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015498 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015499 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015500 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015501 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15502 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015503 "Signature"=>$Signature,
15504 "Position"=>$Position,
15505 "Param_Name"=>$Param_Name,
15506 "Location"=>$Location
15507 );
15508 }
15509 }
15510 }
15511 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015512 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015513 @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 +040015514 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15515 if($#Symbols+1>$LIMIT)
15516 { # remove last element
15517 pop(@Symbols);
15518 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015519 my $Affected = "";
15520 if($ReportFormat eq "xml")
15521 { # XML
15522 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015523 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015524 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015525 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15526 my $Description = $SProblems{$Symbol}{"Descr"};
15527 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015528 my $Target = "";
15529 if($Param_Name) {
15530 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15531 }
15532 elsif($Location=~/\Aretval(\-|\Z)/i) {
15533 $Target = " affected=\"retval\"";
15534 }
15535 elsif($Location=~/\Athis(\-|\Z)/i) {
15536 $Target = " affected=\"this\"";
15537 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015538 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015539 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015540 $Affected .= " </symbol>\n";
15541 }
15542 $Affected .= " </affected>\n";
15543 }
15544 else
15545 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015546 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015547 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015548 my $Description = $SProblems{$Symbol}{"Descr"};
15549 my $Signature = $SProblems{$Symbol}{"Signature"};
15550 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015551 $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 +040015552 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015553 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015554 $Affected .= "and others ...<br/>";
15555 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015556 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015557 if($Affected)
15558 {
15559 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015560 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015561 }
15562 }
15563 return $Affected;
15564}
15565
15566sub cmp_locations($$)
15567{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015568 my ($L1, $L2) = @_;
15569 if($L2=~/\b(retval|this)\b/
15570 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015571 return 1;
15572 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015573 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15574 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015575 return 1;
15576 }
15577 return 0;
15578}
15579
15580sub getAffectDescription($$$$)
15581{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015582 my ($Level, $Symbol, $Kind, $Location) = @_;
15583 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015584 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015585 my @Sentence = ();
15586 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15587 if($Kind eq "Overridden_Virtual_Method"
15588 or $Kind eq "Overridden_Virtual_Method_B") {
15589 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15590 }
15591 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15592 {
15593 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15594 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015595 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015596 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015597 if($ClassName eq $Problem{"Type_Name"}) {
15598 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15599 }
15600 else {
15601 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15602 }
15603 }
15604 else
15605 {
15606 if($Location=~/retval/)
15607 { # return value
15608 if($Location=~/\-\>/) {
15609 push(@Sentence, "Field \'".$Location."\' in return value");
15610 }
15611 else {
15612 push(@Sentence, "Return value");
15613 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015614 if(my $Init = $Problem{"InitialType_Type"})
15615 {
15616 if($Init eq "Pointer") {
15617 push(@Sentence, "(pointer)");
15618 }
15619 elsif($Init eq "Ref") {
15620 push(@Sentence, "(reference)");
15621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015622 }
15623 }
15624 elsif($Location=~/this/)
15625 { # "this" pointer
15626 if($Location=~/\-\>/) {
15627 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15628 }
15629 else {
15630 push(@Sentence, "\'this\' pointer");
15631 }
15632 }
15633 else
15634 { # parameters
15635 if($Location=~/\-\>/) {
15636 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15637 }
15638 else {
15639 push(@Sentence, "$PPos parameter");
15640 }
15641 if($Problem{"Param_Name"}) {
15642 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15643 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015644 if(my $Init = $Problem{"InitialType_Type"})
15645 {
15646 if($Init eq "Pointer") {
15647 push(@Sentence, "(pointer)");
15648 }
15649 elsif($Init eq "Ref") {
15650 push(@Sentence, "(reference)");
15651 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015652 }
15653 }
15654 if($Location eq "this") {
15655 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15656 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015657 elsif(defined $Problem{"Start_Type_Name"}
15658 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015659 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15660 }
15661 else {
15662 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15663 }
15664 }
15665 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015666 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015667 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15668 }
15669 return join(" ", @Sentence);
15670}
15671
15672sub get_XmlSign($$)
15673{
15674 my ($Symbol, $LibVersion) = @_;
15675 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15676 my $Report = "";
15677 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15678 {
15679 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015680 my $Type = $Info->{"Param"}{$Pos}{"type"};
15681 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015682 foreach my $Typedef (keys(%ChangedTypedef))
15683 {
15684 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015685 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015686 }
15687 $Report .= " <param pos=\"$Pos\">\n";
15688 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015689 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015690 $Report .= " </param>\n";
15691 }
15692 if(my $Return = $Info->{"Return"})
15693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015694 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015695 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015696 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015697 $Report .= " </retval>\n";
15698 }
15699 return $Report;
15700}
15701
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015702sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015703{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015704 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015705 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015706 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015707 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015708 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15709 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015710 next;
15711 }
15712 $Report .= " <symbol name=\"$Symbol\">\n";
15713 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015714 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015715 {
15716 if(defined $CompleteSignature{1}{$Symbol}
15717 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15718 {
15719 $P1 = get_XmlSign($Symbol, 1);
15720 $S1 = get_Signature($Symbol, 1);
15721 }
15722 elsif($Symbol=~/\A(_Z|\?)/) {
15723 $S1 = $tr_name{$Symbol};
15724 }
15725 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015726 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015727 {
15728 if(defined $CompleteSignature{2}{$Symbol}
15729 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15730 {
15731 $P2 = get_XmlSign($Symbol, 2);
15732 $S2 = get_Signature($Symbol, 2);
15733 }
15734 elsif($Symbol=~/\A(_Z|\?)/) {
15735 $S2 = $tr_name{$Symbol};
15736 }
15737 }
15738 if($S1)
15739 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015740 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015741 $Report .= $P1;
15742 $Report .= " </old>\n";
15743 }
15744 if($S2 and $S2 ne $S1)
15745 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015746 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015747 $Report .= $P2;
15748 $Report .= " </new>\n";
15749 }
15750 $Report .= " </symbol>\n";
15751 }
15752 $Report .= "</symbols_info>\n";
15753 return $Report;
15754}
15755
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015756sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015757{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015758 my ($Level, $Report) = @_;
15759 if($ReportFormat eq "xml") {
15760 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015761 }
15762 if($StdOut)
15763 { # --stdout option
15764 print STDOUT $Report;
15765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015766 else
15767 {
15768 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015769 mkpath(get_dirname($RPath));
15770
15771 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15772 print REPORT $Report;
15773 close(REPORT);
15774
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015775 if($Browse or $OpenReport)
15776 { # open in browser
15777 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015778 if($JoinReport or $DoubleReport)
15779 {
15780 if($Level eq "Binary")
15781 { # wait to open a browser
15782 sleep(1);
15783 }
15784 }
15785 }
15786 }
15787}
15788
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015789sub openReport($)
15790{
15791 my $Path = $_[0];
15792 my $Cmd = "";
15793 if($Browse)
15794 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015795 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015796 }
15797 if(not $Cmd)
15798 { # default browser
15799 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015800 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015801 }
15802 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015803 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015804 }
15805 else
15806 { # linux, freebsd, solaris
15807 my @Browsers = (
15808 "x-www-browser",
15809 "sensible-browser",
15810 "firefox",
15811 "opera",
15812 "xdg-open",
15813 "lynx",
15814 "links"
15815 );
15816 foreach my $Br (@Browsers)
15817 {
15818 if($Br = get_CmdPath($Br))
15819 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015820 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015821 last;
15822 }
15823 }
15824 }
15825 }
15826 if($Cmd)
15827 {
15828 if($Debug) {
15829 printMsg("INFO", "running $Cmd");
15830 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015831 if($OSgroup ne "windows"
15832 and $OSgroup ne "macos")
15833 {
15834 if($Cmd!~/lynx|links/) {
15835 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15836 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015837 }
15838 system($Cmd);
15839 }
15840 else {
15841 printMsg("ERROR", "cannot open report in browser");
15842 }
15843}
15844
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015845sub getReport($)
15846{
15847 my $Level = $_[0];
15848 if($ReportFormat eq "xml")
15849 { # XML
15850
15851 if($Level eq "Join")
15852 {
15853 my $Report = "<reports>\n";
15854 $Report .= getReport("Binary");
15855 $Report .= getReport("Source");
15856 $Report .= "</reports>\n";
15857 return $Report;
15858 }
15859 else
15860 {
15861 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15862 my ($Summary, $MetaData) = get_Summary($Level);
15863 $Report .= $Summary."\n";
15864 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15865 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15866 $Report .= get_Report_SymbolsInfo($Level);
15867 $Report .= "</report>\n";
15868 return $Report;
15869 }
15870 }
15871 else
15872 { # HTML
15873 my $CssStyles = readModule("Styles", "Report.css");
15874 my $JScripts = readModule("Scripts", "Sections.js");
15875 if($Level eq "Join")
15876 {
15877 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15878 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015879 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15880 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015881 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15882 my ($BSummary, $BMetaData) = get_Summary("Binary");
15883 my ($SSummary, $SMetaData) = get_Summary("Source");
15884 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>";
15885 $Report .= get_Report_Header("Join")."
15886 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015887 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15888 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015889 </div>";
15890 $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>";
15891 $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 +040015892 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015893 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15894 return $Report;
15895 }
15896 else
15897 {
15898 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015899 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15900 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15901 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 +040015902 if($Level eq "Binary")
15903 {
15904 if(getArch(1) eq getArch(2)
15905 and getArch(1) ne "unknown") {
15906 $Description .= " on ".showArch(getArch(1));
15907 }
15908 }
15909 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15910 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15911 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15912 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15913 $Report .= get_SourceInfo();
15914 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015915 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015916 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15917 return $Report;
15918 }
15919 }
15920}
15921
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015922sub getLegend()
15923{
15924 return "<br/>
15925<table class='summary'>
15926<tr>
15927 <td class='new'>added</td>
15928 <td class='passed'>compatible</td>
15929</tr>
15930<tr>
15931 <td class='warning'>warning</td>
15932 <td class='failed'>incompatible</td>
15933</tr></table>\n";
15934}
15935
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015936sub createReport()
15937{
15938 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015939 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015940 writeReport("Join", getReport("Join"));
15941 }
15942 elsif($DoubleReport)
15943 { # default
15944 writeReport("Binary", getReport("Binary"));
15945 writeReport("Source", getReport("Source"));
15946 }
15947 elsif($BinaryOnly)
15948 { # --binary
15949 writeReport("Binary", getReport("Binary"));
15950 }
15951 elsif($SourceOnly)
15952 { # --source
15953 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015954 }
15955}
15956
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015957sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015958{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015959 my ($LibName, $Wide) = @_;
15960 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015961 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015962 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015963 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15964 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015965 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15966 return $Footer;
15967}
15968
15969sub get_Report_Problems($$)
15970{
15971 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015972 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015973 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15974 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015975 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015976 if($Priority eq "Low")
15977 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015978 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015979 if($ReportFormat eq "html") {
15980 if($CheckImpl and $Level eq "Binary") {
15981 $Report .= get_Report_Impl();
15982 }
15983 }
15984 }
15985 if($ReportFormat eq "html")
15986 {
15987 if($Report)
15988 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015989 if($JoinReport)
15990 {
15991 if($Priority eq "Safe") {
15992 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15993 }
15994 else {
15995 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15996 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015997 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015998 else
15999 {
16000 if($Priority eq "Safe") {
16001 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16002 }
16003 else {
16004 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016006 }
16007 }
16008 }
16009 return $Report;
16010}
16011
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016012sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016013{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016014 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16015 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16016 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16017 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016018 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16019 <meta name=\"keywords\" content=\"$Keywords\" />
16020 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016021 <title>
16022 $Title
16023 </title>
16024 <style type=\"text/css\">
16025 $Styles
16026 </style>
16027 <script type=\"text/javascript\" language=\"JavaScript\">
16028 <!--
16029 $Scripts
16030 -->
16031 </script>
16032 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016033}
16034
16035sub insertIDs($)
16036{
16037 my $Text = $_[0];
16038 while($Text=~/CONTENT_ID/)
16039 {
16040 if(int($Content_Counter)%2) {
16041 $ContentID -= 1;
16042 }
16043 $Text=~s/CONTENT_ID/c_$ContentID/;
16044 $ContentID += 1;
16045 $Content_Counter += 1;
16046 }
16047 return $Text;
16048}
16049
16050sub checkPreprocessedUnit($)
16051{
16052 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016053 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016054 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016055 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016056 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016057
16058 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016059 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016060 chomp($Line);
16061 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016062 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016063 $CurHeader = path_format($1, $OSgroup);
16064 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016065 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016066 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16067 and not $Registered_Headers{$Version}{$CurHeader})
16068 { # not a target
16069 next;
16070 }
16071 if(not is_target_header($CurHeaderName, 1)
16072 and not is_target_header($CurHeaderName, 2))
16073 { # user-defined header
16074 next;
16075 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016076 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016077 {
16078 my ($Name, $Value) = ($1, $2);
16079 if(not $Constants{$Version}{$Name}{"Access"})
16080 {
16081 $Constants{$Version}{$Name}{"Access"} = "public";
16082 $Constants{$Version}{$Name}{"Value"} = $Value;
16083 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16084 }
16085 }
16086 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16087 $Constants{$Version}{$1}{"Access"} = "private";
16088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016089 }
16090 }
16091 close(PREPROC);
16092 foreach my $Constant (keys(%{$Constants{$Version}}))
16093 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016094 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16095 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016096 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16097 { # skip private constants
16098 delete($Constants{$Version}{$Constant});
16099 }
16100 else {
16101 delete($Constants{$Version}{$Constant}{"Access"});
16102 }
16103 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016104 if($Debug)
16105 {
16106 mkpath($DEBUG_PATH{$Version});
16107 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016109}
16110
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016111sub uncoverConstant($$)
16112{
16113 my ($LibVersion, $Constant) = @_;
16114 return "" if(not $LibVersion or not $Constant);
16115 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16116 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16117 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16118 }
16119 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16120 if(defined $Value)
16121 {
16122 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16123 {
16124 push(@RecurConstant, $Constant);
16125 my $Uncovered = uncoverConstant($LibVersion, $Value);
16126 if($Uncovered ne "") {
16127 $Value = $Uncovered;
16128 }
16129 pop(@RecurConstant);
16130 }
16131 # FIXME: uncover $Value using all the enum constants
16132 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16133 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16134 }
16135 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16136}
16137
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016138my %IgnoreConstant = map {$_=>1} (
16139 "VERSION",
16140 "VERSIONCODE",
16141 "VERNUM",
16142 "VERS_INFO",
16143 "PATCHLEVEL",
16144 "INSTALLPREFIX",
16145 "VBUILD",
16146 "VPATCH",
16147 "VMINOR",
16148 "BUILD_STRING",
16149 "BUILD_TIME",
16150 "PACKAGE_STRING",
16151 "PRODUCTION",
16152 "CONFIGURE_COMMAND",
16153 "INSTALLDIR",
16154 "BINDIR",
16155 "CONFIG_FILE_PATH",
16156 "DATADIR",
16157 "EXTENSION_DIR",
16158 "INCLUDE_PATH",
16159 "LIBDIR",
16160 "LOCALSTATEDIR",
16161 "SBINDIR",
16162 "SYSCONFDIR",
16163 "RELEASE",
16164 "SOURCE_ID",
16165 "SUBMINOR",
16166 "MINOR",
16167 "MINNOR",
16168 "MINORVERSION",
16169 "MAJOR",
16170 "MAJORVERSION",
16171 "MICRO",
16172 "MICROVERSION",
16173 "BINARY_AGE",
16174 "INTERFACE_AGE",
16175 "CORE_ABI",
16176 "PATCH",
16177 "COPYRIGHT",
16178 "TIMESTAMP",
16179 "REVISION",
16180 "PACKAGE_TAG",
16181 "PACKAGEDATE",
16182 "NUMVERSION",
16183 "Release",
16184 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016185);
16186
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016187sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016188{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016189 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016190 foreach my $Constant (keys(%{$Constants{1}}))
16191 {
16192 if($SkipConstants{1}{$Constant})
16193 { # skipped by the user
16194 next;
16195 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016196 if(not defined $Constants{2}{$Constant}{"Value"}
16197 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016198 { # empty value
16199 next;
16200 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016201 my $Header = $Constants{1}{$Constant}{"Header"};
16202 if(not is_target_header($Header, 1)
16203 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016204 { # user-defined header
16205 next;
16206 }
16207 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016208 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16209 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016210 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16211 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16212 $New_Value_Pure=~s/(\W)\s+/$1/g;
16213 $New_Value_Pure=~s/\s+(\W)/$1/g;
16214 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16215 if($New_Value_Pure ne $Old_Value_Pure)
16216 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016217 if($Level eq "Binary")
16218 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016219 foreach (keys(%IgnoreConstant))
16220 {
16221 if($Constant=~/(\A|_)$_(_|\Z)/)
16222 { # ignore library version
16223 next;
16224 }
16225 if(/\A[A-Z].*[a-z]\Z/)
16226 {
16227 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16228 { # ignore library version
16229 next;
16230 }
16231 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016232 }
16233 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16234 { # ignore library version
16235 next;
16236 }
16237 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16238 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016239 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016240 next;
16241 }
16242 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16243 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016244 # static int gcry_pth_init ( void) { return ...
16245 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16246 next;
16247 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016248 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016249 { # ignore source defines:
16250 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016251 next;
16252 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016253 }
16254 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16255 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16256 next;
16257 }
16258 if($Old_Value eq "0" and $New_Value eq "NULL")
16259 { # 0 => NULL
16260 next;
16261 }
16262 if($Old_Value eq "NULL" and $New_Value eq "0")
16263 { # NULL => 0
16264 next;
16265 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016266 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016267 "Target"=>$Constant,
16268 "Old_Value"=>$Old_Value,
16269 "New_Value"=>$New_Value );
16270 }
16271 }
16272}
16273
16274sub convert_integer($)
16275{
16276 my $Value = $_[0];
16277 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016278 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016279 return hex($Value);
16280 }
16281 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016282 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016283 return oct($Value);
16284 }
16285 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016286 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016287 return oct($Value);
16288 }
16289 else {
16290 return $Value;
16291 }
16292}
16293
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016294sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016295{
16296 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016297 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016298 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016299 {
16300 if($LibVersion==1)
16301 {
16302 printMsg("WARNING", "checking headers only");
16303 $CheckHeadersOnly = 1;
16304 }
16305 else {
16306 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16307 }
16308 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016309 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016310 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016311 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016312 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016313 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016314 if($#LibPaths!=-1)
16315 {
16316 if(not keys(%{$Symbol_Library{$LibVersion}}))
16317 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016318 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016319 printMsg("WARNING", "checking headers only");
16320 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016321 }
16322 }
16323 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016324
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016325 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016326 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016327}
16328
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016329sub getSymbolSize($$)
16330{ # size from the shared library
16331 my ($Symbol, $LibVersion) = @_;
16332 return 0 if(not $Symbol);
16333 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16334 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16335 {
16336 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16337 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16338 {
16339 if($Size<0) {
16340 return -$Size;
16341 }
16342 }
16343 }
16344 return 0;
16345}
16346
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016347sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016348{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16349 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016350 my ($Name, $Type) = @_;
16351
16352 # single
16353 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016354 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016355 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016356 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016357 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016358
16359 # double
16360 if($Name=~/$DEFAULT_STD_PARMS/)
16361 {
16362 if($Type eq "F")
16363 {
16364 my ($ShortName, $FuncParams) = split_Signature($Name);
16365
16366 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16367 {
16368 if(index($FParam, "<")!=-1)
16369 {
16370 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16371 my $FParam_N = canonifyName($FParam, "T");
16372 if($FParam_N ne $FParam) {
16373 $Name=~s/\Q$FParam\E/$FParam_N/g;
16374 }
16375 }
16376 }
16377 }
16378 elsif($Type eq "T")
16379 {
16380 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16381
16382 my @TParams = separate_Params($TmplParams, 0, 0);
16383 my $Pos = 0;
16384 while($Pos <= $#TParams-1)
16385 {
16386 my $TParam1 = canonifyName($TParams[$Pos], "T");
16387 my $TParam2 = canonifyName($TParams[$Pos+1], "T");
16388
16389 if($TParam2=~/\A$DEFAULT_STD_PARMS<\Q$TParam1\E >\Z/) {
16390 $Name=~s/\Q$TParam1, $TParam2\E/$TParam1/g;
16391 }
16392
16393 $Pos+=2;
16394 }
16395 }
16396 }
16397
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016398 return $Name;
16399}
16400
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016401sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016402{
16403 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016404 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016405 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016406 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016407 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016408 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016409 next if($tr_name{$Symbol});
16410 $Symbol=~s/[\@\$]+(.*)\Z//;
16411 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016412 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016413 elsif(index($Symbol, "?")==0) {
16414 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016415 }
16416 else
16417 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016418 $tr_name{$Symbol} = $Symbol;
16419 $mangled_name_gcc{$Symbol} = $Symbol;
16420 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016421 }
16422 }
16423 if($#MnglNames1 > -1)
16424 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016425 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016426 foreach my $MnglName (@MnglNames1)
16427 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016428 if(my $Unmangled = pop(@UnmangledNames))
16429 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016430 $tr_name{$MnglName} = formatName(canonifyName($Unmangled, "F"), "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016431 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16432 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16433 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016434 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016435 and $tr_name{$MnglName}=~/vtable for (.+)/)
16436 { # bind class name and v-table symbol
16437 my $ClassName = $1;
16438 $ClassVTable{$ClassName} = $MnglName;
16439 $VTableClass{$MnglName} = $ClassName;
16440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016441 }
16442 }
16443 }
16444 if($#MnglNames2 > -1)
16445 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016446 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016447 foreach my $MnglName (@MnglNames2)
16448 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016449 if(my $Unmangled = pop(@UnmangledNames))
16450 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016451 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016452 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16453 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016454 }
16455 }
16456 return \%tr_name;
16457}
16458
16459sub link_symbol($$$)
16460{
16461 my ($Symbol, $RunWith, $Deps) = @_;
16462 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16463 return 1;
16464 }
16465 if($Deps eq "+Deps")
16466 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016467 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016468 return 1;
16469 }
16470 }
16471 return 0;
16472}
16473
16474sub link_symbol_internal($$$)
16475{
16476 my ($Symbol, $RunWith, $Where) = @_;
16477 return 0 if(not $Where or not $Symbol);
16478 if($Where->{$RunWith}{$Symbol})
16479 { # the exact match by symbol name
16480 return 1;
16481 }
16482 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16483 { # indirect symbol version, i.e.
16484 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016485 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016486 if($Where->{$RunWith}{$VSym}) {
16487 return 1;
16488 }
16489 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016490 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016491 if($Sym and $Ver)
16492 { # search for the symbol with the same version
16493 # or without version
16494 if($Where->{$RunWith}{$Sym})
16495 { # old: foo@v|foo@@v
16496 # new: foo
16497 return 1;
16498 }
16499 if($Where->{$RunWith}{$Sym."\@".$Ver})
16500 { # old: foo|foo@@v
16501 # new: foo@v
16502 return 1;
16503 }
16504 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16505 { # old: foo|foo@v
16506 # new: foo@@v
16507 return 1;
16508 }
16509 }
16510 return 0;
16511}
16512
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016513sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016514{
16515 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016516 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016517 my @Imported = ();
16518 if($OSgroup eq "macos")
16519 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016520 my $NM = get_CmdPath("nm");
16521 if(not $NM) {
16522 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016523 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016524 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016525 while(<APP>)
16526 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016527 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016528 push(@Imported, $1);
16529 }
16530 }
16531 close(APP);
16532 }
16533 elsif($OSgroup eq "windows")
16534 {
16535 my $DumpBinCmd = get_CmdPath("dumpbin");
16536 if(not $DumpBinCmd) {
16537 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16538 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016539 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016540 while(<APP>)
16541 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016542 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16543 push(@Imported, $1);
16544 }
16545 }
16546 close(APP);
16547 }
16548 else
16549 {
16550 my $ReadelfCmd = get_CmdPath("readelf");
16551 if(not $ReadelfCmd) {
16552 exitStatus("Not_Found", "can't find \"readelf\"");
16553 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016554 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016555 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016556 while(<APP>)
16557 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016558 if(defined $symtab)
16559 { # do nothing with symtab
16560 if(index($_, "'.dynsym'")!=-1)
16561 { # dynamic table
16562 $symtab = undef;
16563 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016564 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016565 elsif(index($_, "'.symtab'")!=-1)
16566 { # symbol table
16567 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016568 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016569 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016570 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016571 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16572 if($Ndx eq "UND")
16573 { # only imported symbols
16574 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016575 }
16576 }
16577 }
16578 close(APP);
16579 }
16580 return @Imported;
16581}
16582
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016583my %ELF_BIND = map {$_=>1} (
16584 "WEAK",
16585 "GLOBAL"
16586);
16587
16588my %ELF_TYPE = map {$_=>1} (
16589 "FUNC",
16590 "IFUNC",
16591 "OBJECT",
16592 "COMMON"
16593);
16594
16595my %ELF_VIS = map {$_=>1} (
16596 "DEFAULT",
16597 "PROTECTED"
16598);
16599
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016600sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016601{ # read the line of 'readelf' output corresponding to the symbol
16602 my @Info = split(/\s+/, $_[0]);
16603 # Num: Value Size Type Bind Vis Ndx Name
16604 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16605 shift(@Info); # spaces
16606 shift(@Info); # num
16607 if($#Info!=6)
16608 { # other lines
16609 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016610 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016611 return () if(not defined $ELF_TYPE{$Info[2]});
16612 return () if(not defined $ELF_BIND{$Info[3]});
16613 return () if(not defined $ELF_VIS{$Info[4]});
16614 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16615 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16616 return ();
16617 }
16618 if($OStarget eq "symbian")
16619 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16620 if(index($Info[6], "_._.absent_export_")!=-1)
16621 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16622 return ();
16623 }
16624 $Info[6]=~s/\@.+//g; # remove version
16625 }
16626 if(index($Info[2], "0x") == 0)
16627 { # size == 0x3d158
16628 $Info[2] = hex($Info[2]);
16629 }
16630 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016631}
16632
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016633sub read_symlink($)
16634{
16635 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016636 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016637 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016638 }
16639 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016640 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016641 }
16642 elsif(my $FileCmd = get_CmdPath("file"))
16643 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016644 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016645 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016646 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016647 }
16648 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016649
16650 # can't read
16651 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016652}
16653
16654sub resolve_symlink($)
16655{
16656 my $Path = $_[0];
16657 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016658
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016659 if(defined $Cache{"resolve_symlink"}{$Path}) {
16660 return $Cache{"resolve_symlink"}{$Path};
16661 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016662 if(not -f $Path and not -l $Path)
16663 { # broken
16664 return ($Cache{"resolve_symlink"}{$Path} = "");
16665 }
16666 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16667}
16668
16669sub resolve_symlink_I($)
16670{
16671 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016672 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016673 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016674 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016675 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016676 {
16677 if(is_abs($Redirect))
16678 { # absolute path
16679 if($SystemRoot and $SystemRoot ne "/"
16680 and $Path=~/\A\Q$SystemRoot\E\//
16681 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16682 { # symbolic links from the sysroot
16683 # should be corrected to point to
16684 # the files inside sysroot
16685 $Redirect = $SystemRoot.$Redirect;
16686 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016687 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016688 }
16689 elsif($Redirect=~/\.\.[\/\\]/)
16690 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016691 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016692 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016693 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016694 }
16695 elsif(-f get_dirname($Path)."/".$Redirect)
16696 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016697 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016698 }
16699 else
16700 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016701 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016702 }
16703 }
16704 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016705 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016706}
16707
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016708sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016709{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016710 my ($LibVersion, $Name) = @_;
16711 return "" if(not $LibVersion or not $Name);
16712 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16713 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016714 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016715 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16716}
16717
16718sub get_LibPath_I($$)
16719{
16720 my ($LibVersion, $Name) = @_;
16721 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016722 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016723 if(-f $Name)
16724 { # absolute path
16725 return $Name;
16726 }
16727 else
16728 { # broken
16729 return "";
16730 }
16731 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016732 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016733 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016734 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016735 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016736 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016737 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016738 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016739 }
16740 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16741 { # ldconfig default paths
16742 return $DefaultPath;
16743 }
16744 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16745 { # search in default linker directories
16746 # and then in all system paths
16747 if(-f $Dir."/".$Name) {
16748 return joinPath($Dir,$Name);
16749 }
16750 }
16751 detectSystemObjects() if(not keys(%SystemObjects));
16752 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16753 return $AllObjects[0];
16754 }
16755 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16756 {
16757 if($ShortName ne $Name)
16758 { # FIXME: check this case
16759 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16760 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016761 }
16762 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016763 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016764 # can't find
16765 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016766}
16767
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016768sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016769{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016770 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16771 return () if(not $LibVersion or not $Lib_Path);
16772 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16773 if($IsNeededLib)
16774 {
16775 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16776 return ();
16777 }
16778 }
16779 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016780 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016781
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016782 if($CheckImpl)
16783 {
16784 if(not $IsNeededLib) {
16785 getImplementations($LibVersion, $Lib_Path);
16786 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016787 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016788
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016789 push(@RecurLib, $Lib_Name);
16790 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016791 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16792 if($IsNeededLib)
16793 { # change short name to use later for needed libraries
16794 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16795 }
16796 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016797 { # libstdc++ and libc are always used by other libs
16798 # if you test one of these libs then you not need
16799 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016800 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016801 { # libstdc++.so.6
16802 $STDCXX_TESTING = 1;
16803 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016804 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016805 { # libc-2.11.3.so
16806 $GLIBC_TESTING = 1;
16807 }
16808 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016809 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016810 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016811 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016812 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016813 mkpath(get_dirname($DebugPath));
16814 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016815 if($OStarget eq "macos")
16816 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016817 my $NM = get_CmdPath("nm");
16818 if(not $NM)
16819 {
16820 print STDERR "ERROR: can't find \"nm\"\n";
16821 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016822 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016823 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016824 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016825 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016826 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016827 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016828 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016829 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016830 else
16831 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016832 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016833 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016834 while(<LIB>)
16835 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016836 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016837 {
16838 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016839 if($IsNeededLib)
16840 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016841 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016842 {
16843 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16844 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016846 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016847 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016848 {
16849 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16850 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016851 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16852 {
16853 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16854 setLanguage($LibVersion, "C++");
16855 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016856 }
16857 if($CheckObjectsOnly
16858 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016859 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016860 }
16861 }
16862 }
16863 }
16864 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016865
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016866 if($Deps)
16867 {
16868 if($LIB_TYPE eq "dynamic")
16869 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016870
16871 my $OtoolCmd = get_CmdPath("otool");
16872 if(not $OtoolCmd)
16873 {
16874 print STDERR "ERROR: can't find \"otool\"\n";
16875 exit(1);
16876 }
16877
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016878 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16879 while(<LIB>)
16880 {
16881 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16882 and $1 ne $Lib_Path) {
16883 $NeededLib{$1} = 1;
16884 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016885 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016886 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016887 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016888 }
16889 }
16890 elsif($OStarget eq "windows")
16891 { # Windows *.dll, *.lib
16892 my $DumpBinCmd = get_CmdPath("dumpbin");
16893 if(not $DumpBinCmd) {
16894 exitStatus("Not_Found", "can't find \"dumpbin\"");
16895 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016896 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016897 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016898 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016899 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016900 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016901 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016902 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016903 else
16904 { # write to pipe
16905 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016906 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016907 while(<LIB>)
16908 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16909 # 1198 4AD SetThreadToken (forwarded to ...)
16910 # 3368 _o2i_ECPublicKey
16911 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16912 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16913 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16914 { # dynamic, static and forwarded symbols
16915 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016916 if($IsNeededLib)
16917 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016918 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016919 {
16920 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16921 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16922 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016923 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016924 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016925 {
16926 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16927 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016928 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16929 {
16930 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16931 setLanguage($LibVersion, "C++");
16932 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016933 }
16934 if($CheckObjectsOnly
16935 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016936 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016937 }
16938 }
16939 }
16940 }
16941 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016942 if($Deps)
16943 {
16944 if($LIB_TYPE eq "dynamic")
16945 { # dependencies
16946 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16947 while(<LIB>)
16948 {
16949 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16950 and $1 ne $Lib_Path) {
16951 $NeededLib{path_format($1, $OSgroup)} = 1;
16952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016953 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016954 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016956 }
16957 }
16958 else
16959 { # Unix; *.so, *.a
16960 # Symbian: *.dso, *.lib
16961 my $ReadelfCmd = get_CmdPath("readelf");
16962 if(not $ReadelfCmd) {
16963 exitStatus("Not_Found", "can't find \"readelf\"");
16964 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016965 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16966 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016967 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016968 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016969 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016970 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016971 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016972 else
16973 { # write to pipe
16974 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016975 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016976 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016977 while(<LIB>)
16978 {
16979 if($LIB_TYPE eq "dynamic")
16980 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016981 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016982 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016983 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016984 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016985 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016986 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016987 # do nothing with symtab
16988 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016989 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016990 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016991 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016992 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016993 next;
16994 }
16995 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016996 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016997 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016998 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016999 { # ignore interfaces that are imported from somewhere else
17000 next;
17001 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017002 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017003 and $Weak eq "-Weak")
17004 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017005 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017006 next;
17007 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017008 my $Short = $Symbol;
17009 $Short=~s/\@.+//g;
17010 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017011 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017012 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17013 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017014 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017015 if($IsNeededLib)
17016 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017017 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017018 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017019 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17020 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017022 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017023 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017024 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017025 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17026 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17027 if($Vers)
17028 {
17029 if($LIB_EXT eq "so")
17030 { # value
17031 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17032 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17033 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017034 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017035 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17036 {
17037 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17038 setLanguage($LibVersion, "C++");
17039 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017040 }
17041 if($CheckObjectsOnly
17042 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017043 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017044 }
17045 }
17046 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017047 elsif($LIB_TYPE eq "dynamic")
17048 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017049 if($Deps)
17050 {
17051 if(/NEEDED.+\[([^\[\]]+)\]/)
17052 { # dependencies:
17053 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17054 $NeededLib{$1} = 1;
17055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017056 }
17057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017058 }
17059 close(LIB);
17060 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017061 if($Vers)
17062 {
17063 if(not $IsNeededLib and $LIB_EXT eq "so")
17064 { # get symbol versions
17065 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017066 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017067 next if(index($Symbol,"\@")==-1);
17068 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017069 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017070 my $Interface_SymName = "";
17071 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017072 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017073 if($Symbol_SameValue ne $Symbol
17074 and index($Symbol_SameValue,"\@")==-1)
17075 {
17076 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17077 $Interface_SymName = $Symbol_SameValue;
17078 last;
17079 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017080 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017081 if(not $Interface_SymName)
17082 {
17083 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17084 and not $SymVer{$LibVersion}{$1}) {
17085 $SymVer{$LibVersion}{$1} = $Symbol;
17086 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017087 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017088 }
17089 }
17090 }
17091 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017092 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017093 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017094 foreach my $DyLib (sort keys(%NeededLib))
17095 {
17096 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17097 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17098 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017099 }
17100 }
17101 pop(@RecurLib);
17102 return $Library_Symbol{$LibVersion};
17103}
17104
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017105sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017106{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017107 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017108 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017109 return keys(%Prefixes);
17110}
17111
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017112sub get_prefixes_I($$)
17113{
17114 foreach my $P (@{$_[0]})
17115 {
17116 my @Parts = reverse(split(/[\/\\]+/, $P));
17117 my $Name = $Parts[0];
17118 foreach (1 .. $#Parts)
17119 {
17120 $_[1]->{$Name}{$P} = 1;
17121 last if($_>4 or $Parts[$_] eq "include");
17122 $Name = $Parts[$_].$SLASH.$Name;
17123 }
17124 }
17125}
17126
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017127sub detectSystemHeaders()
17128{
17129 my @SysHeaders = ();
17130 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17131 {
17132 next if(not -d $DevelPath);
17133 # search for all header files in the /usr/include
17134 # with or without extension (ncurses.h, QtCore, ...)
17135 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17136 foreach my $Link (cmd_find($DevelPath,"l","",""))
17137 { # add symbolic links
17138 if(-f $Link) {
17139 push(@SysHeaders, $Link);
17140 }
17141 }
17142 }
17143 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017144 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017145 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017146 foreach (cmd_find($DevelPath,"f","",""))
17147 {
17148 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17149 {
17150 if(/\.h\Z|\/include\//) {
17151 push(@SysHeaders, $_);
17152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017153 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017154 }
17155 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017156 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017157}
17158
17159sub detectSystemObjects()
17160{
17161 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17162 {
17163 next if(not -d $DevelPath);
17164 foreach my $Path (find_libs($DevelPath,"",""))
17165 { # search for shared libraries in the /usr/lib (including symbolic links)
17166 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17167 }
17168 }
17169}
17170
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017171sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017172{
17173 my $LibVersion = $_[0];
17174 my @SoPaths = ();
17175 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17176 {
17177 if(not -e $Dest) {
17178 exitStatus("Access_Error", "can't access \'$Dest\'");
17179 }
17180 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17181 foreach (@SoPaths_Dest) {
17182 push(@SoPaths, $_);
17183 }
17184 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017185 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017186}
17187
17188sub skip_lib($$)
17189{
17190 my ($Path, $LibVersion) = @_;
17191 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017192 my $Name = get_filename($Path);
17193 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017194 return 1;
17195 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017196 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017197 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17198 return 1;
17199 }
17200 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17201 {
17202 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17203 return 1;
17204 }
17205 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017206 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017207 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017208 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017209 return 1;
17210 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017211 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017212 return 1;
17213 }
17214 }
17215 return 0;
17216}
17217
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017218sub skipHeader($$)
17219{
17220 my ($Path, $LibVersion) = @_;
17221 return 1 if(not $Path or not $LibVersion);
17222 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17223 return 0;
17224 }
17225 if(defined $Cache{"skipHeader"}{$Path}) {
17226 return $Cache{"skipHeader"}{$Path};
17227 }
17228 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17229}
17230
17231sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017232{ # returns:
17233 # 1 - if header should NOT be included and checked
17234 # 2 - if header should NOT be included, but should be checked
17235 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017236 my $Name = get_filename($Path);
17237 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017238 return $Kind;
17239 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017240 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017241 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017242 if(index($Path, $D)!=-1)
17243 {
17244 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17245 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17246 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017247 }
17248 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017249 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017250 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017251 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17252 {
17253 if($Name=~/$P/) {
17254 return $Kind;
17255 }
17256 if($P=~/[\/\\]/ and $Path=~/$P/) {
17257 return $Kind;
17258 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017259 }
17260 }
17261 return 0;
17262}
17263
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017264sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017265{
17266 my ($Dir, $LibVersion) = @_;
17267 if($SystemPaths{"lib"}{$Dir})
17268 { # system directory
17269 return;
17270 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017271 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017272 { # already registered
17273 return;
17274 }
17275 foreach my $Path (find_libs($Dir,"",1))
17276 {
17277 next if(ignore_path($Path));
17278 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017279 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017280 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017281 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17282}
17283
17284sub registerObject($$)
17285{
17286 my ($Path, $LibVersion) = @_;
17287 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017288 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017289 if(my $SONAME = getSONAME($Path)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017290 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017291 }
17292 if(my $SName = parse_libname($Name, "name", $OStarget)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017293 $RegisteredObjects_Short{$LibVersion}{$SName} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017294 }
17295}
17296
17297sub getSONAME($)
17298{
17299 my $Path = $_[0];
17300 return if(not $Path);
17301 if(defined $Cache{"getSONAME"}{$Path}) {
17302 return $Cache{"getSONAME"}{$Path};
17303 }
17304 my $ObjdumpCmd = get_CmdPath("objdump");
17305 if(not $ObjdumpCmd) {
17306 exitStatus("Not_Found", "can't find \"objdump\"");
17307 }
17308 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17309 if($OSgroup eq "windows") {
17310 $SonameCmd .= " | find \"SONAME\"";
17311 }
17312 else {
17313 $SonameCmd .= " | grep SONAME";
17314 }
17315 if(my $SonameInfo = `$SonameCmd`) {
17316 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17317 return ($Cache{"getSONAME"}{$Path} = $1);
17318 }
17319 }
17320 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017321}
17322
17323sub getSOPaths_Dest($$)
17324{
17325 my ($Dest, $LibVersion) = @_;
17326 if(skip_lib($Dest, $LibVersion)) {
17327 return ();
17328 }
17329 if(-f $Dest)
17330 {
17331 if(not parse_libname($Dest, "name", $OStarget)) {
17332 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17333 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017334 registerObject($Dest, $LibVersion);
17335 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017336 return ($Dest);
17337 }
17338 elsif(-d $Dest)
17339 {
17340 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017341 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017342 if($SystemPaths{"lib"}{$Dest})
17343 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17344 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17345 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17346 { # all files and symlinks that match the name of a library
17347 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17348 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017349 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017350 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017351 }
17352 }
17353 }
17354 else
17355 { # search for all files and symlinks
17356 foreach my $Path (find_libs($Dest,"",""))
17357 {
17358 next if(ignore_path($Path));
17359 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017360 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017361 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017362 }
17363 if($OSgroup eq "macos")
17364 { # shared libraries on MacOS X may have no extension
17365 foreach my $Path (cmd_find($Dest,"f","",""))
17366 {
17367 next if(ignore_path($Path));
17368 next if(skip_lib($Path, $LibVersion));
17369 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017370 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17371 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017372 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017373 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017374 }
17375 }
17376 }
17377 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017378 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017379 }
17380 else {
17381 return ();
17382 }
17383}
17384
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017385sub isCyclical($$)
17386{
17387 my ($Stack, $Value) = @_;
17388 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017389}
17390
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017391sub generateTemplate()
17392{
17393 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17394 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17395}
17396
17397sub detectWordSize()
17398{
17399 return "" if(not $GCC_PATH);
17400 if($Cache{"detectWordSize"}) {
17401 return $Cache{"detectWordSize"};
17402 }
17403 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017404 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017405 unlink("$TMP_DIR/empty.h");
17406 my $WSize = 0;
17407 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017408 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017409 $WSize = $1;
17410 }
17411 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017412 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017413 my $PTRDIFF = $1;
17414 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017415 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017416 }
17417 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017418 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017419 }
17420 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017421 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017422 exitStatus("Error", "can't check WORD size");
17423 }
17424 return ($Cache{"detectWordSize"} = $WSize);
17425}
17426
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017427sub getWordSize($) {
17428 return $WORD_SIZE{$_[0]};
17429}
17430
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017431sub majorVersion($)
17432{
17433 my $V = $_[0];
17434 return 0 if(not $V);
17435 my @VParts = split(/\./, $V);
17436 return $VParts[0];
17437}
17438
17439sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017440{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017441 my ($V1, $V2) = @_;
17442 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017443 my @V1Parts = split(/\./, $V1);
17444 my @V2Parts = split(/\./, $V2);
17445 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17446 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17447 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17448 }
17449 return -1 if($#V1Parts < $#V2Parts);
17450 return 1 if($#V1Parts > $#V2Parts);
17451 return 0;
17452}
17453
17454sub read_ABI_Dump($$)
17455{
17456 my ($LibVersion, $Path) = @_;
17457 return if(not $LibVersion or not -e $Path);
17458 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017459 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017460 { # input *.abi
17461 $FilePath = $Path;
17462 }
17463 else
17464 { # input *.abi.tar.gz
17465 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017466 if(not isDump_U($FilePath)) {
17467 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17468 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017469 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017470
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017471 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017472
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017473 my $Line = readLineNum($FilePath, 0);
17474 if($Line=~/xml/)
17475 { # XML format
17476 loadModule("XmlDump");
17477 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017478 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017479 else
17480 { # Perl Data::Dumper format (default)
17481 open(DUMP, $FilePath);
17482 local $/ = undef;
17483 my $Content = <DUMP>;
17484 close(DUMP);
17485
17486 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17487 { # remove temp file
17488 unlink($FilePath);
17489 }
17490 if($Content!~/};\s*\Z/) {
17491 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17492 }
17493 $ABI = eval($Content);
17494 if(not $ABI) {
17495 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017497 }
17498 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017499 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17500 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017501 if(not $DumpVersion)
17502 { # old dumps (<=1.21.6) have been marked by the tool version
17503 $DumpVersion = $ToolVersion;
17504 }
17505 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17506 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17507 { # should be compatible with dumps of the same major version
17508 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17509 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017510 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017511 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017512 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017513 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017514 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017515 }
17516 if($UseOldDumps)
17517 {
17518 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017519 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017520 }
17521 }
17522 else
17523 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017524 my $Msg = "incompatible version \'$DumpVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017525 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17526 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17527 }
17528 exitStatus("Dump_Version", $Msg);
17529 }
17530 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017531 if(not checkDump($LibVersion, "2.11"))
17532 { # old ABI dumps
17533 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017534 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017535 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017536 { # ABI dump created with --binary option
17537 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17538 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017539 else
17540 { # default
17541 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17542 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017543 if(defined $ABI->{"Mode"}
17544 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017545 { # --ext option
17546 $ExtendedCheck = 1;
17547 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017548 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017549 {
17550 $UsedDump{$LibVersion}{"L"} = $Lang;
17551 setLanguage($LibVersion, $Lang);
17552 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017553 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017554 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017555 }
17556 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017557 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017558 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017559 if(not $TInfo)
17560 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017561 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017562 }
17563 my %Tid_TDid = ();
17564 foreach my $TDid (keys(%{$TInfo}))
17565 {
17566 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17567 {
17568 $MAX_ID = $Tid if($Tid>$MAX_ID);
17569 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17570 $Tid_TDid{$Tid}{$TDid}=1;
17571 }
17572 }
17573 my %NewID = ();
17574 foreach my $Tid (keys(%Tid_TDid))
17575 {
17576 my @TDids = keys(%{$Tid_TDid{$Tid}});
17577 if($#TDids>=1)
17578 {
17579 foreach my $TDid (@TDids)
17580 {
17581 if($TDid) {
17582 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17583 }
17584 else
17585 {
17586 if(my $ID = ++$MAX_ID)
17587 {
17588 $NewID{$TDid}{$Tid} = $ID;
17589 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17590 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17591 }
17592 }
17593 }
17594 }
17595 else
17596 {
17597 my $TDid = $TDids[0];
17598 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17599 }
17600 }
17601 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17602 {
17603 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17604 if(defined $Info{"BaseType"})
17605 {
17606 my $Bid = $Info{"BaseType"}{"Tid"};
17607 my $BDid = $Info{"BaseType"}{"TDid"};
17608 $BDid="" if(not defined $BDid);
17609 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17610 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17611 }
17612 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17613 }
17614 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17615 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017616 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017617 read_Machine_DumpInfo($ABI, $LibVersion);
17618 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017619 if(not $SymbolInfo{$LibVersion})
17620 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017621 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017622 }
17623 if(not keys(%{$SymbolInfo{$LibVersion}}))
17624 { # validation of old-version dumps
17625 if(not $ExtendedCheck) {
17626 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17627 }
17628 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017629 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017630 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017631 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017632 else
17633 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017634 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017635 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017636 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017637 }
17638 if(not $DepSymbols)
17639 { # Cannot reconstruct DepSymbols. This may result in false
17640 # positives if the old dump is for library 2. Not a problem if
17641 # old dumps are only from old libraries.
17642 $DepSymbols = {};
17643 }
17644 foreach my $Symbol (keys(%{$DepSymbols})) {
17645 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17646 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017647 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017648 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17649 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17650 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017651 if(not $SkipTypes{$LibVersion})
17652 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017653 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017654 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017655 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017656 if(not $SkipSymbols{$LibVersion})
17657 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017658 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017659 }
17660 if(not $SkipSymbols{$LibVersion})
17661 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017662 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017663 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017664 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17665 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17666 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017667 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017668 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017669 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017670 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017671 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017672 read_Headers_DumpInfo($ABI, $LibVersion);
17673 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017674 if(not checkDump($LibVersion, "2.10.1")
17675 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017676 { # support for old ABI dumps: added target headers
17677 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17678 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017679 }
17680 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017681 $Constants{$LibVersion} = $ABI->{"Constants"};
17682 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017683 if(not $NestedNameSpaces{$LibVersion})
17684 { # support for old dumps
17685 # Cannot reconstruct NameSpaces. This may affect design
17686 # of the compatibility report.
17687 $NestedNameSpaces{$LibVersion} = {};
17688 }
17689 # target system type
17690 # needed to adopt HTML report
17691 if(not $DumpSystem)
17692 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017693 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017694 }
17695 # recreate environment
17696 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17697 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017698 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017699 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017700 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17701 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017702 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017703 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017704 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017705 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17706 {
17707 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17708 setLanguage($LibVersion, "C++");
17709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017710 }
17711 }
17712 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017713 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17714 {
17715 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17716 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17717 }
17718 }
17719
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017720 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017721 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017722 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017723 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017724 {
17725 if(not $Symbol_Library{$LibVersion}{$MnglName}
17726 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17727 push(@VFunc, $MnglName);
17728 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017729 }
17730 }
17731 translateSymbols(@VFunc, $LibVersion);
17732 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017733 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17734
17735 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017736 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017737 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17738 { # support for old ABI dumps < 2.0 (ACC 1.22)
17739 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17740 {
17741 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17742 {
17743 if($Access ne "public") {
17744 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17745 }
17746 }
17747 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17748 }
17749 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17750 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017751 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17752 { # support for old ABI dumps
17753 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17754 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017755 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17756 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17757 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017758 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17759 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017760 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017761 foreach (keys(%{$TInfo{"Base"}})) {
17762 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017764 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017765 if($TInfo{"Type"} eq "MethodPtr")
17766 {
17767 if(defined $TInfo{"Param"})
17768 { # support for old ABI dumps <= 1.17
17769 if(not defined $TInfo{"Param"}{"0"})
17770 {
17771 my $Max = keys(%{$TInfo{"Param"}});
17772 foreach my $Pos (1 .. $Max) {
17773 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17774 }
17775 delete($TInfo{"Param"}{$Max});
17776 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17777 }
17778 }
17779 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017780 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17781 {
17782 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017783 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017784 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17785 if(not $BName)
17786 { # broken type
17787 next;
17788 }
17789 if($TInfo{"Name"} eq $BName)
17790 { # typedef to "class Class"
17791 # should not be registered in TName_Tid
17792 next;
17793 }
17794 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17795 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017796 }
17797 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017798 }
17799 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17800 { # classes: class (id1), typedef (artificial, id2 > id1)
17801 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17802 }
17803 }
17804
17805 if(not checkDump($LibVersion, "2.15"))
17806 { # support for old ABI dumps
17807 my %Dups = ();
17808 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17809 {
17810 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017811 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017812 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17813 { # remove template decls
17814 delete($SymbolInfo{$LibVersion}{$InfoId});
17815 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017816 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017817 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017818 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17819 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017820 { # templates
17821 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017822 }
17823 }
17824 }
17825
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017826 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17827 {
17828 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17829 { # ABI dumps have no mangled names for C-functions
17830 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17831 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017832 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17833 { # support for old ABI dumps
17834 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17835 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017836 }
17837
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017838 $Descriptor{$LibVersion}{"Dump"} = 1;
17839}
17840
17841sub read_Machine_DumpInfo($$)
17842{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017843 my ($ABI, $LibVersion) = @_;
17844 if($ABI->{"Arch"}) {
17845 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017846 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017847 if($ABI->{"WordSize"}) {
17848 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017849 }
17850 else
17851 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017852 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017853 }
17854 if(not $WORD_SIZE{$LibVersion})
17855 { # support for old dumps (<1.23)
17856 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17857 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017858 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017859 }
17860 else
17861 {
17862 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017863 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017864 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017865 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17866 { # any "pointer"-type
17867 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017868 last;
17869 }
17870 }
17871 if($PSize)
17872 { # a pointer type size
17873 $WORD_SIZE{$LibVersion} = $PSize;
17874 }
17875 else {
17876 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17877 }
17878 }
17879 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017880 if($ABI->{"GccVersion"}) {
17881 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017882 }
17883}
17884
17885sub read_Libs_DumpInfo($$)
17886{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017887 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017888 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17889 if(not $Library_Symbol{$LibVersion})
17890 { # support for old dumps
17891 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17892 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017893 if(keys(%{$Library_Symbol{$LibVersion}})
17894 and not $DumpAPI) {
17895 $Descriptor{$LibVersion}{"Libs"} = "OK";
17896 }
17897}
17898
17899sub read_Headers_DumpInfo($$)
17900{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017901 my ($ABI, $LibVersion) = @_;
17902 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017903 and not $DumpAPI) {
17904 $Descriptor{$LibVersion}{"Headers"} = "OK";
17905 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017906 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017907 { # headers info is stored in the old dumps in the different way
17908 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017909 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017910 { # support for old dumps: headers info corrected in 1.22
17911 $Identity = $Name;
17912 }
17913 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017914 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017915 }
17916}
17917
17918sub find_libs($$$)
17919{
17920 my ($Path, $Type, $MaxDepth) = @_;
17921 # FIXME: correct the search pattern
17922 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17923}
17924
17925sub createDescriptor($$)
17926{
17927 my ($LibVersion, $Path) = @_;
17928 if(not $LibVersion or not $Path
17929 or not -e $Path) {
17930 return "";
17931 }
17932 if(-d $Path)
17933 { # directory with headers files and shared objects
17934 return "
17935 <version>
17936 ".$TargetVersion{$LibVersion}."
17937 </version>
17938
17939 <headers>
17940 $Path
17941 </headers>
17942
17943 <libs>
17944 $Path
17945 </libs>";
17946 }
17947 else
17948 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017949 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017950 { # standard XML-descriptor
17951 return readFile($Path);
17952 }
17953 elsif(is_header($Path, 2, $LibVersion))
17954 { # header file
17955 return "
17956 <version>
17957 ".$TargetVersion{$LibVersion}."
17958 </version>
17959
17960 <headers>
17961 $Path
17962 </headers>
17963
17964 <libs>
17965 none
17966 </libs>";
17967 }
17968 elsif(parse_libname($Path, "name", $OStarget))
17969 { # shared object
17970 return "
17971 <version>
17972 ".$TargetVersion{$LibVersion}."
17973 </version>
17974
17975 <headers>
17976 none
17977 </headers>
17978
17979 <libs>
17980 $Path
17981 </libs>";
17982 }
17983 else
17984 { # standard XML-descriptor
17985 return readFile($Path);
17986 }
17987 }
17988}
17989
17990sub detect_lib_default_paths()
17991{
17992 my %LPaths = ();
17993 if($OSgroup eq "bsd")
17994 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017995 if(my $LdConfig = get_CmdPath("ldconfig"))
17996 {
17997 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
17998 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017999 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18000 $LPaths{"lib".$1} = $2;
18001 }
18002 }
18003 }
18004 else {
18005 printMsg("WARNING", "can't find ldconfig");
18006 }
18007 }
18008 else
18009 {
18010 if(my $LdConfig = get_CmdPath("ldconfig"))
18011 {
18012 if($SystemRoot and $OSgroup eq "linux")
18013 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18014 if(-e $SystemRoot."/etc/ld.so.conf") {
18015 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18016 }
18017 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018018 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18019 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018020 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18021 {
18022 my ($Name, $Path) = ($1, $2);
18023 $Path=~s/[\/]{2,}/\//;
18024 $LPaths{$Name} = $Path;
18025 }
18026 }
18027 }
18028 elsif($OSgroup=~/linux/i) {
18029 printMsg("WARNING", "can't find ldconfig");
18030 }
18031 }
18032 return \%LPaths;
18033}
18034
18035sub detect_bin_default_paths()
18036{
18037 my $EnvPaths = $ENV{"PATH"};
18038 if($OSgroup eq "beos") {
18039 $EnvPaths.=":".$ENV{"BETOOLS"};
18040 }
18041 my $Sep = ($OSgroup eq "windows")?";":":|;";
18042 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18043 {
18044 $Path = path_format($Path, $OSgroup);
18045 $Path=~s/[\/\\]+\Z//g;
18046 next if(not $Path);
18047 if($SystemRoot
18048 and $Path=~/\A\Q$SystemRoot\E\//)
18049 { # do NOT use binaries from target system
18050 next;
18051 }
18052 $DefaultBinPaths{$Path} = 1;
18053 }
18054}
18055
18056sub detect_inc_default_paths()
18057{
18058 return () if(not $GCC_PATH);
18059 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18060 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018061 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018062 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018063 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18064 {
18065 my $Path = simplify_path($1);
18066 $Path=~s/[\/\\]+\Z//g;
18067 $Path = path_format($Path, $OSgroup);
18068 if($Path=~/c\+\+|\/g\+\+\//)
18069 {
18070 $DPaths{"Cpp"}{$Path}=1;
18071 if(not defined $MAIN_CPP_DIR
18072 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18073 $MAIN_CPP_DIR = $Path;
18074 }
18075 }
18076 elsif($Path=~/gcc/) {
18077 $DPaths{"Gcc"}{$Path}=1;
18078 }
18079 else
18080 {
18081 next if($Path=~/local[\/\\]+include/);
18082 if($SystemRoot
18083 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18084 { # The GCC include path for user headers is not a part of the system root
18085 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18086 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18087 next;
18088 }
18089 $DPaths{"Inc"}{$Path}=1;
18090 }
18091 }
18092 }
18093 unlink("$TMP_DIR/empty.h");
18094 return %DPaths;
18095}
18096
18097sub detect_default_paths($)
18098{
18099 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18100 my $Search = $_[0];
18101 if($Search!~/inc/) {
18102 $HSearch = 0;
18103 }
18104 if($Search!~/lib/) {
18105 $LSearch = 0;
18106 }
18107 if($Search!~/bin/) {
18108 $BSearch = 0;
18109 }
18110 if($Search!~/gcc/) {
18111 $GSearch = 0;
18112 }
18113 if(keys(%{$SystemPaths{"include"}}))
18114 { # <search_headers> section of the XML descriptor
18115 # do NOT search for systems headers
18116 $HSearch = 0;
18117 }
18118 if(keys(%{$SystemPaths{"lib"}}))
18119 { # <search_headers> section of the XML descriptor
18120 # do NOT search for systems headers
18121 $LSearch = 0;
18122 }
18123 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18124 { # additional search paths
18125 next if($Type eq "include" and not $HSearch);
18126 next if($Type eq "lib" and not $LSearch);
18127 next if($Type eq "bin" and not $BSearch);
18128 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18129 {
18130 next if(not -d $Path);
18131 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18132 }
18133 }
18134 if($OSgroup ne "windows")
18135 { # unix-like
18136 foreach my $Type ("include", "lib", "bin")
18137 { # automatic detection of system "devel" directories
18138 next if($Type eq "include" and not $HSearch);
18139 next if($Type eq "lib" and not $LSearch);
18140 next if($Type eq "bin" and not $BSearch);
18141 my ($UsrDir, $RootDir) = ("/usr", "/");
18142 if($SystemRoot and $Type ne "bin")
18143 { # 1. search for target headers and libraries
18144 # 2. use host commands: ldconfig, readelf, etc.
18145 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18146 }
18147 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18148 $SystemPaths{$Type}{$Path} = 1;
18149 }
18150 if(-d $RootDir."/".$Type)
18151 { # if "/lib" is symbolic link
18152 if($RootDir eq "/") {
18153 $SystemPaths{$Type}{"/".$Type} = 1;
18154 }
18155 else {
18156 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18157 }
18158 }
18159 if(-d $UsrDir) {
18160 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18161 $SystemPaths{$Type}{$Path} = 1;
18162 }
18163 if(-d $UsrDir."/".$Type)
18164 { # if "/usr/lib" is symbolic link
18165 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18166 }
18167 }
18168 }
18169 }
18170 if($BSearch)
18171 {
18172 detect_bin_default_paths();
18173 foreach my $Path (keys(%DefaultBinPaths)) {
18174 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18175 }
18176 }
18177 # check environment variables
18178 if($OSgroup eq "beos")
18179 {
18180 foreach (keys(%{$SystemPaths{"bin"}}))
18181 {
18182 if($_ eq ".") {
18183 next;
18184 }
18185 foreach my $Path (cmd_find($_, "d", "bin", ""))
18186 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18187 $SystemPaths{"bin"}{$Path} = 1;
18188 }
18189 }
18190 if($HSearch)
18191 {
18192 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18193 {
18194 if(is_abs($Path)) {
18195 $DefaultIncPaths{$Path} = 1;
18196 }
18197 }
18198 }
18199 if($LSearch)
18200 {
18201 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18202 {
18203 if(is_abs($Path)) {
18204 $DefaultLibPaths{$Path} = 1;
18205 }
18206 }
18207 }
18208 }
18209 if($LSearch)
18210 { # using linker to get system paths
18211 if(my $LPaths = detect_lib_default_paths())
18212 { # unix-like
18213 foreach my $Name (keys(%{$LPaths}))
18214 {
18215 if($SystemRoot
18216 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18217 { # wrong ldconfig configuration
18218 # check your <sysroot>/etc/ld.so.conf
18219 next;
18220 }
18221 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18222 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18223 }
18224 }
18225 foreach my $Path (keys(%DefaultLibPaths)) {
18226 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18227 }
18228 }
18229 if($BSearch)
18230 {
18231 if($CrossGcc)
18232 { # --cross-gcc=arm-linux-gcc
18233 if(-e $CrossGcc)
18234 { # absolute or relative path
18235 $GCC_PATH = get_abs_path($CrossGcc);
18236 }
18237 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18238 { # command name
18239 $GCC_PATH = $CrossGcc;
18240 }
18241 else {
18242 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18243 }
18244 if($GCC_PATH=~/\s/) {
18245 $GCC_PATH = "\"".$GCC_PATH."\"";
18246 }
18247 }
18248 }
18249 if($GSearch)
18250 { # GCC path and default include dirs
18251 if(not $CrossGcc) {
18252 $GCC_PATH = get_CmdPath("gcc");
18253 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018254 if(not $GCC_PATH)
18255 { # try to find gcc-X.Y
18256 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18257 keys(%{$SystemPaths{"bin"}}))
18258 {
18259 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18260 { # select the latest version
18261 @GCCs = sort {$b cmp $a} @GCCs;
18262 if(check_gcc($GCCs[0], "3"))
18263 {
18264 $GCC_PATH = $GCCs[0];
18265 last;
18266 }
18267 }
18268 }
18269 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018270 if(not $GCC_PATH) {
18271 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18272 }
18273 if(not $CheckObjectsOnly_Opt)
18274 {
18275 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18276 {
18277 my $GccTarget = get_dumpmachine($GCC_PATH);
18278 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18279 if($GccTarget=~/symbian/)
18280 {
18281 $OStarget = "symbian";
18282 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18283 }
18284 }
18285 else {
18286 exitStatus("Error", "something is going wrong with the GCC compiler");
18287 }
18288 }
18289 if(not $NoStdInc)
18290 { # do NOT search in GCC standard paths
18291 my %DPaths = detect_inc_default_paths();
18292 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18293 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18294 %DefaultIncPaths = %{$DPaths{"Inc"}};
18295 foreach my $Path (keys(%DefaultIncPaths)) {
18296 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18297 }
18298 }
18299 }
18300 if($HSearch)
18301 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018302 my $IncPath = "/usr/include";
18303 if($SystemRoot) {
18304 $IncPath = $SystemRoot.$IncPath;
18305 }
18306 if(-d $IncPath) {
18307 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018308 }
18309 }
18310}
18311
18312sub getLIB_EXT($)
18313{
18314 my $Target = $_[0];
18315 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18316 return $Ext;
18317 }
18318 return $OS_LibExt{$LIB_TYPE}{"default"};
18319}
18320
18321sub getAR_EXT($)
18322{
18323 my $Target = $_[0];
18324 if(my $Ext = $OS_Archive{$Target}) {
18325 return $Ext;
18326 }
18327 return $OS_Archive{"default"};
18328}
18329
18330sub get_dumpversion($)
18331{
18332 my $Cmd = $_[0];
18333 return "" if(not $Cmd);
18334 if($Cache{"get_dumpversion"}{$Cmd}) {
18335 return $Cache{"get_dumpversion"}{$Cmd};
18336 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018337 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018338 chomp($V);
18339 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18340}
18341
18342sub get_dumpmachine($)
18343{
18344 my $Cmd = $_[0];
18345 return "" if(not $Cmd);
18346 if($Cache{"get_dumpmachine"}{$Cmd}) {
18347 return $Cache{"get_dumpmachine"}{$Cmd};
18348 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018349 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018350 chomp($Machine);
18351 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18352}
18353
18354sub check_command($)
18355{
18356 my $Cmd = $_[0];
18357 return "" if(not $Cmd);
18358 my @Options = (
18359 "--version",
18360 "-help"
18361 );
18362 foreach my $Opt (@Options)
18363 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018364 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018365 if($Info) {
18366 return 1;
18367 }
18368 }
18369 return 0;
18370}
18371
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018372sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018373{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018374 my ($Cmd, $ReqVer) = @_;
18375 return 0 if(not $Cmd or not $ReqVer);
18376 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18377 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018378 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018379 if(my $GccVer = get_dumpversion($Cmd))
18380 {
18381 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18382 if(cmpVersions($GccVer, $ReqVer)>=0) {
18383 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18384 }
18385 }
18386 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018387}
18388
18389sub get_depth($)
18390{
18391 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018392 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018393 }
18394 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18395}
18396
18397sub find_gcc_cxx_headers($)
18398{
18399 my $LibVersion = $_[0];
18400 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18401 # detecting system header paths
18402 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18403 {
18404 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18405 {
18406 my $FileName = get_filename($HeaderPath);
18407 next if($DefaultGccHeader{$FileName});
18408 $DefaultGccHeader{$FileName} = $HeaderPath;
18409 }
18410 }
18411 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18412 {
18413 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18414 {
18415 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18416 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18417 {
18418 my $FileName = get_filename($Path);
18419 next if($DefaultCppHeader{$FileName});
18420 $DefaultCppHeader{$FileName} = $Path;
18421 }
18422 }
18423 }
18424 $Cache{"find_gcc_cxx_headers"} = 1;
18425}
18426
18427sub parse_libname($$$)
18428{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018429 return "" if(not $_[0]);
18430 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18431 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018432 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018433 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18434}
18435
18436sub parse_libname_I($$$)
18437{
18438 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018439 if($Target eq "symbian") {
18440 return parse_libname_symbian($Name, $Type);
18441 }
18442 elsif($Target eq "windows") {
18443 return parse_libname_windows($Name, $Type);
18444 }
18445 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018446 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018447 { # libSDL-1.2.so.0.7.1
18448 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018449 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018450 if($Type eq "name")
18451 { # libSDL-1.2
18452 # libwbxml2
18453 return $2;
18454 }
18455 elsif($Type eq "name+ext")
18456 { # libSDL-1.2.so
18457 # libwbxml2.so
18458 return $1;
18459 }
18460 elsif($Type eq "version")
18461 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018462 if(defined $7
18463 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018464 { # 0.7.1
18465 return $7;
18466 }
18467 else
18468 { # libc-2.5.so (=>2.5 version)
18469 my $MV = $5;
18470 $MV=~s/\A[\-\_]+//g;
18471 return $MV;
18472 }
18473 }
18474 elsif($Type eq "short")
18475 { # libSDL
18476 # libwbxml2
18477 return $3;
18478 }
18479 elsif($Type eq "shortest")
18480 { # SDL
18481 # wbxml
18482 return shortest_name($3);
18483 }
18484 }
18485 return "";# error
18486}
18487
18488sub parse_libname_symbian($$)
18489{
18490 my ($Name, $Type) = @_;
18491 my $Ext = getLIB_EXT("symbian");
18492 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18493 { # libpthread{00010001}.dso
18494 if($Type eq "name")
18495 { # libpthread{00010001}
18496 return $2;
18497 }
18498 elsif($Type eq "name+ext")
18499 { # libpthread{00010001}.dso
18500 return $1;
18501 }
18502 elsif($Type eq "version")
18503 { # 00010001
18504 my $V = $4;
18505 $V=~s/\{(.+)\}/$1/;
18506 return $V;
18507 }
18508 elsif($Type eq "short")
18509 { # libpthread
18510 return $3;
18511 }
18512 elsif($Type eq "shortest")
18513 { # pthread
18514 return shortest_name($3);
18515 }
18516 }
18517 return "";# error
18518}
18519
18520sub parse_libname_windows($$)
18521{
18522 my ($Name, $Type) = @_;
18523 my $Ext = getLIB_EXT("windows");
18524 if($Name=~/((.+?)\.$Ext)\Z/)
18525 { # netapi32.dll
18526 if($Type eq "name")
18527 { # netapi32
18528 return $2;
18529 }
18530 elsif($Type eq "name+ext")
18531 { # netapi32.dll
18532 return $1;
18533 }
18534 elsif($Type eq "version")
18535 { # DLL version embedded
18536 # at binary-level
18537 return "";
18538 }
18539 elsif($Type eq "short")
18540 { # netapi32
18541 return $2;
18542 }
18543 elsif($Type eq "shortest")
18544 { # netapi
18545 return shortest_name($2);
18546 }
18547 }
18548 return "";# error
18549}
18550
18551sub shortest_name($)
18552{
18553 my $Name = $_[0];
18554 # remove prefix
18555 $Name=~s/\A(lib|open)//;
18556 # remove suffix
18557 $Name=~s/[\W\d_]+\Z//i;
18558 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18559 return $Name;
18560}
18561
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018562sub createSymbolsList($$$$$)
18563{
18564 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18565 read_ABI_Dump(1, $DPath);
18566 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018567 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018568 }
18569 my %SymbolHeaderLib = ();
18570 my $Total = 0;
18571 # Get List
18572 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18573 {
18574 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018575 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018576 next;
18577 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018578 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018579 { # skip other symbols
18580 next;
18581 }
18582 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18583 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018584 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018585 next;
18586 }
18587 my $DyLib = $Symbol_Library{1}{$Symbol};
18588 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018589 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018590 next;
18591 }
18592 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18593 $Total+=1;
18594 }
18595 # Draw List
18596 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18597 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18598 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18599 {
18600 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18601 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018602 my %NS_Symbol = ();
18603 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18604 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18605 }
18606 foreach my $NameSpace (sort keys(%NS_Symbol))
18607 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018608 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018609 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18610 foreach my $Symbol (@SortedInterfaces)
18611 {
18612 my $SubReport = "";
18613 my $Signature = get_Signature($Symbol, 1);
18614 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018615 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018616 }
18617 if($Symbol=~/\A(_Z|\?)/)
18618 {
18619 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018620 $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 +040018621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018622 else {
18623 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18624 }
18625 }
18626 else
18627 {
18628 if($Signature) {
18629 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18630 }
18631 else {
18632 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18633 }
18634 }
18635 $SYMBOLS_LIST .= $SubReport;
18636 }
18637 }
18638 $SYMBOLS_LIST .= "<br/>\n";
18639 }
18640 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018641 # clear info
18642 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18643 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18644 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18645 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018646 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018647 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018648 my $CssStyles = readModule("Styles", "SymbolsList.css");
18649 my $JScripts = readModule("Scripts", "Sections.js");
18650 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018651 my $Title = "$LName: public symbols";
18652 my $Keywords = "$LName, API, symbols";
18653 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018654 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018655 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018656 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018657 <div style='height:999px;'></div></body></html>";
18658 writeFile($SaveTo, $SYMBOLS_LIST);
18659}
18660
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018661sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018662{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018663 my ($Module, $Name) = @_;
18664 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018665 if(not -f $Path) {
18666 exitStatus("Module_Error", "can't access \'$Path\'");
18667 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018668 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018669}
18670
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018671sub add_target_libs($)
18672{
18673 foreach (@{$_[0]}) {
18674 $TargetLibs{$_} = 1;
18675 }
18676}
18677
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018678sub is_target_lib($)
18679{
18680 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018681 if(not $LName) {
18682 return 0;
18683 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018684 if($TargetLibraryName
18685 and $LName!~/\Q$TargetLibraryName\E/) {
18686 return 0;
18687 }
18688 if(keys(%TargetLibs)
18689 and not $TargetLibs{$LName}
18690 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18691 return 0;
18692 }
18693 return 1;
18694}
18695
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018696sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018697{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018698 my ($H, $V) = @_;
18699 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018700 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018701 if($TargetHeaders{$V}{$H}) {
18702 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018703 }
18704 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018705 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018706}
18707
18708sub checkVersionNum($$)
18709{
18710 my ($LibVersion, $Path) = @_;
18711 if(my $VerNum = $TargetVersion{$LibVersion}) {
18712 return $VerNum;
18713 }
18714 my $UsedAltDescr = 0;
18715 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018716 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018717 next if(isDump($Part)); # ABI dump
18718 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018719 my $VerNum = "";
18720 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018721 {
18722 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018723 $VerNum = parse_libname($Part, "version", $OStarget);
18724 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018725 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018726 }
18727 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018728 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18729 {
18730 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018731 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018732 }
18733 if($VerNum ne "")
18734 {
18735 $TargetVersion{$LibVersion} = $VerNum;
18736 if($DumpAPI) {
18737 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18738 }
18739 else {
18740 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18741 }
18742 return $TargetVersion{$LibVersion};
18743 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018744 }
18745 if($UsedAltDescr)
18746 {
18747 if($DumpAPI) {
18748 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18749 }
18750 else {
18751 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18752 }
18753 }
18754}
18755
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018756sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018757{
18758 my $Str = $_[0];
18759 return "" if(not $Str);
18760 $Str=~s/\Q$TargetLibraryName\E//g;
18761 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018762 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018763 return $2;
18764 }
18765 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18766 return $V;
18767 }
18768 return "";
18769}
18770
18771sub readLibs($)
18772{
18773 my $LibVersion = $_[0];
18774 if($OStarget eq "windows")
18775 { # dumpbin.exe will crash
18776 # without VS Environment
18777 check_win32_env();
18778 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018779 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018780 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018781 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018782}
18783
18784sub dump_sorting($)
18785{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018786 my $Hash = $_[0];
18787 return [] if(not $Hash);
18788 my @Keys = keys(%{$Hash});
18789 return [] if($#Keys<0);
18790 if($Keys[0]=~/\A\d+\Z/)
18791 { # numbers
18792 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018793 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018794 else
18795 { # strings
18796 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018797 }
18798}
18799
18800sub printMsg($$)
18801{
18802 my ($Type, $Msg) = @_;
18803 if($Type!~/\AINFO/) {
18804 $Msg = $Type.": ".$Msg;
18805 }
18806 if($Type!~/_C\Z/) {
18807 $Msg .= "\n";
18808 }
18809 if($Quiet)
18810 { # --quiet option
18811 appendFile($COMMON_LOG_PATH, $Msg);
18812 }
18813 else
18814 {
18815 if($Type eq "ERROR") {
18816 print STDERR $Msg;
18817 }
18818 else {
18819 print $Msg;
18820 }
18821 }
18822}
18823
18824sub exitStatus($$)
18825{
18826 my ($Code, $Msg) = @_;
18827 printMsg("ERROR", $Msg);
18828 exit($ERROR_CODE{$Code});
18829}
18830
18831sub exitReport()
18832{ # the tool has run without any errors
18833 printReport();
18834 if($COMPILE_ERRORS)
18835 { # errors in headers may add false positives/negatives
18836 exit($ERROR_CODE{"Compile_Error"});
18837 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018838 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18839 { # --binary
18840 exit($ERROR_CODE{"Incompatible"});
18841 }
18842 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18843 { # --source
18844 exit($ERROR_CODE{"Incompatible"});
18845 }
18846 elsif($RESULT{"Source"}{"Problems"}
18847 or $RESULT{"Binary"}{"Problems"})
18848 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018849 exit($ERROR_CODE{"Incompatible"});
18850 }
18851 else {
18852 exit($ERROR_CODE{"Compatible"});
18853 }
18854}
18855
18856sub readRules($)
18857{
18858 my $Kind = $_[0];
18859 if(not -f $RULES_PATH{$Kind}) {
18860 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18861 }
18862 my $Content = readFile($RULES_PATH{$Kind});
18863 while(my $Rule = parseTag(\$Content, "rule"))
18864 {
18865 my $RId = parseTag(\$Rule, "id");
18866 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18867 foreach my $Prop (@Properties) {
18868 if(my $Value = parseTag(\$Rule, lc($Prop)))
18869 {
18870 $Value=~s/\n[ ]*//;
18871 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18872 }
18873 }
18874 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18875 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18876 }
18877 else {
18878 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18879 }
18880 }
18881}
18882
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018883sub getReportPath($)
18884{
18885 my $Level = $_[0];
18886 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18887 if($Level eq "Binary")
18888 {
18889 if($BinaryReportPath)
18890 { # --bin-report-path
18891 return $BinaryReportPath;
18892 }
18893 elsif($OutputReportPath)
18894 { # --report-path
18895 return $OutputReportPath;
18896 }
18897 else
18898 { # default
18899 return $Dir."/abi_compat_report.$ReportFormat";
18900 }
18901 }
18902 elsif($Level eq "Source")
18903 {
18904 if($SourceReportPath)
18905 { # --src-report-path
18906 return $SourceReportPath;
18907 }
18908 elsif($OutputReportPath)
18909 { # --report-path
18910 return $OutputReportPath;
18911 }
18912 else
18913 { # default
18914 return $Dir."/src_compat_report.$ReportFormat";
18915 }
18916 }
18917 else
18918 {
18919 if($OutputReportPath)
18920 { # --report-path
18921 return $OutputReportPath;
18922 }
18923 else
18924 { # default
18925 return $Dir."/compat_report.$ReportFormat";
18926 }
18927 }
18928}
18929
18930sub printStatMsg($)
18931{
18932 my $Level = $_[0];
18933 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18934}
18935
18936sub listAffected($)
18937{
18938 my $Level = $_[0];
18939 my $List = "";
18940 foreach (keys(%{$TotalAffected{$Level}}))
18941 {
18942 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18943 { # skip "Low"-severity problems
18944 next;
18945 }
18946 $List .= "$_\n";
18947 }
18948 my $Dir = get_dirname(getReportPath($Level));
18949 if($Level eq "Binary") {
18950 writeFile($Dir."/abi_affected.txt", $List);
18951 }
18952 elsif($Level eq "Source") {
18953 writeFile($Dir."/src_affected.txt", $List);
18954 }
18955}
18956
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018957sub printReport()
18958{
18959 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018960 createReport();
18961 if($JoinReport or $DoubleReport)
18962 {
18963 if($RESULT{"Binary"}{"Problems"}
18964 or $RESULT{"Source"}{"Problems"}) {
18965 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018966 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018967 else {
18968 printMsg("INFO", "result: COMPATIBLE");
18969 }
18970 printStatMsg("Binary");
18971 printStatMsg("Source");
18972 if($ListAffected)
18973 { # --list-affected
18974 listAffected("Binary");
18975 listAffected("Source");
18976 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018977 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018978 elsif($BinaryOnly)
18979 {
18980 if($RESULT{"Binary"}{"Problems"}) {
18981 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18982 }
18983 else {
18984 printMsg("INFO", "result: COMPATIBLE");
18985 }
18986 printStatMsg("Binary");
18987 if($ListAffected)
18988 { # --list-affected
18989 listAffected("Binary");
18990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018991 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018992 elsif($SourceOnly)
18993 {
18994 if($RESULT{"Source"}{"Problems"}) {
18995 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18996 }
18997 else {
18998 printMsg("INFO", "result: COMPATIBLE");
18999 }
19000 printStatMsg("Source");
19001 if($ListAffected)
19002 { # --list-affected
19003 listAffected("Source");
19004 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019005 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019006 if($StdOut)
19007 {
19008 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019009 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019010 printMsg("INFO", "compatibility report has been generated to stdout");
19011 }
19012 else
19013 { # default
19014 printMsg("INFO", "compatibility reports have been generated to stdout");
19015 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019016 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019017 else
19018 {
19019 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019020 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019021 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19022 }
19023 elsif($DoubleReport)
19024 { # default
19025 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19026 }
19027 elsif($BinaryOnly)
19028 { # --binary
19029 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19030 }
19031 elsif($SourceOnly)
19032 { # --source
19033 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019035 }
19036}
19037
19038sub check_win32_env()
19039{
19040 if(not $ENV{"DevEnvDir"}
19041 or not $ENV{"LIB"}) {
19042 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19043 }
19044}
19045
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019046sub diffSets($$)
19047{
19048 my ($S1, $S2) = @_;
19049 my @SK1 = keys(%{$S1});
19050 my @SK2 = keys(%{$S2});
19051 if($#SK1!=$#SK2) {
19052 return 1;
19053 }
19054 foreach my $K1 (@SK1)
19055 {
19056 if(not defined $S2->{$K1}) {
19057 return 1;
19058 }
19059 }
19060 return 0;
19061}
19062
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019063sub create_ABI_Dump()
19064{
19065 if(not -e $DumpAPI) {
19066 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19067 }
19068 # check the archive utilities
19069 if($OSgroup eq "windows")
19070 { # using zip
19071 my $ZipCmd = get_CmdPath("zip");
19072 if(not $ZipCmd) {
19073 exitStatus("Not_Found", "can't find \"zip\"");
19074 }
19075 }
19076 else
19077 { # using tar and gzip
19078 my $TarCmd = get_CmdPath("tar");
19079 if(not $TarCmd) {
19080 exitStatus("Not_Found", "can't find \"tar\"");
19081 }
19082 my $GzipCmd = get_CmdPath("gzip");
19083 if(not $GzipCmd) {
19084 exitStatus("Not_Found", "can't find \"gzip\"");
19085 }
19086 }
19087 my @DParts = split(/\s*,\s*/, $DumpAPI);
19088 foreach my $Part (@DParts)
19089 {
19090 if(not -e $Part) {
19091 exitStatus("Access_Error", "can't access \'$Part\'");
19092 }
19093 }
19094 checkVersionNum(1, $DumpAPI);
19095 foreach my $Part (@DParts)
19096 {
19097 if(isDump($Part)) {
19098 read_ABI_Dump(1, $Part);
19099 }
19100 else {
19101 readDescriptor(1, createDescriptor(1, $Part));
19102 }
19103 }
19104 initLogging(1);
19105 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019106 if(not $Descriptor{1}{"Dump"})
19107 {
19108 if(not $CheckHeadersOnly) {
19109 readLibs(1);
19110 }
19111 if($CheckHeadersOnly) {
19112 setLanguage(1, "C++");
19113 }
19114 if(not $CheckObjectsOnly) {
19115 searchForHeaders(1);
19116 }
19117 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019118 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019119 if(not $Descriptor{1}{"Dump"})
19120 {
19121 if($Descriptor{1}{"Headers"}) {
19122 readHeaders(1);
19123 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019124 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019125 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019126 if(not keys(%{$SymbolInfo{1}}))
19127 { # check if created dump is valid
19128 if(not $ExtendedCheck and not $CheckObjectsOnly)
19129 {
19130 if($CheckHeadersOnly) {
19131 exitStatus("Empty_Set", "the set of public symbols is empty");
19132 }
19133 else {
19134 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19135 }
19136 }
19137 }
19138 my %HeadersInfo = ();
19139 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19140 { # headers info stored without paths in the dump
19141 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19142 }
19143 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019144 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019145 "TypeInfo" => $TypeInfo{1},
19146 "SymbolInfo" => $SymbolInfo{1},
19147 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019148 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019149 "SymbolVersion" => $SymVer{1},
19150 "LibraryVersion" => $Descriptor{1}{"Version"},
19151 "LibraryName" => $TargetLibraryName,
19152 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019153 "SkipTypes" => $SkipTypes{1},
19154 "SkipSymbols" => $SkipSymbols{1},
19155 "SkipNameSpaces" => $SkipNameSpaces{1},
19156 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019157 "Headers" => \%HeadersInfo,
19158 "Constants" => $Constants{1},
19159 "NameSpaces" => $NestedNameSpaces{1},
19160 "Target" => $OStarget,
19161 "Arch" => getArch(1),
19162 "WordSize" => $WORD_SIZE{1},
19163 "GccVersion" => get_dumpversion($GCC_PATH),
19164 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19165 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19166 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019167 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019168 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019169 }
19170 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019171 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019172 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019173 if($ExtendedCheck)
19174 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019175 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019176 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019177 if($BinaryOnly)
19178 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019179 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019180 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019181
19182 my $ABI_DUMP = "";
19183 if($UseXML)
19184 {
19185 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019186 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019187 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019188 else
19189 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019190 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019191 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019192 if($StdOut)
19193 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019194 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019195 printMsg("INFO", "ABI dump has been generated to stdout");
19196 return;
19197 }
19198 else
19199 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019200 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19201 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019202 if($OutputDumpPath)
19203 { # user defined path
19204 $DumpPath = $OutputDumpPath;
19205 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019206 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019207 my ($DDir, $DName) = separate_path($DumpPath);
19208 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019209 if(not $Archive) {
19210 $DPath = $DumpPath;
19211 }
19212
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019213 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019214
19215 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019216 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019217 close(DUMP);
19218
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019219 if(not -s $DPath) {
19220 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19221 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019222 if($Archive) {
19223 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019224 }
19225
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019226 if(not $OutputDumpPath)
19227 {
19228 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19229 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19230 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019231 }
19232}
19233
19234sub quickEmptyReports()
19235{ # Quick "empty" reports
19236 # 4 times faster than merging equal dumps
19237 # NOTE: the dump contains the "LibraryVersion" attribute
19238 # if you change the version, then your dump will be different
19239 # OVERCOME: use -v1 and v2 options for comparing dumps
19240 # and don't change version in the XML descriptor (and dumps)
19241 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19242 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19243 {
19244 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19245 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19246 if($FilePath1 and $FilePath2)
19247 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019248 my $Line = readLineNum($FilePath1, 0);
19249 if($Line=~/xml/)
19250 { # XML format
19251 # is not supported yet
19252 return;
19253 }
19254
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019255 local $/ = undef;
19256
19257 open(DUMP1, $FilePath1);
19258 my $Content1 = <DUMP1>;
19259 close(DUMP1);
19260
19261 open(DUMP2, $FilePath2);
19262 my $Content2 = <DUMP2>;
19263 close(DUMP2);
19264
19265 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019266 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019267 # clean memory
19268 undef $Content2;
19269
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019270 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019271 my $ABIdump = eval($Content1);
19272
19273 # clean memory
19274 undef $Content1;
19275
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019276 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019277 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 +040019278 }
19279 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019280 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019281 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19282 }
19283 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019284 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019285 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19286 }
19287 read_Headers_DumpInfo($ABIdump, 1);
19288 read_Libs_DumpInfo($ABIdump, 1);
19289 read_Machine_DumpInfo($ABIdump, 1);
19290 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019291
19292 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19293 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19294
19295 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19296 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19297
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019298 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19299 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19300 exitReport();
19301 }
19302 }
19303 }
19304}
19305
19306sub initLogging($)
19307{
19308 my $LibVersion = $_[0];
19309 # create log directory
19310 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19311 if($OutputLogPath{$LibVersion})
19312 { # user-defined by -log-path option
19313 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19314 }
19315 if($LogMode ne "n") {
19316 mkpath($LOG_DIR);
19317 }
19318 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019319 if($Debug)
19320 { # debug directory
19321 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019322 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019323 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019324}
19325
19326sub writeLog($$)
19327{
19328 my ($LibVersion, $Msg) = @_;
19329 if($LogMode ne "n") {
19330 appendFile($LOG_PATH{$LibVersion}, $Msg);
19331 }
19332}
19333
19334sub resetLogging($)
19335{
19336 my $LibVersion = $_[0];
19337 if($LogMode!~/a|n/)
19338 { # remove old log
19339 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019340 if($Debug) {
19341 rmtree($DEBUG_PATH{$LibVersion});
19342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019343 }
19344}
19345
19346sub printErrorLog($)
19347{
19348 my $LibVersion = $_[0];
19349 if($LogMode ne "n") {
19350 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19351 }
19352}
19353
19354sub isDump($)
19355{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019356 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19357 return $1;
19358 }
19359 return 0;
19360}
19361
19362sub isDump_U($)
19363{
19364 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019365 return $1;
19366 }
19367 return 0;
19368}
19369
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019370sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019371{
19372 # read input XML descriptors or ABI dumps
19373 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019374 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019375 }
19376 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19377 foreach my $Part (@DParts1)
19378 {
19379 if(not -e $Part) {
19380 exitStatus("Access_Error", "can't access \'$Part\'");
19381 }
19382 }
19383 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019384 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019385 }
19386 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19387 foreach my $Part (@DParts2)
19388 {
19389 if(not -e $Part) {
19390 exitStatus("Access_Error", "can't access \'$Part\'");
19391 }
19392 }
19393 detect_default_paths("bin"); # to extract dumps
19394 if($#DParts1==0 and $#DParts2==0
19395 and isDump($Descriptor{1}{"Path"})
19396 and isDump($Descriptor{2}{"Path"}))
19397 { # optimization: equal ABI dumps
19398 quickEmptyReports();
19399 }
19400 checkVersionNum(1, $Descriptor{1}{"Path"});
19401 checkVersionNum(2, $Descriptor{2}{"Path"});
19402 printMsg("INFO", "preparation, please wait ...");
19403 foreach my $Part (@DParts1)
19404 {
19405 if(isDump($Part)) {
19406 read_ABI_Dump(1, $Part);
19407 }
19408 else {
19409 readDescriptor(1, createDescriptor(1, $Part));
19410 }
19411 }
19412 foreach my $Part (@DParts2)
19413 {
19414 if(isDump($Part)) {
19415 read_ABI_Dump(2, $Part);
19416 }
19417 else {
19418 readDescriptor(2, createDescriptor(2, $Part));
19419 }
19420 }
19421 initLogging(1);
19422 initLogging(2);
19423 # check consistency
19424 if(not $Descriptor{1}{"Headers"}
19425 and not $Descriptor{1}{"Libs"}) {
19426 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19427 }
19428 if(not $Descriptor{2}{"Headers"}
19429 and not $Descriptor{2}{"Libs"}) {
19430 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19431 }
19432 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19433 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19434 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19435 }
19436 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19437 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19438 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19439 }
19440 if(not $Descriptor{1}{"Headers"}) {
19441 if($CheckHeadersOnly_Opt) {
19442 exitStatus("Error", "can't find header files info in descriptor d1");
19443 }
19444 }
19445 if(not $Descriptor{2}{"Headers"}) {
19446 if($CheckHeadersOnly_Opt) {
19447 exitStatus("Error", "can't find header files info in descriptor d2");
19448 }
19449 }
19450 if(not $Descriptor{1}{"Headers"}
19451 or not $Descriptor{2}{"Headers"}) {
19452 if(not $CheckObjectsOnly_Opt) {
19453 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19454 $CheckObjectsOnly = 1;
19455 }
19456 }
19457 if(not $Descriptor{1}{"Libs"}) {
19458 if($CheckObjectsOnly_Opt) {
19459 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19460 }
19461 }
19462 if(not $Descriptor{2}{"Libs"}) {
19463 if($CheckObjectsOnly_Opt) {
19464 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19465 }
19466 }
19467 if(not $Descriptor{1}{"Libs"}
19468 or not $Descriptor{2}{"Libs"})
19469 { # comparing standalone header files
19470 # comparing ABI dumps created with --headers-only
19471 if(not $CheckHeadersOnly_Opt)
19472 {
19473 printMsg("WARNING", "checking headers only");
19474 $CheckHeadersOnly = 1;
19475 }
19476 }
19477 if($UseDumps)
19478 { # --use-dumps
19479 # parallel processing
19480 my $pid = fork();
19481 if($pid)
19482 { # dump on two CPU cores
19483 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19484 if($RelativeDirectory{1}) {
19485 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19486 }
19487 if($OutputLogPath{1}) {
19488 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19489 }
19490 if($CrossGcc) {
19491 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19492 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019493 if($Quiet)
19494 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019495 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019496 @PARAMS = (@PARAMS, "-logging-mode", "a");
19497 }
19498 elsif($LogMode and $LogMode ne "w")
19499 { # "w" is default
19500 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019501 }
19502 if($ExtendedCheck) {
19503 @PARAMS = (@PARAMS, "-extended");
19504 }
19505 if($UserLang) {
19506 @PARAMS = (@PARAMS, "-lang", $UserLang);
19507 }
19508 if($TargetVersion{1}) {
19509 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19510 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019511 if($BinaryOnly) {
19512 @PARAMS = (@PARAMS, "-binary");
19513 }
19514 if($SourceOnly) {
19515 @PARAMS = (@PARAMS, "-source");
19516 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019517 if($SortDump) {
19518 @PARAMS = (@PARAMS, "-sort");
19519 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019520 if($DumpFormat and $DumpFormat ne "perl") {
19521 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19522 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019523 if($CheckHeadersOnly) {
19524 @PARAMS = (@PARAMS, "-headers-only");
19525 }
19526 if($CheckObjectsOnly) {
19527 @PARAMS = (@PARAMS, "-objects-only");
19528 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019529 if($Debug)
19530 {
19531 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019532 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019533 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019534 system("perl", $0, @PARAMS);
19535 if($?) {
19536 exit(1);
19537 }
19538 }
19539 else
19540 { # child
19541 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19542 if($RelativeDirectory{2}) {
19543 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19544 }
19545 if($OutputLogPath{2}) {
19546 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19547 }
19548 if($CrossGcc) {
19549 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19550 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019551 if($Quiet)
19552 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019553 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019554 @PARAMS = (@PARAMS, "-logging-mode", "a");
19555 }
19556 elsif($LogMode and $LogMode ne "w")
19557 { # "w" is default
19558 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019559 }
19560 if($ExtendedCheck) {
19561 @PARAMS = (@PARAMS, "-extended");
19562 }
19563 if($UserLang) {
19564 @PARAMS = (@PARAMS, "-lang", $UserLang);
19565 }
19566 if($TargetVersion{2}) {
19567 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19568 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019569 if($BinaryOnly) {
19570 @PARAMS = (@PARAMS, "-binary");
19571 }
19572 if($SourceOnly) {
19573 @PARAMS = (@PARAMS, "-source");
19574 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019575 if($SortDump) {
19576 @PARAMS = (@PARAMS, "-sort");
19577 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019578 if($DumpFormat and $DumpFormat ne "perl") {
19579 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19580 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019581 if($CheckHeadersOnly) {
19582 @PARAMS = (@PARAMS, "-headers-only");
19583 }
19584 if($CheckObjectsOnly) {
19585 @PARAMS = (@PARAMS, "-objects-only");
19586 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019587 if($Debug)
19588 {
19589 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019590 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019591 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019592 system("perl", $0, @PARAMS);
19593 if($?) {
19594 exit(1);
19595 }
19596 else {
19597 exit(0);
19598 }
19599 }
19600 waitpid($pid, 0);
19601 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19602 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19603 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19604 if($TargetLibraryFName ne $TargetLibraryName) {
19605 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19606 }
19607 if($ShowRetVal) {
19608 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19609 }
19610 if($CrossGcc) {
19611 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19612 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019613 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19614 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019615 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019616 }
19617 if($ReportFormat and $ReportFormat ne "html")
19618 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019619 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19620 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019621 if($OutputReportPath) {
19622 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19623 }
19624 if($BinaryReportPath) {
19625 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19626 }
19627 if($SourceReportPath) {
19628 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19629 }
19630 if($LoggingPath) {
19631 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19632 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019633 if($CheckHeadersOnly) {
19634 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19635 }
19636 if($CheckObjectsOnly) {
19637 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19638 }
19639 if($BinaryOnly) {
19640 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19641 }
19642 if($SourceOnly) {
19643 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19644 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019645 if($Browse) {
19646 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19647 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019648 if($OpenReport) {
19649 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19650 }
19651 if($Debug)
19652 {
19653 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19654 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019656 system("perl", $0, @CMP_PARAMS);
19657 exit($?>>8);
19658 }
19659 if(not $Descriptor{1}{"Dump"}
19660 or not $Descriptor{2}{"Dump"})
19661 { # need GCC toolchain to analyze
19662 # header files and libraries
19663 detect_default_paths("inc|lib|gcc");
19664 }
19665 if(not $Descriptor{1}{"Dump"})
19666 {
19667 if(not $CheckHeadersOnly) {
19668 readLibs(1);
19669 }
19670 if($CheckHeadersOnly) {
19671 setLanguage(1, "C++");
19672 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019673 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019674 searchForHeaders(1);
19675 }
19676 $WORD_SIZE{1} = detectWordSize();
19677 }
19678 if(not $Descriptor{2}{"Dump"})
19679 {
19680 if(not $CheckHeadersOnly) {
19681 readLibs(2);
19682 }
19683 if($CheckHeadersOnly) {
19684 setLanguage(2, "C++");
19685 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019686 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019687 searchForHeaders(2);
19688 }
19689 $WORD_SIZE{2} = detectWordSize();
19690 }
19691 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19692 { # support for old ABI dumps
19693 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019694 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019695 {
19696 $WORD_SIZE{1} = $WORD_SIZE{2};
19697 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19698 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019699 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019700 {
19701 $WORD_SIZE{2} = $WORD_SIZE{1};
19702 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19703 }
19704 }
19705 elsif(not $WORD_SIZE{1}
19706 and not $WORD_SIZE{2})
19707 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019708 $WORD_SIZE{1} = "4";
19709 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019710 }
19711 if($Descriptor{1}{"Dump"})
19712 { # support for old ABI dumps
19713 prepareTypes(1);
19714 }
19715 if($Descriptor{2}{"Dump"})
19716 { # support for old ABI dumps
19717 prepareTypes(2);
19718 }
19719 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19720 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19721 }
19722 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019723 if(not $CheckObjectsOnly)
19724 {
19725 if($Descriptor{1}{"Headers"}
19726 and not $Descriptor{1}{"Dump"}) {
19727 readHeaders(1);
19728 }
19729 if($Descriptor{2}{"Headers"}
19730 and not $Descriptor{2}{"Dump"}) {
19731 readHeaders(2);
19732 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019733 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019734
19735 # clean memory
19736 %SystemHeaders = ();
19737 %mangled_name_gcc = ();
19738
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019739 prepareSymbols(1);
19740 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019741
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019742 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019743 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019744
19745 # Virtual Tables
19746 registerVTable(1);
19747 registerVTable(2);
19748
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019749 if(not checkDump(1, "1.22")
19750 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019751 { # support for old ABI dumps
19752 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19753 {
19754 if($ClassName=~/</)
19755 { # templates
19756 if(not defined $VirtualTable{1}{$ClassName})
19757 { # synchronize
19758 delete($VirtualTable{2}{$ClassName});
19759 }
19760 }
19761 }
19762 }
19763
19764 registerOverriding(1);
19765 registerOverriding(2);
19766
19767 setVirtFuncPositions(1);
19768 setVirtFuncPositions(2);
19769
19770 # Other
19771 addParamNames(1);
19772 addParamNames(2);
19773
19774 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019775}
19776
19777sub compareAPIs($)
19778{
19779 my $Level = $_[0];
19780 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019781 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019782 if($Level eq "Binary") {
19783 printMsg("INFO", "comparing ABIs ...");
19784 }
19785 else {
19786 printMsg("INFO", "comparing APIs ...");
19787 }
19788 if($CheckHeadersOnly
19789 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019790 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019791 detectAdded_H($Level);
19792 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019793 }
19794 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019795 { # added/removed in libs
19796 detectAdded($Level);
19797 detectRemoved($Level);
19798 }
19799 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019800 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019801 mergeSignatures($Level);
19802 if(keys(%{$CheckedSymbols{$Level}})) {
19803 mergeConstants($Level);
19804 }
19805 }
19806 if($CheckHeadersOnly
19807 or $Level eq "Source")
19808 { # added/removed in headers
19809 mergeHeaders($Level);
19810 }
19811 else
19812 { # added/removed in libs
19813 mergeLibs($Level);
19814 if($CheckImpl
19815 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019816 mergeImpl();
19817 }
19818 }
19819}
19820
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019821sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019822{
19823 my %Opts = (
19824 "OStarget"=>$OStarget,
19825 "Debug"=>$Debug,
19826 "Quiet"=>$Quiet,
19827 "LogMode"=>$LogMode,
19828 "CheckHeadersOnly"=>$CheckHeadersOnly,
19829
19830 "SystemRoot"=>$SystemRoot,
19831 "MODULES_DIR"=>$MODULES_DIR,
19832 "GCC_PATH"=>$GCC_PATH,
19833 "TargetSysInfo"=>$TargetSysInfo,
19834 "CrossPrefix"=>$CrossPrefix,
19835 "TargetLibraryName"=>$TargetLibraryName,
19836 "CrossGcc"=>$CrossGcc,
19837 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019838 "NoStdInc"=>$NoStdInc,
19839
19840 "BinaryOnly" => $BinaryOnly,
19841 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019842 );
19843 return \%Opts;
19844}
19845
19846sub get_CoreError($)
19847{
19848 my %CODE_ERROR = reverse(%ERROR_CODE);
19849 return $CODE_ERROR{$_[0]};
19850}
19851
19852sub scenario()
19853{
19854 if($StdOut)
19855 { # enable quiet mode
19856 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019857 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019858 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019859 if(not $LogMode)
19860 { # default
19861 $LogMode = "w";
19862 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019863 if($UserLang)
19864 { # --lang=C++
19865 $UserLang = uc($UserLang);
19866 $COMMON_LANGUAGE{1}=$UserLang;
19867 $COMMON_LANGUAGE{2}=$UserLang;
19868 }
19869 if($LoggingPath)
19870 {
19871 $OutputLogPath{1} = $LoggingPath;
19872 $OutputLogPath{2} = $LoggingPath;
19873 if($Quiet) {
19874 $COMMON_LOG_PATH = $LoggingPath;
19875 }
19876 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019877 if($OutputDumpPath)
19878 { # validate
19879 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19880 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19881 }
19882 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019883 if($BinaryOnly and $SourceOnly)
19884 { # both --binary and --source
19885 # is the default mode
19886 $DoubleReport = 1;
19887 $JoinReport = 0;
19888 $BinaryOnly = 0;
19889 $SourceOnly = 0;
19890 if($OutputReportPath)
19891 { # --report-path
19892 $DoubleReport = 0;
19893 $JoinReport = 1;
19894 }
19895 }
19896 elsif($BinaryOnly or $SourceOnly)
19897 { # --binary or --source
19898 $DoubleReport = 0;
19899 $JoinReport = 0;
19900 }
19901 if($UseXML)
19902 { # --xml option
19903 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019904 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019905 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019906 if($ReportFormat)
19907 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019908 $ReportFormat = lc($ReportFormat);
19909 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019910 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019911 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019912 if($ReportFormat eq "htm")
19913 { # HTM == HTML
19914 $ReportFormat = "html";
19915 }
19916 elsif($ReportFormat eq "xml")
19917 { # --report-format=XML equal to --xml
19918 $UseXML = 1;
19919 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019920 }
19921 else
19922 { # default: HTML
19923 $ReportFormat = "html";
19924 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019925 if($DumpFormat)
19926 { # validate
19927 $DumpFormat = lc($DumpFormat);
19928 if($DumpFormat!~/\A(xml|perl)\Z/) {
19929 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19930 }
19931 if($DumpFormat eq "xml")
19932 { # --dump-format=XML equal to --xml
19933 $UseXML = 1;
19934 }
19935 }
19936 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019937 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019938 $DumpFormat = "perl";
19939 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019940 if($Quiet and $LogMode!~/a|n/)
19941 { # --quiet log
19942 if(-f $COMMON_LOG_PATH) {
19943 unlink($COMMON_LOG_PATH);
19944 }
19945 }
19946 if($TestTool and $UseDumps)
19947 { # --test && --use-dumps == --test-dump
19948 $TestDump = 1;
19949 }
19950 if($Help) {
19951 HELP_MESSAGE();
19952 exit(0);
19953 }
19954 if($InfoMsg) {
19955 INFO_MESSAGE();
19956 exit(0);
19957 }
19958 if($ShowVersion) {
19959 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.");
19960 exit(0);
19961 }
19962 if($DumpVersion) {
19963 printMsg("INFO", $TOOL_VERSION);
19964 exit(0);
19965 }
19966 if($ExtendedCheck) {
19967 $CheckHeadersOnly = 1;
19968 }
19969 if($SystemRoot_Opt)
19970 { # user defined root
19971 if(not -e $SystemRoot_Opt) {
19972 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19973 }
19974 $SystemRoot = $SystemRoot_Opt;
19975 $SystemRoot=~s/[\/]+\Z//g;
19976 if($SystemRoot) {
19977 $SystemRoot = get_abs_path($SystemRoot);
19978 }
19979 }
19980 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019981
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019982 if($SortDump)
19983 {
19984 $Data::Dumper::Useperl = 1;
19985 $Data::Dumper::Sortkeys = \&dump_sorting;
19986 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019987
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019988 if($TargetLibsPath)
19989 {
19990 if(not -f $TargetLibsPath) {
19991 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19992 }
19993 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19994 $TargetLibs{$Lib} = 1;
19995 }
19996 }
19997 if($TargetHeadersPath)
19998 { # --headers-list
19999 if(not -f $TargetHeadersPath) {
20000 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20001 }
20002 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20003 {
20004 $TargetHeaders{1}{$Header} = 1;
20005 $TargetHeaders{2}{$Header} = 1;
20006 }
20007 }
20008 if($TargetHeader)
20009 { # --header
20010 $TargetHeaders{1}{$TargetHeader} = 1;
20011 $TargetHeaders{2}{$TargetHeader} = 1;
20012 }
20013 if($TestTool
20014 or $TestDump)
20015 { # --test, --test-dump
20016 detect_default_paths("bin|gcc"); # to compile libs
20017 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020018 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20019 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020020 exit(0);
20021 }
20022 if($DumpSystem)
20023 { # --dump-system
20024 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020025 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020026 { # system XML descriptor
20027 if(not -f $DumpSystem) {
20028 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20029 }
20030 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020031 foreach (@{$Ret->{"Tools"}})
20032 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020033 $SystemPaths{"bin"}{$_} = 1;
20034 $TargetTools{$_}=1;
20035 }
20036 if($Ret->{"CrossPrefix"}) {
20037 $CrossPrefix = $Ret->{"CrossPrefix"};
20038 }
20039 }
20040 elsif($SystemRoot_Opt)
20041 { # -sysroot "/" option
20042 # default target: /usr/lib, /usr/include
20043 # search libs: /usr/lib and /lib
20044 if(not -e $SystemRoot."/usr/lib") {
20045 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20046 }
20047 if(not -e $SystemRoot."/lib") {
20048 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20049 }
20050 if(not -e $SystemRoot."/usr/include") {
20051 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20052 }
20053 readSystemDescriptor("
20054 <name>
20055 $DumpSystem
20056 </name>
20057 <headers>
20058 $SystemRoot/usr/include
20059 </headers>
20060 <libs>
20061 $SystemRoot/usr/lib
20062 </libs>
20063 <search_libs>
20064 $SystemRoot/lib
20065 </search_libs>");
20066 }
20067 else {
20068 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20069 }
20070 detect_default_paths("bin|gcc"); # to check symbols
20071 if($OStarget eq "windows")
20072 { # to run dumpbin.exe
20073 # and undname.exe
20074 check_win32_env();
20075 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020076 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020077 exit(0);
20078 }
20079 if($CmpSystems)
20080 { # --cmp-systems
20081 detect_default_paths("bin"); # to extract dumps
20082 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020083 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020084 exit(0);
20085 }
20086 if($GenerateTemplate) {
20087 generateTemplate();
20088 exit(0);
20089 }
20090 if(not $TargetLibraryName) {
20091 exitStatus("Error", "library name is not selected (option -l <name>)");
20092 }
20093 else
20094 { # validate library name
20095 if($TargetLibraryName=~/[\*\/\\]/) {
20096 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20097 }
20098 }
20099 if(not $TargetLibraryFName) {
20100 $TargetLibraryFName = $TargetLibraryName;
20101 }
20102 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20103 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20104 }
20105 if($SymbolsListPath)
20106 {
20107 if(not -f $SymbolsListPath) {
20108 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20109 }
20110 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20111 $SymbolsList{$Interface} = 1;
20112 }
20113 }
20114 if($SkipHeadersPath)
20115 {
20116 if(not -f $SkipHeadersPath) {
20117 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20118 }
20119 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020120 { # register for both versions
20121 $SkipHeadersList{1}{$Path} = 1;
20122 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020123 my ($CPath, $Type) = classifyPath($Path);
20124 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020125 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020126 }
20127 }
20128 if($ParamNamesPath)
20129 {
20130 if(not -f $ParamNamesPath) {
20131 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20132 }
20133 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20134 {
20135 if($Line=~s/\A(\w+)\;//)
20136 {
20137 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020138 if($Line=~/;(\d+);/)
20139 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020140 while($Line=~s/(\d+);(\w+)//) {
20141 $AddIntParams{$Interface}{$1}=$2;
20142 }
20143 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020144 else
20145 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020146 my $Num = 0;
20147 foreach my $Name (split(/;/, $Line)) {
20148 $AddIntParams{$Interface}{$Num++}=$Name;
20149 }
20150 }
20151 }
20152 }
20153 }
20154 if($AppPath)
20155 {
20156 if(not -f $AppPath) {
20157 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20158 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020159 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020160 $SymbolsList_App{$Interface} = 1;
20161 }
20162 }
20163 if($DumpAPI)
20164 { # --dump-abi
20165 # make an API dump
20166 create_ABI_Dump();
20167 exit($COMPILE_ERRORS);
20168 }
20169 # default: compare APIs
20170 # -d1 <path>
20171 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020172 compareInit();
20173 if($JoinReport or $DoubleReport)
20174 {
20175 compareAPIs("Binary");
20176 compareAPIs("Source");
20177 }
20178 elsif($BinaryOnly) {
20179 compareAPIs("Binary");
20180 }
20181 elsif($SourceOnly) {
20182 compareAPIs("Source");
20183 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020184 exitReport();
20185}
20186
20187scenario();